From 0aa8a8787720a9b5ea700c248e9ccd6ac78873a1 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:10:26 +0200 Subject: [PATCH 01/74] doc/ioc/pre-requisites: init tutorial --- doc/_quarto.yml | 1 + doc/ioc/tutorials/pre-requisites.md | 76 +++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 doc/ioc/tutorials/pre-requisites.md diff --git a/doc/_quarto.yml b/doc/_quarto.yml index b9bd75f0..6bc4d695 100644 --- a/doc/_quarto.yml +++ b/doc/_quarto.yml @@ -27,6 +27,7 @@ website: - section: User Tutorials file: ./ioc/tutorials.md contents: + - ./ioc/tutorials/pre-requisites.md - ./ioc/tutorials/getting-started.md - ./ioc/tutorials/porting.md - ./ioc/tutorials/day-to-day-dev.md diff --git a/doc/ioc/tutorials/pre-requisites.md b/doc/ioc/tutorials/pre-requisites.md new file mode 100644 index 00000000..6ea7a9dd --- /dev/null +++ b/doc/ioc/tutorials/pre-requisites.md @@ -0,0 +1,76 @@ +--- +title: "Pre-requisites" +--- + +The requirements for using EPNix are having curl, Nix, and Git installed, +either in a Linux system, +or in Windows' WSL2. +Nix must be configured with "flakes" enabled. + +You *don't* need to have EPICS base installed globally, +EPNix makes it available to you +when you enter your top's development shell. + +Having a global EPICS base installation shouldn't pose any issue. + +# Installing Nix + +::: callout-warning +If you use a Linux distribution with SELinux, +be sure to turn it off. +You can do this by adding the line `SELINUX=disabled` in `/etc/sysconfig/selinux` on distributions based on RedHat Enterprise Linux (RHEL) like CentOS, Rocky Linux, and so on. +::: + +If you don't have Nix installed, +first follow the [official instructions]. +Make sure to have the `xz` utility installed beforehand, +often part of the `xzip` or `xz` package. + +Unless you use WSL2, +use the multi-user installation, +because it builds packages in an isolated environment. + + [official instructions]: https://nixos.org/download.html#download-nix + +# Enabling Nix flakes and the `nix`{.bash} command + +Because Nix flakes and the unified `nix` command are experimental features at the time of writing, +you need to enable them in your `/etc/nix/nix.conf`. + +To enable this feature, +add this line to your `/etc/nix/nix.conf`: + +``` ini +experimental-features = nix-command flakes +``` + +If you have installed Nix in multi-user mode, +then you have to restart the Nix daemon by running: + +``` bash +systemctl restart nix-daemon.service +``` + +# Untracked files and Nix flakes + +One important thing with Nix flakes: +when your flake is in a Git repository, +Nix only considers files that Git tracks. + +For example, +if your `flake.nix` is in a Git repository, +and you create a file `foobar.txt`, +you must run `git add [-N] foobar.txt`{.bash} to make Nix recognize it. + +This prevents copying build products into the Nix store. + +# Git version + +If you use an old system and see Git errors when using Nix, +install a recent version of Git by running this: + +``` bash +nix-env -iA nixpkgs.git +``` + +This command installs a recent version of Git for your current user. From 0424ddee669da36a7e4b48e15ac30520e8bfc444 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:11:05 +0200 Subject: [PATCH 02/74] doc/ioc/streamdevice: init tutorial --- doc/_quarto.yml | 1 + doc/ioc/tutorials/streamdevice.md | 294 ++++++++++++++++++++++++++++++ 2 files changed, 295 insertions(+) create mode 100644 doc/ioc/tutorials/streamdevice.md diff --git a/doc/_quarto.yml b/doc/_quarto.yml index 6bc4d695..54cbbe23 100644 --- a/doc/_quarto.yml +++ b/doc/_quarto.yml @@ -29,6 +29,7 @@ website: contents: - ./ioc/tutorials/pre-requisites.md - ./ioc/tutorials/getting-started.md + - ./ioc/tutorials/streamdevice.md - ./ioc/tutorials/porting.md - ./ioc/tutorials/day-to-day-dev.md - ./ioc/tutorials/integration-tests.md diff --git a/doc/ioc/tutorials/streamdevice.md b/doc/ioc/tutorials/streamdevice.md new file mode 100644 index 00000000..29441736 --- /dev/null +++ b/doc/ioc/tutorials/streamdevice.md @@ -0,0 +1,294 @@ +--- +title: "Creating a StreamDevice IOC" +--- + +In this tutorial, +you're gonna learn how to create an EPICS IOC with EPNix +that communicates with a power supply, +using the [StreamDevice] support module. + + [StreamDevice]: https://paulscherrerinstitute.github.io/StreamDevice/ + +# Pre-requisites + +Verify that you have all pre-requisites installed. +If not, +follow the [Pre-requisites] section. + + [Pre-requisites]: ./pre-requisites.md + +# Running the power supply simulator + +EPNix has a power supply simulator +for you to test your IOC. + +To run it: + +``` bash +nix run 'github:epics-extensions/epnix#psu-simulator' +``` + +For the rest of the tutorial, +leave it running in a separate terminal. + +# Creating your top + +We can use these command to create an EPNix top: + +``` bash +# Initialise an EPNix top +nix flake new -t 'github:epics-extensions/epnix' my-top +cd my-top + +# Enter the EPNix development shell, that has EPICS base installed in it. +nix develop + +# Create your app and ioc boot folder +makeBaseApp.pl -t ioc example +makeBaseApp.pl -i -t ioc -p example -a linux-x86_64 Example + +# Create a git repository, and make sure all files are tracked +git init +git add . +``` + +After that, +you can already check that your top build with: + +``` bash +nix build -L +``` + +This `nix build`{.sh} command compiles your IOC, +and all its dependencies. +This makes the usual EPICS environment setup unneeded. + +If found in the official Nix cache server, +Nix downloads packages from there +instead of compiling them. + +This command puts a `./result` symbolic link in your current directory, +containing the compilation result. + +# Adding StreamDevice to the EPNix environment + +Adding dependencies to the EPNix environment happen inside the `flake.nix` file. +This file is the main entry point for specifying your build environment: +most Nix commands used here read this file to work. + +For adding StreamDevice, +change yours like so: + +``` {.diff filename="flake.nix"} + # Add one of the supported modules here: + # --- +- #support.modules = with pkgs.epnix.support; [ StreamDevice ]; ++ support.modules = with pkgs.epnix.support; [ StreamDevice ]; +``` + +Then, +leave your EPNix development shell by running `exit`{.sh}, +and re-enter it with `nix develop`{.sh}. + +Because you modified the support modules, +run `eregen-config`{.sh} to regenerate `configure/RELEASE.local`. + +With this, +your development shell has StreamDevice available, +and StreamDevice is also added in the `RELEASE.local` file. + +::: callout-tip +As a rule, +each time you edit the `flake.nix` file, +leave and re-enter your development shell (`exit`{.sh} then `nix develop`{.sh}), +and run `eregen-config`{.sh}. +::: + +# Adding StreamDevice to your EPICS app + +To add StreamDevice to your app, +make the following modifications: + +Change the `exampleApp/src/Makefile` +so that your App knows the record types of StreamDevice and its dependencies. +Also change that file so that it links to the StreamDevice library and its dependencies, +during compilation. +For example: + +``` {.makefile filename="exampleApp/src/Makefile"} +# ... + +# Include dbd files from all support applications: +example_DBD += calc.dbd +example_DBD += asyn.dbd +example_DBD += stream.dbd +example_DBD += drvAsynIPPort.dbd + +# Add all the support libraries needed by this IOC +example_LIBS += calc +example_LIBS += asyn +example_LIBS += stream + +# ... +``` + +Create the `exampleApp/Db/example.proto` file +that has the definition of the protocol. +This file tells StreamDevice what to send the power supply, +and what to expect in return. + +``` {.perl filename="exampleApp/Db/example.proto"} +Terminator = LF; + +getVoltage { + out ":VOLT?"; in "%f"; +} + +setVoltage { + out ":VOLT %f"; + @init { getVoltage; } +} +``` + +Create the `exampleApp/Db/example.db` file. +That file specifies the name, type, and properties of the Process Variables (PV) +that EPICS exposes over the network. +It also specifies how they relate to the functions written in the protocol file. + +``` {.perl filename="exampleApp/Db/example.db"} +record(ai, "${PREFIX}VOLT-RB") { + field(DTYP, "stream") + field(INP, "@example.proto getVoltage ${PORT}") +} + +record(ao, "${PREFIX}VOLT") { + field(DTYP, "stream") + field(OUT, "@example.proto setVoltage ${PORT}") +} +``` + +Change `exampleApp/Db/Makefile` +so that the EPICS build system installs `example.proto` and `example.db`: + +``` {.makefile filename="exampleApp/Db/Makefile"} +# ... + +#---------------------------------------------------- +# Create and install (or just install) into /db +# databases, templates, substitutions like this +DB += example.db +DB += example.proto + +# ... +``` + +Change your `st.cmd` file +so that it knows where to load the protocol file, +and how to connect to the remote power supply. + +``` {.csh filename="iocBoot/iocExample/st.cmd"} +#!../../bin/linux-x86_64/example + +< envPaths + +## Register all support components +dbLoadDatabase("${TOP}/dbd/example.dbd") +example_registerRecordDeviceDriver(pdbbase) + +# Where to find the protocol files +epicsEnvSet("STREAM_PROTOCOL_PATH", "${TOP}/db") +# The TCP/IP address of the power supply +drvAsynIPPortConfigure("PS1", "localhost:8727") + +## Load record instances +dbLoadRecords("${TOP}/db/example.db", "PREFIX=, PORT=PS1") + +iocInit() +``` + +And run `chmod +x iocBoot/iocExample/st.cmd` +so that you can run your command file as-is. + +You can test that your top builds by running: + +``` bash +nix build -L +``` + +You will see that your IOC does not build. +This is because we haven't told Git to track those newly added files, +and so Nix ignores them too. + +Run `git add .`{.sh} for Git and Nix to track all files, +and try a `nix build -L`{.sh} again. + +If everything goes right, +you can examine your compiled top under `./result`. + +You can observe that: + +- the `example` app is installed under `bin/` and `bin/linux-x86_64`, + and links to the correct libraries +- `example.proto` and `example.db` are installed under `db/` +- `example.dbd` is generated and installed under `dbd/` + +# Running your IOC + +To run your IOC, +build it first with `nix build -L`{.sh}, +and change directory into the `./result/iocBoot/iocExample` folder. +Then, run: + +``` bash +./st.cmd +``` + +You should see the IOC starting and connecting to `localhost:8727`. + +# Recompiling with make + +Using `nix build`{.sh} to compile your IOC each time might feel slow. +This is because Nix re-compiles your IOC from scratch each time. + +If you want a more "traditional" edit / compile / run workflow, +you can place yourself in the development shell with `nix develop`{.sh}, +and use `make` from here. + +# Next steps + +More commands are available in the power supply simulator. +To view them, +close your IOC, +and open a direct connection to the simulator: + +``` bash +nc localhost 8727 +# or +telnet localhost 8727 +``` + +You can install the `nc` command through the `netcat` package, +or you can install the `telnet` command through the `telnet` package, + +Either command opens a prompt +where you can type `help` then press enter +to view the available commands. + +Try to edit the protocol file and the database file +to add those features to your IOC. + +For more information about how to write the StreamDevice protocol, +have a look at the [Protocol Files] documentation. + +You might also be interested in reading [Setting up the flake registry] + + [Protocol Files]: https://paulscherrerinstitute.github.io/StreamDevice/protocol.html + [Setting up the flake registry]: ../guides/flake-registry.md + +# Pitfalls + +Although EPNix tries to be close to a standard EPICS development, +some differences might lead to confusion. +You can find more information about this in the [FAQ]. + + [FAQ]: ../faq.md From fd08b4eb5638d2267866efd662af017dfb310cb0 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:12:18 +0200 Subject: [PATCH 03/74] doc/ioc: remove getting started tutorial removed in favor of the StreamDevice tutorial --- doc/_quarto.yml | 1 - doc/ioc/tutorials/getting-started.md | 273 --------------------------- 2 files changed, 274 deletions(-) delete mode 100644 doc/ioc/tutorials/getting-started.md diff --git a/doc/_quarto.yml b/doc/_quarto.yml index 54cbbe23..ff754c8f 100644 --- a/doc/_quarto.yml +++ b/doc/_quarto.yml @@ -28,7 +28,6 @@ website: file: ./ioc/tutorials.md contents: - ./ioc/tutorials/pre-requisites.md - - ./ioc/tutorials/getting-started.md - ./ioc/tutorials/streamdevice.md - ./ioc/tutorials/porting.md - ./ioc/tutorials/day-to-day-dev.md diff --git a/doc/ioc/tutorials/getting-started.md b/doc/ioc/tutorials/getting-started.md deleted file mode 100644 index 138bf8e3..00000000 --- a/doc/ioc/tutorials/getting-started.md +++ /dev/null @@ -1,273 +0,0 @@ ---- -title: Getting started ---- - -# Requirements - -The requirements for using EPNix are having curl, Nix, and Git installed. - -If you need to install Nix, you also need the `xz` utility, often part of the `xzip` or `xz` package. - -You *don't* need to have EPICS base installed globally, EPNix makes it available to you when you enter your top's development shell. - -# Installing Nix - -::: callout-warning -If you use a Linux distribution with SELinux, be sure to turn it off. -You can do this by adding the line `SELINUX=disabled` in `/etc/sysconfig/selinux` on distributions based on RedHat Enterprise Linux (RHEL) like CentOS, Rocky Linux, and so on. -::: - -If you don't have Nix installed, first follow the [official instructions]. - -Unless you use WSL2, use the multi-user installation, because it builds packages in an isolated environment. - - [official instructions]: https://nixos.org/download.html#download-nix - -# Enabling Nix flakes and the `nix`{.bash} command - -Because Nix flakes and the unified `nix` command are experimental features at the time of writing, you need to enable them in your `/etc/nix/nix.conf`. - -To enable this feature, add this line to your `/etc/nix/nix.conf`: - -``` ini -experimental-features = nix-command flakes -``` - -If you have installed Nix in multi-user mode, then you have to restart the Nix daemon with `systemctl restart nix-daemon.service`{.bash}. - -# Untracked files and Nix flakes - -One important thing with Nix flakes: when your flake is in a Git repository, Nix only considers files that Git tracks. - -For example, if your `flake.nix`, is in a repository, and you create a file `foobar.txt`, you must run `git add [-N] foobar.txt`{.bash} to make Nix recognize it. - -This prevents copying build products into the Nix store. - -# Concepts - -In EPNix, your IOC have mainly one important file: the `flake.nix` file. - -The `flake.nix` file is the entry point that the `nix`{.bash} command reads in order for `nix build`{.bash}, `nix flake check`{.bash}, and `nix develop`{.bash} to work. -It's also the file where you specify your other "repository" dependencies. -For example, your IOC depends on EPNix itself, and also depends on each external EPICS "app." - -The `flake.nix` file also contains the configuration of your EPNix top. -EPNix provides a list of possible options and you can [extend them yourself]. -The [Available options] page of the documentation book documents the options provided by EPNix. - - [extend them yourself]: ./adding-options.md - [Available options]: ../references/options.md - -# Creating your project - -::: callout-note -Verify that you have set up your computer so that you can clone your repositories unattended, with for example SSH keys or tokens. -If you intend to use private Git repositories, see the [Private repository setup] guide. -::: - -With EPNix, we recommend developers to version EPICS tops separate from EPICS apps. -This means that by default, Git ignores apps created with `makeBaseApp.pl`, so that you can create separate Git repositories for them. - -If you use an old system and see Git errors while creating your template, you can install a recent version of Git by running `nix-env -iA nixpkgs.git` after installing Nix. - -To kick-start an EPNix project: - -``` bash -# Create a new directory by using the EPNix template. It will create the -# aforementioned `flake.nix` which will allow you to specify your base and your -# dependencies. It does not however create your top for you, instead, it will -# provide you with an environment with EPICS base installed (see below). -nix flake new -t 'github:epics-extensions/epnix' my-top -cd my-top - -# This will make you enter a new shell, with EPICS base installed in it. -# The EPICS base version will be the one used by your top. -nix develop - -# Initializes the EPICS part of your top, and creates a new app -makeBaseApp.pl -t ioc example -# Creates a new iocBoot folder -makeBaseApp.pl -i -t ioc -p example example - -# Versioning the top. -# This is highly recommended, since this will make Nix ignore your build -# products in its sandboxed builds -git init -git add . - -# Then, create a remote repository for the Top, and push to it -... - -# Versioning the app -cd exampleApp -git init -git add . - -# Then, create a remote repository for the App, and push to it -... -``` - -Now that your EPICS app is in a remote repository, you can instruct EPNix to use your created app from the remote repository: - -Edit your top's `flake.nix` - -- Below the other inputs, add: - -``` nix -inputs.exampleApp = { - url = "git+ssh://git@your.gitlab.com/your/exampleApp.git"; - flake = false; -}; -``` - -And, under the EPNix options section: - -- add `"inputs.exampleApp"`{.nix} in the `applications.apps` list (the quotes are necessary) - -Now, Nix tracks your app from the remote repository, and tracks its Git version in the `flake.lock` file. - -You can test that your top builds by executing: `nix build -L`{.bash}. This puts a `./result` symbolic link in your top's directory containing the result of the compilation. - -::: callout-tip -As a rule, each time you edit the `flake.nix` file, or update your inputs by running `nix flake update`{.bash} or `nix flake lock`{.bash}, you should leave and re-enter your development shell (`nix develop`{.bash}). -::: - - [Private repository setup]: ../guides/private-repo-setup.md - -# Developing your IOC - - - -## Using Nix - -As said earlier, running `nix build`{.bash} compiles your IOC. -This builds your top and all your dependencies, from a clean environment, by using your apps from remote Git repositories. -Nix places the output under `./result`. - - - - -When developing your IOC, it can become cumbersome that Nix tracks the remote repository of your app. -You sometimes want to do some temporary changes to your app, and test them before committing. - -For this exact purpose, EPNix includes a handy command called `enix-local`{.bash}. -This command behaves the same as `nix`, but instead uses your apps as-is from your local directory. - -For example, if you have started your EPNix project as in the [earlier section], you should have your top and a directory `exampleApp` under it. -Therefore, if you run `nix develop`{.bash}, then `enix-local build -L`{.bash} in the development shell, Nix will build your top, with the modifications from your local `exampleApp` directory. - -The advantage of using Nix when developing is that it builds from a "cleaner" environment. -It also stores the result in the Nix store, which you can copy by using the `nix copy`{.bash} command, and test it on another machine. - - [earlier section]: #creating-your-project - -## Using standard tools - -The EPNix development shell (`nix develop`{.bash}) includes your standard build tools. -This means that after creating your project, you can use `make`{.bash} as in any other standard EPICS development. - -The difference is that Git doesn't track `configure/RELEASE.local` and `configure/CONFIG_SITE.local` files, because they contain variables necessary to build with the EPNix environment. -They contain for example the `EPICS_BASE` variable. -To add them to your top, you can run `eregen-config`{.bash}. - -::: callout-tip -As a rule, each time you edit your modules in `flake.nix`, you should leave and re-enter your development shell, and re-run `eregen-config`{.bash}. -::: - -The advantage of using the standard tools, is that the compilation is incremental. -Nix always builds a package fully, meaning it always compiles your top from scratch. -Using `make`{.bash} directly only re-compiles the modified files, at the cost of potential impurities in your build. - -# Upgrading your app version - -After you have modified, tested, committed, and pushed your app changes, you should update your top so that your app version points to the latest version. - -To do this, you can run: - -``` bash -nix flake lock --update-input exampleApp --commit-lock-file -``` - -This command updates the `exampleApp` input, and creates a Git commit for this update. - -This command also works if you want to update the `epnix` input, or the `nixpkgs` input containing the various needed packages used by EPICS. - -# Looking up the documentation - -EPNix includes documentation: it has a documentation book (what you are reading), and man pages. - -To see the documentation book, run `edoc`{.bash} in the development shell from your top directory. - -To see the man page, run `man epnix-ioc`{.bash} in the development shell from your top directory. - -# Adding dependencies - -You now have all the tools you need to have a self-contained EPICS IOC, but it's quite useful to depend on modules from the community. -EPNix provides a way to do it. - -The first step is to examine the documentation, either the `epnix-ioc(5)` man page, under the "AVAILABLE PACKAGES" section, or in the documentation book, under the "Available packages" page. - -If the package exists, you can add this bit to your `flake.nix` file. - -``` nix -support.modules = with pkgs.epnix.support; [ your_dependency ]; -``` - -If the package doesn't exist, you can try [packaging it yourself], or you can request it in the [EPNix issue tracker]. - - [packaging it yourself]: ../developer-guides/packaging.md - [EPNix issue tracker]: https://github.com/epics-extensions/EPNix/issues - -# Deploying your IOC - -To deploy your IOC, build it by using Nix. -If you are doing a production deployment, verify that you have a clean build, by not using `enix-local`, and having a clean top Git repository. - -With this, you get a `./result` symbolic link to the result in the Nix store, which you can copy, with all its dependencies, using `nix copy`. -The only prerequisite is that the remote machine has Nix installed too. - -For example, if you want to copy a built IOC to the machine `example-ioc.prod.mycompany.com`: - -``` bash -nix copy ./result --to ssh://root@example-ioc.prod.mycompany.com -``` - -This copies the build in the Nix store and every dependencies to the remote machine. - -To run the program, you can get where the build is by inspecting the symbolic link on your local machine: - -``` bash -readlink ./result -# Returns something like: -# /nix/store/7p4x6kpawrsk6mngrxi3z09bchl2vag1-epics-distribution-custom-0.0.1 -``` - -Now you can run the IOC on the remote machine. - -``` bash -/nix/store/${SHA}-epics-distribution-custom-0.0.1/bin/linux-x86_64/example -``` - - - -If you want to do automated, declarative, or more complex deployments, we highly recommend using NixOS and optionally one of its deployment tools ([NixOps], [morph], [disnix], [colmena]) . -You can also use non-NixOS hosts. - - - - [NixOps]: https://nixos.org/nixops - [morph]: https://github.com/DBCDK/morph - [disnix]: https://github.com/svanderburg/disnix - [colmena]: https://github.com/zhaofengli/colmena - -# Pitfalls - -Although tries to resemble standard EPICS development, some differences might lead to confusion. -You can find more information about this in the [FAQ]. - - - -You might also be interested in reading [Setting up the flake registry] - - [FAQ]: ../faq.md - [Setting up the flake registry]: ../guides/flake-registry.md From b87bf46630bdf82d138752a50206a3e05b9a8daa Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:12:51 +0200 Subject: [PATCH 04/74] doc/ioc/flake-registry: simplify guide --- doc/ioc/guides/flake-registry.md | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/doc/ioc/guides/flake-registry.md b/doc/ioc/guides/flake-registry.md index bc7c3b72..23483acd 100644 --- a/doc/ioc/guides/flake-registry.md +++ b/doc/ioc/guides/flake-registry.md @@ -2,19 +2,17 @@ title: Setting up the flake registry --- -Since the usage of EPNix doesn't encourage installing epics-base globally, some commonly used command-line programs won't be available in your usual environment. +While developing with EPNix, +it's possible you will end up typing `'github:epics-extensions/epnix'` quite often. -It's possible to go into a top, and type `nix develop`{.bash} just to have the `caget`{.bash} command available, but it's quite tedious. +It happens when you need to create a "top" template, +or when you just want to have `epics-base` in your shell, +and so on. -An alternative would be to run: +This is tedious. -``` bash -nix develop 'github:epics-extensions/epnix' -``` - -This will give you the development shell of EPNix itself, with the added benefit of having the latest version of EPICS base. - -The command is quite hard to remember, but with the "registry" feature of Nix, you can shorten it by running: +Nix provides a way of shortening these URLs, +by adding to the [Nix registry][]: ``` bash nix registry add epnix 'github:epics-extensions/epnix' @@ -27,8 +25,11 @@ For example, the develop command to have EPICS based installed outside of a top nix develop epnix ``` -Another benefit is that you can now initialize an EPNix top by running: +If you want to initialize an EPNix top, +you can run: ``` bash nix flake new -t epnix my-top ``` + + [Nix registry]: https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-registry.html#description From fbfa2fe74cd551578bee126567234452404b6595 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:13:20 +0200 Subject: [PATCH 05/74] vale/Vocab: allow StreamDevice --- doc/_vale/Vocab/EPNix/accept.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/_vale/Vocab/EPNix/accept.txt b/doc/_vale/Vocab/EPNix/accept.txt index fe05a868..02030a90 100644 --- a/doc/_vale/Vocab/EPNix/accept.txt +++ b/doc/_vale/Vocab/EPNix/accept.txt @@ -14,6 +14,7 @@ NixOS NixOps procServ SELinux +StreamDevice systemd RedHat [Uu]ntracked From d4811fd9d7af36fd47ea85bd5c5a04c74d226452 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:13:50 +0200 Subject: [PATCH 06/74] templates/top/.gitignore: don't ignore Apps we know transitioned to a top-based development workflow, instead of app-based --- templates/top/.gitignore | 7 ------- 1 file changed, 7 deletions(-) diff --git a/templates/top/.gitignore b/templates/top/.gitignore index 2ddb5492..4030d251 100644 --- a/templates/top/.gitignore +++ b/templates/top/.gitignore @@ -27,10 +27,3 @@ envPaths # Compilation database generated by bear or other compile_commands.json - -# Applications and Support modules should be an EPNix dependency in flake.nix -*App -*Sup -# You can add exceptions like this: -# --- -#!myCustomLocalApp From 982f24719edf627fd054ea9768275ee8638f013b Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 29 Sep 2023 18:21:50 +0200 Subject: [PATCH 07/74] pkgs/psu-simulator: init --- pkgs/default.nix | 3 + pkgs/doc-support/psu-simulator/default.nix | 14 ++ pkgs/doc-support/psu-simulator/poetry.lock | 83 +++++++ .../psu-simulator/psu_simulator/__init__.py | 206 ++++++++++++++++++ pkgs/doc-support/psu-simulator/pyproject.toml | 19 ++ 5 files changed, 325 insertions(+) create mode 100644 pkgs/doc-support/psu-simulator/default.nix create mode 100644 pkgs/doc-support/psu-simulator/poetry.lock create mode 100644 pkgs/doc-support/psu-simulator/psu_simulator/__init__.py create mode 100644 pkgs/doc-support/psu-simulator/pyproject.toml diff --git a/pkgs/default.nix b/pkgs/default.nix index 0d1e908c..6fab40d0 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -68,5 +68,8 @@ in # EPNix specific packages book = callPackage ./book {}; manpages = callPackage ./manpages {}; + + # Documentation support packages + psu-simulator = callPackage ./doc-support/psu-simulator {}; }); } diff --git a/pkgs/doc-support/psu-simulator/default.nix b/pkgs/doc-support/psu-simulator/default.nix new file mode 100644 index 00000000..2f233396 --- /dev/null +++ b/pkgs/doc-support/psu-simulator/default.nix @@ -0,0 +1,14 @@ +{ + poetry2nix, + lib, + epnixLib, +}: +poetry2nix.mkPoetryApplication { + projectDir = ./.; + + meta = { + homepage = "https://epics-extensions.github.io/EPNix/"; + license = lib.licenses.asl20; + maintainers = with epnixLib.maintainers; [minijackson]; + }; +} diff --git a/pkgs/doc-support/psu-simulator/poetry.lock b/pkgs/doc-support/psu-simulator/poetry.lock new file mode 100644 index 00000000..fde1b804 --- /dev/null +++ b/pkgs/doc-support/psu-simulator/poetry.lock @@ -0,0 +1,83 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, + {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} +importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "importlib-metadata" +version = "6.7.0" +description = "Read metadata from Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, + {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, +] + +[package.dependencies] +typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} +zipp = ">=0.5" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +perf = ["ipython"] +testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] + +[[package]] +name = "typing-extensions" +version = "4.7.1" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, + {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, +] + +[[package]] +name = "zipp" +version = "3.15.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, + {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] + +[metadata] +lock-version = "2.0" +python-versions = ">=3.7.0" +content-hash = "1e70b172657bdbef13c5d18991199035640ab2ff4e638ec047db7a4c7a18602c" diff --git a/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py b/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py new file mode 100644 index 00000000..cae3015b --- /dev/null +++ b/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py @@ -0,0 +1,206 @@ +"""A simple power supply simulator.""" + +import logging +import random +import socketserver + +import click + +__version__ = "0.1.0" + +# We don't need cryptographically secure RNG +# ruff: noqa: S311 + +logging.basicConfig(level="INFO", format="%(levelname)s %(message)s") +logger = logging.getLogger(__package__) + +class Server(socketserver.ThreadingMixIn, socketserver.TCPServer): + """TCP server.""" + + allow_reuse_address = True + + current: int = 0 + voltage: int = 0 + resistance: int = 0 + + +class PowerSupply(socketserver.StreamRequestHandler): + """The power supply protocol handler.""" + + def set_current(self: "PowerSupply", val: float) -> None: + """Set the current.""" + self.server.current = val + self.server.voltage = self.server.current * self.server.resistance + + def set_voltage(self: "PowerSupply", val: float) -> None: + """Set the voltage.""" + self.server.voltage = val + self.server.current = self.server.voltage / self.server.resistance + + def handle(self: "PowerSupply") -> None: + """Handle incoming connections.""" + logger.info("received connection") + + self._dispatch = { + b"help": self.cmd_help, + b":idn?": self.cmd_get_identification, + b"meas:curr?": self.cmd_get_measured_current, + b":curr?": self.cmd_get_current, + b":curr": self.cmd_set_current, + b"meas:volt?": self.cmd_get_measured_voltage, + b":volt?": self.cmd_get_voltage, + b":volt": self.cmd_set_voltage, + } + + while True: + try: + args = self.rfile.readline().strip().split() + except BrokenPipeError: + return + + if args == []: + try: + self.wfile.write(b".\n") + except BrokenPipeError: + return + continue + + command = args[0].lower() + params = args[1:] + + decoded_params = [param.decode() for param in params] + logger.info("received command: %s%s", command.decode(), decoded_params) + + if command in self._dispatch: + result = self._dispatch[command](*params) + self.wfile.write(str(result).encode()) + self.wfile.write(b"\n") + else: + self.wfile.write(f"command not found: {command.decode()}\n".encode()) + + def finish(self: "PowerSupply") -> None: + """Clean up connections.""" + logger.info("closed connection") + + def cmd_help(self: "PowerSupply", *args: str) -> str: + """Get help about various commands. + + Usage: help . + """ + if len(args) >= 1: + command = args[0] + if command in self._dispatch: + doc = self._dispatch[command].__doc__ + self.wfile.write(doc.encode()) + else: + self.wfile.write(f"command not found: {command!s}".encode()) + return "" + + self.wfile.write(b"Available commands:\n") + for command, func in self._dispatch.items(): + doc = func.__doc__.splitlines()[0].encode() + self.wfile.write(b" - '" + command + b"': " + doc + b"\n") + + return "" + + def cmd_get_identification(self: "PowerSupply", *_args: str) -> int: + """Return the identification of the power supply. + + Usage: :idn? + Returns: string + """ + return f"psu-simulator {__version__}" + + def cmd_get_measured_current(self: "PowerSupply", *_args: str) -> int: + """Return the measured current, in Amps. + + Usage: meas:curr? + Returns: float + """ + return self.server.current + random.uniform(-1.5, 1.5) + + def cmd_get_current(self: "PowerSupply", *_args: str) -> int: + """Return the current current command, in Amps. + + Usage: :curr? + Returns: float + """ + return self.server.current + + def cmd_set_current(self: "PowerSupply", *args: str) -> str: + """Set the current, in Amps. + + Usage: :curr + Returns: 'OK' | 'ERR' + """ + try: + val = float(args[0]) + except ValueError: + return "ERR" + else: + self.set_current(val) + return "OK" + + def cmd_get_measured_voltage(self: "PowerSupply", *_args: str) -> int: + """Return the measured voltage, in Volts. + + Usage: meas:volt? + Returns: float + """ + return self.server.voltage + random.uniform(-1.5, 1.5) + + def cmd_get_voltage(self: "PowerSupply", *_args: str) -> int: + """Return the voltage voltage command, in Volts. + + Usage: :volt? + Returns: float + """ + return self.server.voltage + + def cmd_set_voltage(self: "PowerSupply", *args: str) -> str: + """Set the voltage, in Volts. + + Usage: :volt + Returns: 'OK' | 'ERR' + """ + try: + val = float(args[0]) + except ValueError: + return "ERR" + else: + self.set_voltage(val) + return "OK" + + +@click.command() +@click.option( + "-l", + "--listen-address", + default="localhost", + show_default=True, + help="Listening address", +) +@click.option( + "-p", + "--port", + default=8727, + show_default=True, + help="Listening TCP port", +) +@click.option( + "--resistance", + default=20, + show_default=True, + help="Resistance of the circuit connected to the power supply, in Ohms.", +) +def main(listen_address: str, port: int, resistance: int) -> None: + """Start a power supply simulator server.""" + with Server((listen_address, port), PowerSupply) as server: + logger.info("Listening on %s:%s", listen_address, port) + server.resistance = resistance + logger.info("Resistance is %s Ohms", resistance) + + try: + server.serve_forever() + except KeyboardInterrupt: + return diff --git a/pkgs/doc-support/psu-simulator/pyproject.toml b/pkgs/doc-support/psu-simulator/pyproject.toml new file mode 100644 index 00000000..cc599d2f --- /dev/null +++ b/pkgs/doc-support/psu-simulator/pyproject.toml @@ -0,0 +1,19 @@ +[tool.poetry] +name = "psu-simulator" +version = "0.1.0" +description = "A power supply simulator for the StreamDevice tutorial" +authors = ["Rémi NICOLE "] + +[tool.poetry.scripts] +psu-simulator = "psu_simulator:main" + +[tool.poetry.dependencies] +python = ">=3.7.0" +click = "^8.1.7" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +select = ["ALL"] From 7be1fea49216edb3497b0d093358cec91816e11a Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 9 Jan 2024 16:31:04 +0100 Subject: [PATCH 08/74] templates/top/flake: change wording for Apps as separate repo This is to slightly discourage people from doing this. --- templates/top/flake.nix | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/templates/top/flake.nix b/templates/top/flake.nix index 9ea2c6a2..a1cb68d4 100644 --- a/templates/top/flake.nix +++ b/templates/top/flake.nix @@ -4,7 +4,8 @@ inputs.flake-utils.url = "github:numtide/flake-utils"; inputs.epnix.url = "github:epics-extensions/epnix"; - # Add your app inputs here: + # If you have an "App" as a separate repository, + # add it as an input here: # --- #inputs.exampleApp = { # url = "git+ssh://git@my-server.org/me/exampleApp.git"; @@ -36,8 +37,8 @@ # --- #support.modules = with pkgs.epnix.support; [ StreamDevice ]; - # Add your applications: - # Note that flake inputs must be quoted in this context + # If you have an "App" as a separate repository, + # add it here: # --- #applications.apps = [ "inputs.exampleApp" ]; From d506aa73be2b257d067434acf39c8d3ca5669302 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 11 Jan 2024 09:30:31 +0100 Subject: [PATCH 09/74] README: fix documentation book URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a12ce02b..35904260 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ For more information, see the [NixOS modules introduction]. See [over there] in the documentation book. - [over there]: https://epics-extensions.github.io/EPNix/ioc/tutorials/getting-started.html + [over there]: https://epics-extensions.github.io/EPNix/ ## Packaging policy From 21c31df76650bd085fc488fd5472c9bf4681ef35 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 11 Jan 2024 09:30:53 +0100 Subject: [PATCH 10/74] README: don't encourage the usage of external Apps --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 35904260..7748fade 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,6 @@ epnix = { # --- support.modules = with pkgs.epnix.support; [ StreamDevice ]; - # Add your applications: - # --- - applications.apps = [ "inputs.myExampleApp" ]; - # You can specify environment variables for your development shell like this: # --- devShell.environment.variables."EPICS_CA_ADDR_LIST" = "localhost"; From 66c9f6dbbb685fadb9abefcc9621081c8e431916 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 11 Jan 2024 11:14:22 +0100 Subject: [PATCH 11/74] phoebus: 4.7.2 -> 4.7.3 --- nixos/tests/phoebus/save-and-restore.py | 8 +++++--- pkgs/epnix/tools/phoebus/deps/default.nix | 8 ++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/nixos/tests/phoebus/save-and-restore.py b/nixos/tests/phoebus/save-and-restore.py index 1695a2e7..03b542b7 100644 --- a/nixos/tests/phoebus/save-and-restore.py +++ b/nixos/tests/phoebus/save-and-restore.py @@ -8,11 +8,13 @@ root_node_id = "44bef5de-e8e6-4014-af37-b8f6c8a939a2" user = "myself" +base_url = "http://server:8080/save-restore" + def get(uri: str): return json.loads( client.succeed( - "curl -sSf " "-H 'Accept: application/json' " f"'http://server:8080{uri}'" + "curl -sSf " "-H 'Accept: application/json' " f"'{base_url}{uri}'" ) ) @@ -25,7 +27,7 @@ def put(uri: str, data: JSON): "-X PUT " "-H 'Content-Type: application/json' " "-H 'Accept: application/json' " - f"'http://server:8080{uri}' " + f"'{base_url}{uri}' " f"--data '{encoded_data}'" ) ) @@ -37,7 +39,7 @@ def delete(uri: str): "-X DELETE " "-H 'Content-Type: application/json' " "-H 'Accept: application/json' " - f"'http://server:8080{uri}'" + f"'{base_url}{uri}'" ) diff --git a/pkgs/epnix/tools/phoebus/deps/default.nix b/pkgs/epnix/tools/phoebus/deps/default.nix index ad341141..cafe6038 100644 --- a/pkgs/epnix/tools/phoebus/deps/default.nix +++ b/pkgs/epnix/tools/phoebus/deps/default.nix @@ -8,13 +8,13 @@ }: stdenv.mkDerivation { pname = "phoebus-deps"; - version = "4.7.2"; + version = "4.7.3"; src = fetchFromGitHub { owner = "ControlSystemStudio"; repo = "phoebus"; - rev = "v4.7.2"; - hash = "sha256-UdfwQaOFvx+Ox68P2WuI8sN4eUmyW2WmoVKBj9ZzMXc="; + rev = "v4.7.3"; + hash = "sha256-1Q66iZ+mTXzQ9pjW5wypG7q7rPy9K+PUcQXsKKk2sNo="; }; nativeBuildInputs = [jdk maven]; @@ -58,7 +58,7 @@ stdenv.mkDerivation { outputHashAlgo = "sha256"; outputHashMode = "recursive"; - outputHash = "sha256-HFrdvjuImn77y2TJvOTxJUFQSwP3umIPklpqI4feplY="; + outputHash = "sha256-9MJdmIVAqjPW5ihZYWCh+zsWlxrtoHBH7NFwPh01pRc="; doCheck = false; From 3b6984c15195b2e76de764ac50795d5b726c3454 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 11 Jan 2024 13:35:59 +0100 Subject: [PATCH 12/74] nixos/local-kafka: always configure replication factor documentation recommends changing `extraProperties`, which overrides the properties defined here, which makes Kafka complains that the replication factor can't be applied --- nixos/modules/phoebus/local-kafka.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nixos/modules/phoebus/local-kafka.nix b/nixos/modules/phoebus/local-kafka.nix index a206f76f..4c5193df 100644 --- a/nixos/modules/phoebus/local-kafka.nix +++ b/nixos/modules/phoebus/local-kafka.nix @@ -11,7 +11,7 @@ # TODO: document replication setup services.apache-kafka = { logDirs = lib.mkDefault ["/var/lib/apache-kafka"]; - extraProperties = lib.mkDefault '' + extraProperties = '' offsets.topic.replication.factor=1 transaction.state.log.replication.factor=1 transaction.state.log.min.isr=1 From 6d624420b50d30fd9f86731af5b2e685c920d4e6 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 11 Jan 2024 16:30:38 +0100 Subject: [PATCH 13/74] ioc/modules/nixos-integration: change Restart systemd option to always sometimes procServ exits cleanly, even though the IOC was killed by a signal (e.g. SIGSEGV). The IOC should restart in that case. --- ioc/modules/nixos-integration.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioc/modules/nixos-integration.nix b/ioc/modules/nixos-integration.nix index 8669242b..0318ae2f 100644 --- a/ioc/modules/nixos-integration.nix +++ b/ioc/modules/nixos-integration.nix @@ -110,7 +110,7 @@ in { ${toString config.procServ.port} \ ${iocTop}/bin/${arch}/${config.app} ${config.startCommandsFile} ''; - Restart = "on-failure"; + Restart = "always"; }; }; })); From 353d9d10dadeec69341eb8642722d76c17129b19 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 19 Jan 2024 13:52:13 +0100 Subject: [PATCH 14/74] ioc/common: config.epnix.outputs is an attrsOf package epnix.outputs is used in downstream's flake's `packages` output, which can only contain packages, so it's important to not break people's CI --- ioc/modules/common.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioc/modules/common.nix b/ioc/modules/common.nix index a863e2a3..d98303da 100644 --- a/ioc/modules/common.nix +++ b/ioc/modules/common.nix @@ -27,7 +27,7 @@ with lib; { ~ The actual build of this distribution. ''; default = {}; - type = types.attrs; + type = with types; attrsOf package; }; epnix.pkgs = mkOption { From e7679dcf2b5548e8691a3a80eab0a6e70ed45478 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 19 Jan 2024 13:55:20 +0100 Subject: [PATCH 15/74] lib: refactor evaluation, make a function pkgs -> eval this moves the evaluation of the EPNix configuration into its own file this adds a new `epnixFunEval` which is a function that takes `pkgs` as an argument, and evals the EPNix config with this specific package set this function will be used so that an EPNix support module can be used by another EPNix top. It will reuse the same dependencies (the same epics-base, the same support modules, the same system libraries), and will reuse the same nixpkgs configuration (for example cross-compilation configuration). --- lib/default.nix | 62 +----------------------------- lib/evaluation.nix | 95 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 97 insertions(+), 60 deletions(-) create mode 100644 lib/evaluation.nix diff --git a/lib/default.nix b/lib/default.nix index 1edfd521..38ed4520 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -7,71 +7,13 @@ with lib; let self = { documentation = import ./documentation.nix args; + evaluation = import ./evaluation.nix args; formats = import ./formats.nix args; licenses = import ./licenses.nix args; maintainers = import ./maintainers/maintainer-list.nix; testing = import ./testing.nix; - evalEpnixModules = { - nixpkgsConfig, - epnixConfig, - }: let - nixpkgsConfigWithDefaults = - { - crossSystem = null; - config = {}; - } - // nixpkgsConfig; - eval = evalModules { - modules = [ - ({config, ...}: { - config._module.args = let - # Configure the available packages with e.g. cross compilation - # and overlays - finalPkgs = import inputs.nixpkgs { - inherit (nixpkgsConfigWithDefaults) system crossSystem config; - inherit (config.nixpkgs) overlays; - }; - in { - # See: https://github.com/NixOS/nixpkgs/pull/190358 - pkgs = finalPkgs.__splicedPackages; - - # Used when we want to apply the same config in checks - inherit epnixConfig; - }; - }) - - epnixConfig - inputs.self.nixosModules.ioc - - # nixpkgs and assertions are separate, in case we want to include - # this module in a NixOS configuration, where `nixpkgs` and - # `assertions` options are already defined - ../ioc/modules/nixpkgs.nix - ../ioc/modules/assertions.nix - ]; - }; - - # From Robotnix - # From nixpkgs/nixos/modules/system/activation/top-level.nix - failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) eval.config.assertions); - - config = - if failedAssertions != [] - then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" - else lib.showWarnings eval.config.warnings eval.config; - in { - inherit (eval) options; - inherit config; - - inherit (config.epnix) outputs; - }; - - mkEpnixBuild = cfg: - (self.evalEpnixModules cfg).config.epnix.outputs.build; - - mkEpnixDevShell = cfg: - (self.evalEpnixModules cfg).config.epnix.outputs.devShell; + inherit (self.evaluation) evalEpnixModules mkEpnixBuild mkEpnixDevShell; # Like lib.getName, but also supports paths getName = thing: diff --git a/lib/evaluation.nix b/lib/evaluation.nix new file mode 100644 index 00000000..8e9cc6dd --- /dev/null +++ b/lib/evaluation.nix @@ -0,0 +1,95 @@ +{ + inputs, + lib, + ... +}: let + evalEpnixModules' = { + epnixConfig, + epnixFunEval, + pkgs, + }: let + eval = lib.evalModules { + modules = [ + ({config, ...}: { + config._module.args = { + pkgs = pkgs config; + + # Used when we want to apply the same config in checks + inherit epnixConfig; + inherit epnixFunEval; + }; + }) + + epnixConfig + inputs.self.nixosModules.ioc + + # nixpkgs and assertions are separate, in case we want to include + # this module in a NixOS configuration, where `nixpkgs` and + # `assertions` options are already defined + ../ioc/modules/nixpkgs.nix + ../ioc/modules/assertions.nix + ]; + }; + + # From Robotnix + # From nixpkgs/nixos/modules/system/activation/top-level.nix + failedAssertions = map (x: x.message) (lib.filter (x: !x.assertion) eval.config.assertions); + + config = + if failedAssertions != [] + then throw "\nFailed assertions:\n${lib.concatStringsSep "\n" (map (x: "- ${x}") failedAssertions)}" + else lib.showWarnings eval.config.warnings eval.config; + in { + inherit (eval) options; + inherit config; + + inherit (config.epnix) outputs generatedOverlay; + }; + + self = { + evalEpnixModules = { + nixpkgsConfig, + epnixConfig, + }: let + nixpkgsConfigWithDefaults = + { + crossSystem = null; + config = {}; + } + // nixpkgsConfig; + + pkgs = config: + (import inputs.nixpkgs { + inherit (nixpkgsConfigWithDefaults) system crossSystem config; + inherit (config.nixpkgs) overlays; + }) + # See: https://github.com/NixOS/nixpkgs/pull/190358 + .__splicedPackages; + + # As a function, + # so that we can import the package without fixing the dependencies. + # + # This is needed because, + # if this package is an EPICS support module, + # it needs to *not* depend on a specific version of epics-base. + # + # It needs to use the same version of epics-base + # that is going to be used by the final IOC. + epnixFunEval = pkgs: + evalEpnixModules' { + inherit epnixConfig epnixFunEval; + pkgs = config: pkgs; + }; + + fixedEval = evalEpnixModules' {inherit epnixConfig epnixFunEval pkgs;}; + in + fixedEval; + + mkEpnixBuild = cfg: + (self.evalEpnixModules cfg).config.epnix.outputs.build; + + mkEpnixDevShell = cfg: + (self.evalEpnixModules cfg).config.epnix.outputs.devShell; + }; +in + self From ae921da1422b0ff50bb518957f689d1801668561 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 19 Jan 2024 14:07:31 +0100 Subject: [PATCH 16/74] ioc/outputs: generate an overlay containing the top package this generates an nixpkgs overlay[1], with the current top as a package inside `epnix.support` [1]: https://nixos.org/manual/nixpkgs/stable/#chap-overlays this means that the top can be exported as a support module, and dependants top can import that support module by importing the overlay, and adding the package in the `epnix.support.modules` option --- ioc/modules/outputs.nix | 42 +++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) diff --git a/ioc/modules/outputs.nix b/ioc/modules/outputs.nix index 34865ca6..41f56887 100644 --- a/ioc/modules/outputs.nix +++ b/ioc/modules/outputs.nix @@ -3,6 +3,7 @@ lib, pkgs, epnix, + epnixFunEval, ... }: with lib; let @@ -19,25 +20,42 @@ with lib; let toUpper ]; in { - options.epnix.buildConfig = { - attrs = mkOption { - description = "Extra attributes to pass to the derivation"; - type = types.attrs; - default = {}; - }; + options.epnix = { + buildConfig = { + attrs = mkOption { + description = "Extra attributes to pass to the derivation"; + type = types.attrs; + default = {}; + }; + + src = mkOption { + description = '' + The source code for the top. - src = mkOption { - description = '' - The source code for the top. + Defaults to the directory containing the `flake.nix` file. + ''; + type = types.path; + }; + }; - Defaults to the directory containing the `flake.nix` file. - ''; - type = types.path; + generatedOverlay = mkOption { + description = "A generated overlay which has your package inside `pkgs.epnix.support`."; + type = with types; functionTo (functionTo attrs); }; }; config.epnix.buildConfig.src = mkDefault config.epnix.inputs.self; + config.epnix.generatedOverlay = final: prev: let + newEval = final.callPackage epnixFunEval final; + in { + epnix = prev.epnix.extend (_final: prev: { + support = prev.support.extend (_final: _prev: { + "${config.epnix.meta.name}" = newEval.config.epnix.outputs.build; + }); + }); + }; + config.epnix.outputs.build = pkgs.mkEpicsPackage ({ pname = "epnix-${config.epnix.meta.name}"; inherit (config.epnix.meta) version; From 7a37fb50f40e0aeb099b55740d93c476889b18c9 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 19 Jan 2024 14:10:45 +0100 Subject: [PATCH 17/74] templates/top: show how to export/import EPNix support modules importing an EPNix support modules by: - adding the repository as a flake input - importing its overlay - adding the package as a dependency in `epnix.support.modules` exporting an EPNix support modules by: - exporting the generated overlay --- templates/top/flake.nix | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/templates/top/flake.nix b/templates/top/flake.nix index a1cb68d4..3be88393 100644 --- a/templates/top/flake.nix +++ b/templates/top/flake.nix @@ -4,6 +4,14 @@ inputs.flake-utils.url = "github:numtide/flake-utils"; inputs.epnix.url = "github:epics-extensions/epnix"; + # If you have a support module as a separate EPNix repository, + # add it as an input here: + # --- + #inputs.mySupportModule = { + # url = "git+ssh://git@my-server.org/me/exampleApp.git"; + # inputs.epnix.follows = "epnix"; + #}; + # If you have an "App" as a separate repository, # add it as an input here: # --- @@ -18,10 +26,15 @@ epnix, ... } @ inputs: let - myEpnixDistribution = {pkgs, ...}: { + myEpnixConfig = {pkgs, ...}: { # Set your EPNix options here # --- + # If you have a support module as a separate EPNix repository, + # uncomment this line to make the package available: + # --- + #overlays = [inputs.mySupportModule.overlays.default]; + epnix = { inherit inputs; @@ -33,9 +46,9 @@ # --- #epics-base.releaseBranch = "3"; # Defaults to "7" - # Add one of the supported modules here: + # Add your support modules here: # --- - #support.modules = with pkgs.epnix.support; [ StreamDevice ]; + #support.modules = with pkgs.epnix.support; [ StreamDevice mySupportModule ]; # If you have an "App" as a separate repository, # add it here: @@ -69,7 +82,7 @@ # environment can be built on your machine. flake-utils.lib.eachSystem ["x86_64-linux"] (system: with epnix.lib; let - result = evalEpnixModules { + epnixDistribution = evalEpnixModules { nixpkgsConfig = { # This specifies the build architecture inherit system; @@ -81,17 +94,23 @@ # --- #crossSystem = epnix.inputs.nixpkgs.lib.systems.examples.armv7l-hf-multiplatform; }; - epnixConfig = myEpnixDistribution; + epnixConfig = myEpnixConfig; }; in { packages = - result.outputs + epnixDistribution.outputs // { default = self.packages.${system}.build; }; + inherit epnixDistribution; + devShells.default = self.packages.${system}.devShell; - checks = result.config.epnix.checks.derivations; - }); + checks = epnixDistribution.config.epnix.checks.derivations; + }) + // { + overlays.default = final: prev: + self.epnixDistribution.x86_64-linux.generatedOverlay final prev; + }; } From fa0862f24daac48604ff6cebcfa86275842f4d2c Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 2 Feb 2024 09:06:58 +0100 Subject: [PATCH 18/74] github: update actions, pin them with pinact because tags can be changed, they are a security risk. using the commit hash is safer --- .github/workflows/book-gh-pages.yml | 10 +++++----- .github/workflows/editorconfig.yml | 4 ++-- .github/workflows/formatting.yml | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index 7fa65cfd..bf929f35 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -23,18 +23,18 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Build documentation book" run: | nix build '.#book' --print-build-logs cp -Lr --no-preserve=mode,ownership ./result/ ./book - name: Setup Pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@0252fc4ba7626f0298f0cf00902a25c6afc77fa8 # v3.0.0 with: path: './book' - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@87c3283f01cd6fe19a0ab93a23b2f6fcba5a8e42 # v4.0.3 diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml index ab25caa2..a201b54e 100644 --- a/.github/workflows/editorconfig.yml +++ b/.github/workflows/editorconfig.yml @@ -10,7 +10,7 @@ jobs: editorconfig: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Check EditorConfig" run: nix run 'nixpkgs#eclint' --inputs-from . diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index 2afc5367..cc41641e 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -10,7 +10,7 @@ jobs: alejandra: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - uses: cachix/install-nix-action@v20 + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Check Formatting" run: nix fmt -- --check . From 0386c7cbeb8cf5f8d15c373e570a01d54d7093ea Mon Sep 17 00:00:00 2001 From: Minijackson Date: Mon, 7 Aug 2023 13:10:02 +0200 Subject: [PATCH 19/74] pkgs/pvxs: init at 1.3.1 --- pkgs/default.nix | 1 + pkgs/epnix/support/pvxs/default.nix | 38 +++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 pkgs/epnix/support/pvxs/default.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index 6fab40d0..a56a169f 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -31,6 +31,7 @@ in epics-systemd = callPackage ./epnix/support/epics-systemd {}; ipac = callPackage ./epnix/support/ipac {}; modbus = callPackage ./epnix/support/modbus {}; + pvxs = callPackage ./epnix/support/pvxs {}; seq = callPackage ./epnix/support/seq {}; snmp = callPackage ./epnix/support/snmp {}; sscan = callPackage ./epnix/support/sscan {}; diff --git a/pkgs/epnix/support/pvxs/default.nix b/pkgs/epnix/support/pvxs/default.nix new file mode 100644 index 00000000..a0a9145a --- /dev/null +++ b/pkgs/epnix/support/pvxs/default.nix @@ -0,0 +1,38 @@ +{ + lib, + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + libevent, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage rec { + pname = "pvxs"; + version = "1.3.1"; + varname = "PVXS"; + + inherit local_config_site local_release; + + src = fetchFromGitHub { + owner = "mdavidsaver"; + repo = "pvxs"; + rev = version; + sha256 = "sha256-V/38TdjuBuhZE7bsvtLfQ3QH7bmwNdKHpvVeA81oOXY="; + }; + + # TODO: check pvxs cross-compilation, + # since it has a somewhat complex logic for finding libevent + propagatedNativeBuildInputs = [libevent]; + propagatedBuildInputs = [libevent]; + + # Only loopback interface is present + doCheck = false; + + meta = { + description = "PVA protocol client/server library and utilities"; + homepage = "https://mdavidsaver.github.io/pvxs/"; + license = lib.licenses.bsd3; + maintainers = with epnixLib.maintainers; [minijackson]; + }; +} From 0bd438f1ed63e2a392945f5fe16774b6c2715479 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 2 Feb 2024 13:14:57 +0100 Subject: [PATCH 20/74] ioc/tests/pvxs: add test for using PVXS inside an IOC --- ioc/tests/default.nix | 3 +- ioc/tests/support/pvxs/ioc/default.nix | 80 +++++++++++++++++++ .../pvxs/ioc/pvxsIocTestTop/.gitignore | 29 +++++++ .../support/pvxs/ioc/pvxsIocTestTop/Makefile | 31 +++++++ .../pvxs/ioc/pvxsIocTestTop/configure/CONFIG | 45 +++++++++++ .../ioc/pvxsIocTestTop/configure/CONFIG_SITE | 43 ++++++++++ .../ioc/pvxsIocTestTop/configure/Makefile | 8 ++ .../pvxs/ioc/pvxsIocTestTop/configure/RELEASE | 42 ++++++++++ .../pvxs/ioc/pvxsIocTestTop/configure/RULES | 6 ++ .../ioc/pvxsIocTestTop/configure/RULES.ioc | 2 + .../ioc/pvxsIocTestTop/configure/RULES_DIRS | 2 + .../ioc/pvxsIocTestTop/configure/RULES_TOP | 3 + .../support/pvxs/ioc/pvxsIocTestTop/epnix.nix | 13 +++ .../pvxs/ioc/pvxsIocTestTop/iocBoot/Makefile | 6 ++ .../pvxsIocTestTop/iocBoot/iocSimple/Makefile | 5 ++ .../pvxsIocTestTop/iocBoot/iocSimple/st.cmd | 11 +++ .../ioc/pvxsIocTestTop/simpleApp/Db/Makefile | 18 +++++ .../ioc/pvxsIocTestTop/simpleApp/Makefile | 14 ++++ .../ioc/pvxsIocTestTop/simpleApp/src/Makefile | 47 +++++++++++ .../pvxsIocTestTop/simpleApp/src/pvxsIoc.cpp | 39 +++++++++ .../simpleApp/src/registrar.dbd | 1 + .../simpleApp/src/simpleMain.cpp | 23 ++++++ 22 files changed, 470 insertions(+), 1 deletion(-) create mode 100644 ioc/tests/support/pvxs/ioc/default.nix create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/.gitignore create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG_SITE create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RELEASE create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES.ioc create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_DIRS create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_TOP create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/epnix.nix create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/Makefile create mode 100755 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/st.cmd create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Db/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/Makefile create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/pvxsIoc.cpp create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/registrar.dbd create mode 100644 ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/simpleMain.cpp diff --git a/ioc/tests/default.nix b/ioc/tests/default.nix index 679e34e7..06dcd62e 100644 --- a/ioc/tests/default.nix +++ b/ioc/tests/default.nix @@ -4,9 +4,10 @@ with pkgs.lib; default-ioc-epics-base-3 = import ./default-ioc "3" args; default-ioc-epics-base-7 = import ./default-ioc "7" args; + support-autosave-simple = import ./support/autosave/simple args; + support-pvxs-ioc = import ./support/pvxs/ioc args; support-seq-simple = import ./support/seq/simple args; support-StreamDevice-simple = import ./support/StreamDevice/simple args; - support-autosave-simple = import ./support/autosave/simple args; } // (let checkCrossFor = crossSystem: let diff --git a/ioc/tests/support/pvxs/ioc/default.nix b/ioc/tests/support/pvxs/ioc/default.nix new file mode 100644 index 00000000..242ef9b5 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/default.nix @@ -0,0 +1,80 @@ +{pkgs, ...}: let + inherit (pkgs) epnixLib; + inherit (pkgs.stdenv.hostPlatform) system; + + result = epnixLib.evalEpnixModules { + nixpkgsConfig.system = system; + epnixConfig.imports = [./pvxsIocTestTop/epnix.nix]; + }; + + service = result.config.epnix.nixos.services.ioc.config; + + ioc = result.outputs.build; +in + pkgs.nixosTest { + name = "support-pvxs-ioc"; + meta.maintainers = with epnixLib.maintainers; [minijackson]; + + nodes = { + client = { + environment.systemPackages = [ + pkgs.epnix.epics-base + pkgs.epnix.support.pvxs + ]; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + ioc = { + systemd.services.ioc = service; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + }; + + testScript = '' + import json + + start_all() + + addr_list = "EPICS_PVA_ADDR_LIST=192.168.1.2" + + def pvget(name: str): + return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + + def pvxget(name: str): + output = client.succeed(f"{addr_list} pvxget {name}") + return output.splitlines()[1].split()[-1] + + def _pvput(utility: str, name: str, value: str): + client.succeed(f"{addr_list} {utility} {name} {value}") + + def pvput(name: str, value: str): + _pvput("pvput", name, value) + + def pvxput(name: str, value: str): + _pvput("pvxput", name, value) + + with subtest("wait until IOC starts"): + ioc.wait_for_unit("ioc.service") + client.wait_until_succeeds(f"{addr_list} pvget my:pv:name", timeout=60) + + with subtest("PV has the correct value"): + value = pvget("my:pv:name") + assert value["value"] == 42 + assert value["display"]["description"] == "My PV description" + + with subtest("PV can be set"): + pvput("my:pv:name", "1337") + assert pvget("my:pv:name")["value"] == 1337 + + with subtest("PVXS command-line utilities work"): + assert pvxget("my:pv:name") == "1337" + pvxput("my:pv:name", "42") + assert pvxget("my:pv:name") == "42" + client.succeed(f"{addr_list} pvxinfo my:pv:name") + ''; + + passthru = { + inherit ioc; + }; + } diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/.gitignore b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/.gitignore new file mode 100644 index 00000000..3d648caa --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/.gitignore @@ -0,0 +1,29 @@ +# Install directories +/bin/ +/cfg/ +/db/ +/dbd/ +/html/ +/include/ +/lib/ +/templates/ + +# Local configuration files +/configure/*.local + +# iocBoot generated files +/iocBoot/*ioc*/cdCommands +/iocBoot/*ioc*/dllPath.bat +/iocBoot/*ioc*/envPaths +/iocBoot/*ioc*/relPaths.sh + +# Build directories +O.*/ + +# Common files created by other tools +/QtC-* +/.vscode/ +*.orig +*.log +.*.swp +.DS_Store diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/Makefile new file mode 100644 index 00000000..19c9068d --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/Makefile @@ -0,0 +1,31 @@ +# Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG + +# Directories to build, any order +DIRS += configure +DIRS += $(wildcard *Sup) +DIRS += $(wildcard *App) +DIRS += $(wildcard *Top) +DIRS += $(wildcard iocBoot) + +# The build order is controlled by these dependency rules: + +# All dirs except configure depend on configure +$(foreach dir, $(filter-out configure, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += configure)) + +# Any *App dirs depend on all *Sup dirs +$(foreach dir, $(filter %App, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup, $(DIRS)))) + +# Any *Top dirs depend on all *Sup and *App dirs +$(foreach dir, $(filter %Top, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup %App, $(DIRS)))) + +# iocBoot depends on all *App dirs +iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS)) + +# Add any additional dependency rules here: + +include $(TOP)/configure/RULES_TOP diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG new file mode 100644 index 00000000..34ace577 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG @@ -0,0 +1,45 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + -include $(TOP)/configure/RELEASE.Common.$(T_A) + -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +# Check EPICS_BASE is set properly +ifneq (file,$(origin EPICS_BASE)) + $(error EPICS_BASE must be set in a configure/RELEASE file) +else + ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),) + $(error EPICS_BASE does not point to an EPICS installation) + endif +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain local build configuration settings +include $(TOP)/configure/CONFIG_SITE + +# Host-arch specific settings +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + # Target-arch specific settings + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + + # Host & target specific settings + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG_SITE b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG_SITE new file mode 100644 index 00000000..212485eb --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/CONFIG_SITE @@ -0,0 +1,43 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building even if conflicts are found. +CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when the IOC and build host use different paths +# to the install location. This may be needed to boot from +# a Microsoft FTP server say, or on some NFS configurations. +#IOCS_APPL_TOP = + +# For application debugging purposes, override the HOST_OPT and/ +# or CROSS_OPT settings from base/configure/CONFIG_SITE +#HOST_OPT = NO +#CROSS_OPT = NO + +# These allow developers to override the CONFIG_SITE variable +# settings without having to modify the configure/CONFIG_SITE +# file itself. +-include $(TOP)/../CONFIG_SITE.local +-include $(TOP)/configure/CONFIG_SITE.local + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/Makefile new file mode 100644 index 00000000..92543094 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RELEASE b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RELEASE new file mode 100644 index 00000000..d3866518 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RELEASE @@ -0,0 +1,42 @@ +# RELEASE - Location of external support modules +# +# IF YOU CHANGE ANY PATHS in this file or make API changes to +# any modules it refers to, you should do a "make rebuild" in +# this application's top level directory. +# +# The EPICS build process does not check dependencies against +# any files from outside the application, so it is safest to +# rebuild it completely if any modules it depends on change. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file is parsed by both GNUmake and an EPICS Perl script, +# so it may ONLY contain definititions of paths to other support +# modules, variable definitions that are used in module paths, +# and include statements that pull in other RELEASE files. +# Variables may be used before their values have been set. +# Build variables that are NOT used in paths should be set in +# the CONFIG_SITE file. + +# Variables and paths to dependent modules: +#MODULES = /path/to/modules +#MYMODULE = $(MODULES)/my-module + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ = $(MODULES)/seq-ver + +# EPICS_BASE should appear last so earlier modules can override stuff: +EPICS_BASE = /nix/store/9g8q47p14l33kbcz7agz8nz914ghmnzq-epics-base-7.0.7 + +# Set RULES here if you want to use build rules from somewhere +# other than EPICS_BASE: +#RULES = $(MODULES)/build-rules + +# These lines allow developers to override these RELEASE settings +# without having to modify this file directly. +-include $(TOP)/../RELEASE.local +-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local +-include $(TOP)/configure/RELEASE.local diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES new file mode 100644 index 00000000..6d56e14e --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES.ioc b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES.ioc new file mode 100644 index 00000000..901987c6 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_DIRS b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_DIRS new file mode 100644 index 00000000..3ba269dc --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_TOP b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_TOP new file mode 100644 index 00000000..d09d668d --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/epnix.nix b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/epnix.nix new file mode 100644 index 00000000..91a433be --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/epnix.nix @@ -0,0 +1,13 @@ +{pkgs, ...}: { + epnix = { + meta.name = "checks-support-pvxs-ioc"; + buildConfig.src = ./.; + + support.modules = with pkgs.epnix.support; [pvxs]; + + nixos.services.ioc = { + app = "simple"; + ioc = "iocSimple"; + }; + }; +} diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/Makefile new file mode 100644 index 00000000..91e47d0b --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/Makefile @@ -0,0 +1,6 @@ +TOP = .. +include $(TOP)/configure/CONFIG +DIRS += $(wildcard *ioc*) +DIRS += $(wildcard as*) +include $(CONFIG)/RULES_DIRS + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/Makefile new file mode 100644 index 00000000..e1b9aa4a --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/Makefile @@ -0,0 +1,5 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = $(EPICS_HOST_ARCH) +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/st.cmd b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/st.cmd new file mode 100755 index 00000000..5eeca7b8 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/iocBoot/iocSimple/st.cmd @@ -0,0 +1,11 @@ +#!../../bin/linux-x86_64/simple + +< envPaths + +epicsEnvSet("PREFIX", "autosave:test") + +## Register all support components +dbLoadDatabase("$(TOP)/dbd/simple.dbd") +simple_registerRecordDeviceDriver(pdbbase) + +iocInit() diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Db/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Db/Makefile new file mode 100644 index 00000000..8eb97279 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Db/Makefile @@ -0,0 +1,18 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + +#---------------------------------------------------- +# Create and install (or just install) into /db +# databases, templates, substitutions like this +#DB += xxx.db + +#---------------------------------------------------- +# If .db template is not named *.template add +# _template = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Makefile new file mode 100644 index 00000000..60ab8ae8 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/Makefile @@ -0,0 +1,14 @@ +# Makefile at top of application tree +TOP = .. +include $(TOP)/configure/CONFIG + +# Directories to be built, in any order. +# You can replace these wildcards with an explicit list +DIRS += $(wildcard src* *Src*) +DIRS += $(wildcard db* *Db*) + +# If the build order matters, add dependency rules like this, +# which specifies that xxxSrc must be built after src: +#xxxSrc_DEPEND_DIRS += src + +include $(TOP)/configure/RULES_DIRS diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/Makefile b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/Makefile new file mode 100644 index 00000000..0e305c32 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/Makefile @@ -0,0 +1,47 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#============================= +# Build the IOC application + +PROD_IOC = simple +# simple.dbd will be created and installed +DBD += simple.dbd + +# simple.dbd will be made up from these files: +simple_DBD += base.dbd + +# Include dbd files from all support applications: +simple_DBD += pvxsIoc.dbd + +simple_DBD += registrar.dbd + +# Add all the support libraries needed by this IOC +#simple_LIBS += xxx +simple_LIBS += pvxsIoc pvxs + +# simple_registerRecordDeviceDriver.cpp derives from simple.dbd +simple_SRCS += simple_registerRecordDeviceDriver.cpp + +# Build the main IOC entry point on workstation OSs. +simple_SRCS_DEFAULT += simpleMain.cpp +simple_SRCS_vxWorks += -nil- + +simple_SRCS += pvxsIoc.cpp + +# Add support from base/src/vxWorks if needed +#simple_OBJS_vxWorks += $(EPICS_BASE_BIN)/vxComLibrary + +# Finally link to the EPICS Base libraries +simple_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/pvxsIoc.cpp b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/pvxsIoc.cpp new file mode 100644 index 00000000..8be2bbfd --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/pvxsIoc.cpp @@ -0,0 +1,39 @@ +#include +#include + +#include +#include +#include +#include + +// Adapted from the Adding custom PVs to Server here: +// https://mdavidsaver.github.io/pvxs/ioc.html#adding-custom-pvs-to-server + +static void myinitHook(initHookState state) { + if (state != initHookAfterIocBuilt) { + return; + } + + // Must provide a data type for the mailbox. + // Use pre-canned definition of scalar with meta-data + pvxs::Value initial = + pvxs::nt::NTScalar{pvxs::TypeCode::UInt32, true}.create(); + + // (optional) Provide an initial value + initial["value"] = 42u; + initial["alarm.severity"] = 0; + initial["alarm.status"] = 0; + initial["alarm.message"] = ""; + initial["display.description"] = "My PV description"; + + pvxs::server::SharedPV mypv(pvxs::server::SharedPV::buildMailbox()); + mypv.open(initial); + + pvxs::ioc::server().addPV("my:pv:name", mypv); +} + +static void pvxs_ioc_registrar() { initHookRegister(&myinitHook); } + +extern "C" { +epicsExportRegistrar(pvxs_ioc_registrar); +} diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/registrar.dbd b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/registrar.dbd new file mode 100644 index 00000000..12834046 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/registrar.dbd @@ -0,0 +1 @@ +registrar(pvxs_ioc_registrar) diff --git a/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/simpleMain.cpp b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/simpleMain.cpp new file mode 100644 index 00000000..e4e5e3b2 --- /dev/null +++ b/ioc/tests/support/pvxs/ioc/pvxsIocTestTop/simpleApp/src/simpleMain.cpp @@ -0,0 +1,23 @@ +/* simpleMain.cpp */ +/* Author: Marty Kraimer Date: 17MAR2000 */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +} From 50862112dbceb9359ed6f18d7a1f4b95fe07d484 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 2 Feb 2024 16:00:56 +0100 Subject: [PATCH 21/74] ioc/tests/pvxs: add test for PVXS as standalone server --- ioc/tests/default.nix | 1 + .../pvxs/standalone-server/default.nix | 90 +++++++++++++++++++ .../pvxsStandaloneServerTestTop/.gitignore | 29 ++++++ .../pvxsStandaloneServerTestTop/Makefile | 10 +++ .../configure/CONFIG | 45 ++++++++++ .../configure/CONFIG_SITE | 43 +++++++++ .../configure/Makefile | 8 ++ .../configure/RELEASE | 42 +++++++++ .../configure/RULES | 6 ++ .../configure/RULES.ioc | 2 + .../configure/RULES_DIRS | 2 + .../configure/RULES_TOP | 3 + .../pvxsStandaloneServerTestTop/epnix.nix | 8 ++ .../pvxsStandaloneServerTestTop/src/Makefile | 21 +++++ .../src/mailboxServer.cpp | 90 +++++++++++++++++++ 15 files changed, 400 insertions(+) create mode 100644 ioc/tests/support/pvxs/standalone-server/default.nix create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/.gitignore create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/Makefile create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG_SITE create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/Makefile create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RELEASE create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES.ioc create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_DIRS create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_TOP create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/epnix.nix create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/Makefile create mode 100644 ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/mailboxServer.cpp diff --git a/ioc/tests/default.nix b/ioc/tests/default.nix index 06dcd62e..edad9b91 100644 --- a/ioc/tests/default.nix +++ b/ioc/tests/default.nix @@ -6,6 +6,7 @@ with pkgs.lib; support-autosave-simple = import ./support/autosave/simple args; support-pvxs-ioc = import ./support/pvxs/ioc args; + support-pvxs-standalone-server = import ./support/pvxs/standalone-server args; support-seq-simple = import ./support/seq/simple args; support-StreamDevice-simple = import ./support/StreamDevice/simple args; } diff --git a/ioc/tests/support/pvxs/standalone-server/default.nix b/ioc/tests/support/pvxs/standalone-server/default.nix new file mode 100644 index 00000000..5878fde0 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/default.nix @@ -0,0 +1,90 @@ +{pkgs, ...}: let + inherit (pkgs) epnixLib; + inherit (pkgs.stdenv.hostPlatform) system; + + result = epnixLib.evalEpnixModules { + nixpkgsConfig.system = system; + epnixConfig.imports = [./pvxsStandaloneServerTestTop/epnix.nix]; + }; + + ioc = result.outputs.build; +in + pkgs.nixosTest { + name = "support-pvxs-standalone-server"; + meta.maintainers = with epnixLib.maintainers; [minijackson]; + + nodes = { + client = { + environment.systemPackages = [ + pkgs.epnix.epics-base + pkgs.epnix.support.pvxs + ]; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + ioc = { + systemd.services.ioc = { + wantedBy = ["multi-user.target"]; + wants = ["network-online.target"]; + after = ["network-online.target"]; + + description = "EPICS PVXS standalone IOC server"; + + serviceConfig = { + ExecStart = "${ioc}/bin/mailboxServer"; + Restart = "always"; + }; + }; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + }; + + testScript = '' + import json + + start_all() + + addr_list = "EPICS_PVA_ADDR_LIST=192.168.1.2" + + def pvget(name: str): + return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + + def pvxget(name: str): + output = client.succeed(f"{addr_list} pvxget {name}") + return output.splitlines()[1].split()[-1] + + def _pvput(utility: str, name: str, value: str): + client.succeed(f"{addr_list} {utility} {name} {value}") + + def pvput(name: str, value: str): + _pvput("pvput", name, value) + + def pvxput(name: str, value: str): + _pvput("pvxput", name, value) + + with subtest("wait until IOC starts"): + ioc.wait_for_unit("ioc.service") + client.wait_until_succeeds(f"{addr_list} pvget my:pv:name", timeout=60) + + with subtest("PV has the correct value"): + value = pvget("my:pv:name") + assert value["value"] == 42 + assert value["display"]["description"] == "My PV description" + + with subtest("PV can be set"): + pvput("my:pv:name", "1337") + # PV is clipped + assert pvget("my:pv:name")["value"] == 100 + + with subtest("PVXS command-line utilities work"): + assert pvxget("my:pv:name") == "100" + pvxput("my:pv:name", "42") + assert pvxget("my:pv:name") == "42" + client.succeed(f"{addr_list} pvxinfo my:pv:name") + ''; + + passthru = { + inherit ioc; + }; + } diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/.gitignore b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/.gitignore new file mode 100644 index 00000000..3d648caa --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/.gitignore @@ -0,0 +1,29 @@ +# Install directories +/bin/ +/cfg/ +/db/ +/dbd/ +/html/ +/include/ +/lib/ +/templates/ + +# Local configuration files +/configure/*.local + +# iocBoot generated files +/iocBoot/*ioc*/cdCommands +/iocBoot/*ioc*/dllPath.bat +/iocBoot/*ioc*/envPaths +/iocBoot/*ioc*/relPaths.sh + +# Build directories +O.*/ + +# Common files created by other tools +/QtC-* +/.vscode/ +*.orig +*.log +.*.swp +.DS_Store diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/Makefile b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/Makefile new file mode 100644 index 00000000..d8c7ad5c --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/Makefile @@ -0,0 +1,10 @@ +# Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG + +DIRS += configure +DIRS += src + +src_DEPEND_DIRS += configure + +include $(TOP)/configure/RULES_TOP diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG new file mode 100644 index 00000000..34ace577 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG @@ -0,0 +1,45 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + -include $(TOP)/configure/RELEASE.Common.$(T_A) + -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +# Check EPICS_BASE is set properly +ifneq (file,$(origin EPICS_BASE)) + $(error EPICS_BASE must be set in a configure/RELEASE file) +else + ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),) + $(error EPICS_BASE does not point to an EPICS installation) + endif +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain local build configuration settings +include $(TOP)/configure/CONFIG_SITE + +# Host-arch specific settings +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + # Target-arch specific settings + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + + # Host & target specific settings + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG_SITE b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG_SITE new file mode 100644 index 00000000..212485eb --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/CONFIG_SITE @@ -0,0 +1,43 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building even if conflicts are found. +CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when the IOC and build host use different paths +# to the install location. This may be needed to boot from +# a Microsoft FTP server say, or on some NFS configurations. +#IOCS_APPL_TOP = + +# For application debugging purposes, override the HOST_OPT and/ +# or CROSS_OPT settings from base/configure/CONFIG_SITE +#HOST_OPT = NO +#CROSS_OPT = NO + +# These allow developers to override the CONFIG_SITE variable +# settings without having to modify the configure/CONFIG_SITE +# file itself. +-include $(TOP)/../CONFIG_SITE.local +-include $(TOP)/configure/CONFIG_SITE.local + diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/Makefile b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/Makefile new file mode 100644 index 00000000..92543094 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RELEASE b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RELEASE new file mode 100644 index 00000000..d3866518 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RELEASE @@ -0,0 +1,42 @@ +# RELEASE - Location of external support modules +# +# IF YOU CHANGE ANY PATHS in this file or make API changes to +# any modules it refers to, you should do a "make rebuild" in +# this application's top level directory. +# +# The EPICS build process does not check dependencies against +# any files from outside the application, so it is safest to +# rebuild it completely if any modules it depends on change. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file is parsed by both GNUmake and an EPICS Perl script, +# so it may ONLY contain definititions of paths to other support +# modules, variable definitions that are used in module paths, +# and include statements that pull in other RELEASE files. +# Variables may be used before their values have been set. +# Build variables that are NOT used in paths should be set in +# the CONFIG_SITE file. + +# Variables and paths to dependent modules: +#MODULES = /path/to/modules +#MYMODULE = $(MODULES)/my-module + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ = $(MODULES)/seq-ver + +# EPICS_BASE should appear last so earlier modules can override stuff: +EPICS_BASE = /nix/store/9g8q47p14l33kbcz7agz8nz914ghmnzq-epics-base-7.0.7 + +# Set RULES here if you want to use build rules from somewhere +# other than EPICS_BASE: +#RULES = $(MODULES)/build-rules + +# These lines allow developers to override these RELEASE settings +# without having to modify this file directly. +-include $(TOP)/../RELEASE.local +-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local +-include $(TOP)/configure/RELEASE.local diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES new file mode 100644 index 00000000..6d56e14e --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES.ioc b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES.ioc new file mode 100644 index 00000000..901987c6 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_DIRS b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_DIRS new file mode 100644 index 00000000..3ba269dc --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_TOP b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_TOP new file mode 100644 index 00000000..d09d668d --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/epnix.nix b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/epnix.nix new file mode 100644 index 00000000..6b8a90dd --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/epnix.nix @@ -0,0 +1,8 @@ +{pkgs, ...}: { + epnix = { + meta.name = "checks-support-pvxs-standalone-server"; + buildConfig.src = ./.; + + support.modules = with pkgs.epnix.support; [pvxs]; + }; +} diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/Makefile b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/Makefile new file mode 100644 index 00000000..f597a1ee --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/Makefile @@ -0,0 +1,21 @@ +TOP=.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#============================= +# Build the IOC application + +PROD_IOC = mailboxServer + +mailboxServer_LIBS += pvxsIoc pvxs Com +mailboxServer_SRCS += mailboxServer.cpp + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/mailboxServer.cpp b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/mailboxServer.cpp new file mode 100644 index 00000000..f070cdc7 --- /dev/null +++ b/ioc/tests/support/pvxs/standalone-server/pvxsStandaloneServerTestTop/src/mailboxServer.cpp @@ -0,0 +1,90 @@ +#include + +#include + +#include +#include +#include +#include + +using namespace pvxs; + +// Adapted from the Mailbox Server example here: +// https://mdavidsaver.github.io/pvxs/example.html#mailbox-server + +int main() { + // Read $PVXS_LOG from process environment and update + // logging configuration. eg. + // export PVXS_LOG=*=DEBUG + // makes a lot of noise. + logger_config_env(); + + // Must provide a data type for the mailbox. + // Use pre-canned definition of scalar with meta-data + Value initial = nt::NTScalar{TypeCode::Float64, true}.create(); + + // (optional) Provide an initial value + initial["value"] = 42.0; + initial["alarm.severity"] = 0; + initial["alarm.status"] = 0; + initial["alarm.message"] = ""; + initial["display.description"] = "My PV description"; + + // Actually creating a mailbox PV. + // buildMailbox() installs a default onPut() handler which + // stores whatever a client sends (subject to our data type). + server::SharedPV pv(server::SharedPV::buildMailbox()); + + // (optional) Replace the default PUT handler to do a range check + pv.onPut([](server::SharedPV &pv, std::unique_ptr &&op, + Value &&top) { + // arbitrarily clip value to [-100.0, 100.0] + double val(top["value"].as()); + if (val < -100.0) { + top["value"] = -100.0; + } else if (val > 100.0) { + top["value"] = 100.0; + } + + // Provide a timestamp if the client has not (common) + Value ts(top["timeStamp"]); + if (!ts.isMarked(true, true)) { + // use current time + epicsTimeStamp now; + if (!epicsTimeGetCurrent(&now)) { + ts["secondsPastEpoch"] = now.secPastEpoch + POSIX_TIME_AT_EPICS_EPOCH; + ts["nanoseconds"] = now.nsec; + } + } + + // update the SharedPV cache and send + // a update to any subscribers + pv.post(top); + + // Required. Inform client that PUT operation is complete. + op->reply(); + }); + + // Associate a data type (and maybe initial value) with this PV + pv.open(initial); + + // Build server which will serve this PV + // Configure using process environment. + auto serv(server::Server::fromEnv()); + + serv.addPV("my:pv:name", pv); + + // (optional) Print the configuration this server is using + // with any auto-address list expanded. + std::cout << "Effective config\n" << serv.config(); + + std::cout << "Running\n"; + + // Start server and run forever, or until Ctrl+c is pressed. + // Returns on SIGINT or SIGTERM + serv.run(); + + std::cout << "Done\n"; + + return 0; +} From c79680de485dfb63c3e71a3589dffe128db77b33 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 2 Feb 2024 18:46:40 +0100 Subject: [PATCH 22/74] ioc/tests/pvxs: test PVXS' QSRV2 --- ioc/tests/default.nix | 1 + ioc/tests/support/pvxs/qsrv2/default.nix | 100 ++++++++++++++++++ .../pvxs/qsrv2/pvxsQsrv2TestTop/.gitignore | 29 +++++ .../pvxs/qsrv2/pvxsQsrv2TestTop/Makefile | 31 ++++++ .../qsrv2/pvxsQsrv2TestTop/configure/CONFIG | 45 ++++++++ .../pvxsQsrv2TestTop/configure/CONFIG_SITE | 43 ++++++++ .../qsrv2/pvxsQsrv2TestTop/configure/Makefile | 8 ++ .../qsrv2/pvxsQsrv2TestTop/configure/RELEASE | 42 ++++++++ .../qsrv2/pvxsQsrv2TestTop/configure/RULES | 6 ++ .../pvxsQsrv2TestTop/configure/RULES.ioc | 2 + .../pvxsQsrv2TestTop/configure/RULES_DIRS | 2 + .../pvxsQsrv2TestTop/configure/RULES_TOP | 3 + .../pvxs/qsrv2/pvxsQsrv2TestTop/epnix.nix | 13 +++ .../qsrv2/pvxsQsrv2TestTop/iocBoot/Makefile | 6 ++ .../iocBoot/iocSimple/Makefile | 5 + .../pvxsQsrv2TestTop/iocBoot/iocSimple/st.cmd | 18 ++++ .../pvxsQsrv2TestTop/simpleApp/Db/Makefile | 18 ++++ .../pvxsQsrv2TestTop/simpleApp/Db/simple.db | 17 +++ .../qsrv2/pvxsQsrv2TestTop/simpleApp/Makefile | 14 +++ .../pvxsQsrv2TestTop/simpleApp/src/Makefile | 39 +++++++ .../simpleApp/src/simpleMain.cpp | 23 ++++ 21 files changed, 465 insertions(+) create mode 100644 ioc/tests/support/pvxs/qsrv2/default.nix create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/.gitignore create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG_SITE create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RELEASE create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES.ioc create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_DIRS create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_TOP create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/epnix.nix create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/Makefile create mode 100755 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/st.cmd create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/simple.db create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/Makefile create mode 100644 ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/simpleMain.cpp diff --git a/ioc/tests/default.nix b/ioc/tests/default.nix index edad9b91..7f7d020e 100644 --- a/ioc/tests/default.nix +++ b/ioc/tests/default.nix @@ -6,6 +6,7 @@ with pkgs.lib; support-autosave-simple = import ./support/autosave/simple args; support-pvxs-ioc = import ./support/pvxs/ioc args; + support-pvxs-qsrv2 = import ./support/pvxs/qsrv2 args; support-pvxs-standalone-server = import ./support/pvxs/standalone-server args; support-seq-simple = import ./support/seq/simple args; support-StreamDevice-simple = import ./support/StreamDevice/simple args; diff --git a/ioc/tests/support/pvxs/qsrv2/default.nix b/ioc/tests/support/pvxs/qsrv2/default.nix new file mode 100644 index 00000000..732c8678 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/default.nix @@ -0,0 +1,100 @@ +{pkgs, ...}: let + inherit (pkgs) epnixLib; + inherit (pkgs.stdenv.hostPlatform) system; + + result = epnixLib.evalEpnixModules { + nixpkgsConfig.system = system; + epnixConfig.imports = [./pvxsQsrv2TestTop/epnix.nix]; + }; + + service = result.config.epnix.nixos.services.ioc.config; + + ioc = result.outputs.build; +in + pkgs.nixosTest { + name = "support-pvxs-standalone-server"; + meta.maintainers = with epnixLib.maintainers; [minijackson]; + + nodes = { + client = { + environment.systemPackages = [ + pkgs.epnix.epics-base + pkgs.epnix.support.pvxs + ]; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + ioc = { + systemd.services.ioc = service; + networking.firewall.allowedTCPPorts = [5075]; + networking.firewall.allowedUDPPorts = [5076]; + }; + }; + + testScript = '' + import json + + start_all() + + addr_list = "EPICS_PVA_ADDR_LIST=192.168.1.2" + p = "PVXS:QSRV2:" + + def pvget(name: str): + return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + + def pvxget(name: str): + output = client.succeed(f"{addr_list} pvxget {name}") + return output.splitlines()[1].split()[-1] + + def _pvput(utility: str, name: str, value: str): + client.succeed(f"{addr_list} {utility} {name} {value}") + + def pvput(name: str, value: str): + _pvput("pvput", name, value) + + def pvxput(name: str, value: str): + _pvput("pvxput", name, value) + + with subtest("wait until IOC starts"): + ioc.wait_for_unit("ioc.service") + client.wait_until_succeeds(f"{addr_list} pvget {p}ai", timeout=60) + + with subtest("Check initial data"): + # JSON seems broken here? + #value = pvget(f"{p}ai") + #assert value["value"] == 42 + #assert value["display"]["description"] == "An ai" + + value = pvget(f"{p}stringin") + assert value["value"] == "hello" + assert value["display"]["description"] == "An stringin" + + value = pvget(f"{p}waveform") + assert value["value"] == "" + assert value["display"]["description"] == "An waveform" + + with subtest("PVs can be set"): + #pvput(f"{p}ai", "1337") + #assert pvget("{p}ai")["value"] == 1337 + + pvput(f"{p}stringin", "world") + assert pvget(f"{p}stringin")["value"] == "world" + + pvput(f"{p}waveform", '"some long text"') + assert pvget(f"{p}waveform")["value"] == "some long text" + + with subtest("PVXS command-line utilities work"): + # assert pvxget(f"{p}ai") == "1337" + assert pvxget(f"{p}ai") == "42" + pvxput(f"{p}ai", "153") + assert pvxget(f"{p}ai") == "153" + + pvxput(f"{p}waveform", "something") + assert pvxget(f"{p}waveform") == '"something"' + print(client.succeed(f"{addr_list} pvxinfo {p}waveform")) + ''; + + passthru = { + inherit ioc; + }; + } diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/.gitignore b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/.gitignore new file mode 100644 index 00000000..3d648caa --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/.gitignore @@ -0,0 +1,29 @@ +# Install directories +/bin/ +/cfg/ +/db/ +/dbd/ +/html/ +/include/ +/lib/ +/templates/ + +# Local configuration files +/configure/*.local + +# iocBoot generated files +/iocBoot/*ioc*/cdCommands +/iocBoot/*ioc*/dllPath.bat +/iocBoot/*ioc*/envPaths +/iocBoot/*ioc*/relPaths.sh + +# Build directories +O.*/ + +# Common files created by other tools +/QtC-* +/.vscode/ +*.orig +*.log +.*.swp +.DS_Store diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/Makefile new file mode 100644 index 00000000..19c9068d --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/Makefile @@ -0,0 +1,31 @@ +# Makefile at top of application tree +TOP = . +include $(TOP)/configure/CONFIG + +# Directories to build, any order +DIRS += configure +DIRS += $(wildcard *Sup) +DIRS += $(wildcard *App) +DIRS += $(wildcard *Top) +DIRS += $(wildcard iocBoot) + +# The build order is controlled by these dependency rules: + +# All dirs except configure depend on configure +$(foreach dir, $(filter-out configure, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += configure)) + +# Any *App dirs depend on all *Sup dirs +$(foreach dir, $(filter %App, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup, $(DIRS)))) + +# Any *Top dirs depend on all *Sup and *App dirs +$(foreach dir, $(filter %Top, $(DIRS)), \ + $(eval $(dir)_DEPEND_DIRS += $(filter %Sup %App, $(DIRS)))) + +# iocBoot depends on all *App dirs +iocBoot_DEPEND_DIRS += $(filter %App,$(DIRS)) + +# Add any additional dependency rules here: + +include $(TOP)/configure/RULES_TOP diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG new file mode 100644 index 00000000..34ace577 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG @@ -0,0 +1,45 @@ +# CONFIG - Load build configuration data +# +# Do not make changes to this file! + +# Allow user to override where the build rules come from +RULES = $(EPICS_BASE) + +# RELEASE files point to other application tops +include $(TOP)/configure/RELEASE +-include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + -include $(TOP)/configure/RELEASE.Common.$(T_A) + -include $(TOP)/configure/RELEASE.$(EPICS_HOST_ARCH).$(T_A) +endif + +# Check EPICS_BASE is set properly +ifneq (file,$(origin EPICS_BASE)) + $(error EPICS_BASE must be set in a configure/RELEASE file) +else + ifeq ($(wildcard $(EPICS_BASE)/configure/CONFIG_BASE),) + $(error EPICS_BASE does not point to an EPICS installation) + endif +endif + +CONFIG = $(RULES)/configure +include $(CONFIG)/CONFIG + +# Override the Base definition: +INSTALL_LOCATION = $(TOP) + +# CONFIG_SITE files contain local build configuration settings +include $(TOP)/configure/CONFIG_SITE + +# Host-arch specific settings +-include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).Common + +ifdef T_A + # Target-arch specific settings + -include $(TOP)/configure/CONFIG_SITE.Common.$(T_A) + + # Host & target specific settings + -include $(TOP)/configure/CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) +endif + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG_SITE b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG_SITE new file mode 100644 index 00000000..212485eb --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/CONFIG_SITE @@ -0,0 +1,43 @@ +# CONFIG_SITE + +# Make any application-specific changes to the EPICS build +# configuration variables in this file. +# +# Host/target specific settings can be specified in files named +# CONFIG_SITE.$(EPICS_HOST_ARCH).Common +# CONFIG_SITE.Common.$(T_A) +# CONFIG_SITE.$(EPICS_HOST_ARCH).$(T_A) + +# CHECK_RELEASE controls the consistency checking of the support +# applications pointed to by the RELEASE* files. +# Normally CHECK_RELEASE should be set to YES. +# Set CHECK_RELEASE to NO to disable checking completely. +# Set CHECK_RELEASE to WARN to perform consistency checking but +# continue building even if conflicts are found. +CHECK_RELEASE = YES + +# Set this when you only want to compile this application +# for a subset of the cross-compiled target architectures +# that Base is built for. +#CROSS_COMPILER_TARGET_ARCHS = vxWorks-ppc32 + +# To install files into a location other than $(TOP) define +# INSTALL_LOCATION here. +#INSTALL_LOCATION= + +# Set this when the IOC and build host use different paths +# to the install location. This may be needed to boot from +# a Microsoft FTP server say, or on some NFS configurations. +#IOCS_APPL_TOP = + +# For application debugging purposes, override the HOST_OPT and/ +# or CROSS_OPT settings from base/configure/CONFIG_SITE +#HOST_OPT = NO +#CROSS_OPT = NO + +# These allow developers to override the CONFIG_SITE variable +# settings without having to modify the configure/CONFIG_SITE +# file itself. +-include $(TOP)/../CONFIG_SITE.local +-include $(TOP)/configure/CONFIG_SITE.local + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/Makefile new file mode 100644 index 00000000..92543094 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/Makefile @@ -0,0 +1,8 @@ +TOP=.. + +include $(TOP)/configure/CONFIG + +TARGETS = $(CONFIG_TARGETS) +CONFIGS += $(subst ../,,$(wildcard $(CONFIG_INSTALLS))) + +include $(TOP)/configure/RULES diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RELEASE b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RELEASE new file mode 100644 index 00000000..d0bb2b14 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RELEASE @@ -0,0 +1,42 @@ +# RELEASE - Location of external support modules +# +# IF YOU CHANGE ANY PATHS in this file or make API changes to +# any modules it refers to, you should do a "make rebuild" in +# this application's top level directory. +# +# The EPICS build process does not check dependencies against +# any files from outside the application, so it is safest to +# rebuild it completely if any modules it depends on change. +# +# Host- or target-specific settings can be given in files named +# RELEASE.$(EPICS_HOST_ARCH).Common +# RELEASE.Common.$(T_A) +# RELEASE.$(EPICS_HOST_ARCH).$(T_A) +# +# This file is parsed by both GNUmake and an EPICS Perl script, +# so it may ONLY contain definititions of paths to other support +# modules, variable definitions that are used in module paths, +# and include statements that pull in other RELEASE files. +# Variables may be used before their values have been set. +# Build variables that are NOT used in paths should be set in +# the CONFIG_SITE file. + +# Variables and paths to dependent modules: +#MODULES = /path/to/modules +#MYMODULE = $(MODULES)/my-module + +# If using the sequencer, point SNCSEQ at its top directory: +#SNCSEQ = $(MODULES)/seq-ver + +# EPICS_BASE should appear last so earlier modules can override stuff: +EPICS_BASE = /nix/store/07lczf4kwn5mpnyp9rnn3hn6qfghykxm-epics-base-7.0.7 + +# Set RULES here if you want to use build rules from somewhere +# other than EPICS_BASE: +#RULES = $(MODULES)/build-rules + +# These lines allow developers to override these RELEASE settings +# without having to modify this file directly. +-include $(TOP)/../RELEASE.local +-include $(TOP)/../RELEASE.$(EPICS_HOST_ARCH).local +-include $(TOP)/configure/RELEASE.local diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES new file mode 100644 index 00000000..6d56e14e --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES @@ -0,0 +1,6 @@ +# RULES + +include $(CONFIG)/RULES + +# Library should be rebuilt because LIBOBJS may have changed. +$(LIBNAME): ../Makefile diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES.ioc b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES.ioc new file mode 100644 index 00000000..901987c6 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES.ioc @@ -0,0 +1,2 @@ +#RULES.ioc +include $(CONFIG)/RULES.ioc diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_DIRS b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_DIRS new file mode 100644 index 00000000..3ba269dc --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_DIRS @@ -0,0 +1,2 @@ +#RULES_DIRS +include $(CONFIG)/RULES_DIRS diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_TOP b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_TOP new file mode 100644 index 00000000..d09d668d --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/configure/RULES_TOP @@ -0,0 +1,3 @@ +#RULES_TOP +include $(CONFIG)/RULES_TOP + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/epnix.nix b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/epnix.nix new file mode 100644 index 00000000..d18fde61 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/epnix.nix @@ -0,0 +1,13 @@ +{pkgs, ...}: { + epnix = { + meta.name = "checks-support-pvxs-qsrv2"; + buildConfig.src = ./.; + + support.modules = with pkgs.epnix.support; [pvxs]; + + nixos.services.ioc = { + app = "simple"; + ioc = "iocSimple"; + }; + }; +} diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/Makefile new file mode 100644 index 00000000..91e47d0b --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/Makefile @@ -0,0 +1,6 @@ +TOP = .. +include $(TOP)/configure/CONFIG +DIRS += $(wildcard *ioc*) +DIRS += $(wildcard as*) +include $(CONFIG)/RULES_DIRS + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/Makefile new file mode 100644 index 00000000..e1b9aa4a --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/Makefile @@ -0,0 +1,5 @@ +TOP = ../.. +include $(TOP)/configure/CONFIG +ARCH = $(EPICS_HOST_ARCH) +TARGETS = envPaths +include $(TOP)/configure/RULES.ioc diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/st.cmd b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/st.cmd new file mode 100755 index 00000000..0e815ba4 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/iocBoot/iocSimple/st.cmd @@ -0,0 +1,18 @@ +#!../../bin/linux-x86_64/simple + +#- You may have to change simple to something else +#- everywhere it appears in this file + +< envPaths + +## Register all support components +dbLoadDatabase "../../dbd/simple.dbd" +simple_registerRecordDeviceDriver(pdbbase) + +## Load record instances +dbLoadRecords("${TOP}/db/simple.db", "P=PVXS:QSRV2:") + +iocInit() + +## Start any sequence programs +#seq sncsimple,"user=minijackson" diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/Makefile new file mode 100644 index 00000000..ea495989 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/Makefile @@ -0,0 +1,18 @@ +TOP=../.. +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE + +#---------------------------------------------------- +# Create and install (or just install) into /db +# databases, templates, substitutions like this +DB += simple.db + +#---------------------------------------------------- +# If .db template is not named *.template add +# _template = + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/simple.db b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/simple.db new file mode 100644 index 00000000..f9c7bc1e --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Db/simple.db @@ -0,0 +1,17 @@ +record(ai, "${P}ai") { + field(DESC, "An ai") + field(VAL, "42") + info(Q:form, "Hex") # hint to clients to render as hexadecimal +} + +record(stringin, "${P}stringin") { + field(DESC, "An stringin") + field(VAL, "hello") +} + +record(waveform, "${P}waveform") { + field(DESC, "An waveform") + field(FTVL, "CHAR") + field(NELM, 1024) + info(Q:form, "String") # hint to QSRV to expose char[] as string +} diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Makefile new file mode 100644 index 00000000..60ab8ae8 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/Makefile @@ -0,0 +1,14 @@ +# Makefile at top of application tree +TOP = .. +include $(TOP)/configure/CONFIG + +# Directories to be built, in any order. +# You can replace these wildcards with an explicit list +DIRS += $(wildcard src* *Src*) +DIRS += $(wildcard db* *Db*) + +# If the build order matters, add dependency rules like this, +# which specifies that xxxSrc must be built after src: +#xxxSrc_DEPEND_DIRS += src + +include $(TOP)/configure/RULES_DIRS diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/Makefile b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/Makefile new file mode 100644 index 00000000..766932f1 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/Makefile @@ -0,0 +1,39 @@ +TOP=../.. + +include $(TOP)/configure/CONFIG +#---------------------------------------- +# ADD MACRO DEFINITIONS AFTER THIS LINE +#============================= + +#============================= +# Build the IOC application + +PROD_IOC = simple +# simple.dbd will be created and installed +DBD += simple.dbd + +# simple.dbd will be made up from these files: +simple_DBD += base.dbd + +# Include dbd files from all support applications: +simple_DBD += pvxsIoc.dbd + +# Add all the support libraries needed by this IOC +simple_LIBS += pvxsIoc pvxs + +# simple_registerRecordDeviceDriver.cpp derives from simple.dbd +simple_SRCS += simple_registerRecordDeviceDriver.cpp + +# Build the main IOC entry point on workstation OSs. +simple_SRCS_DEFAULT += simpleMain.cpp +simple_SRCS_vxWorks += -nil- + +# Finally link to the EPICS Base libraries +simple_LIBS += $(EPICS_BASE_IOC_LIBS) + +#=========================== + +include $(TOP)/configure/RULES +#---------------------------------------- +# ADD RULES AFTER THIS LINE + diff --git a/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/simpleMain.cpp b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/simpleMain.cpp new file mode 100644 index 00000000..e4e5e3b2 --- /dev/null +++ b/ioc/tests/support/pvxs/qsrv2/pvxsQsrv2TestTop/simpleApp/src/simpleMain.cpp @@ -0,0 +1,23 @@ +/* simpleMain.cpp */ +/* Author: Marty Kraimer Date: 17MAR2000 */ + +#include +#include +#include +#include +#include + +#include "epicsExit.h" +#include "epicsThread.h" +#include "iocsh.h" + +int main(int argc,char *argv[]) +{ + if(argc>=2) { + iocsh(argv[1]); + epicsThreadSleep(.2); + } + iocsh(NULL); + epicsExit(0); + return(0); +} From e9f973e197eae5ddc7c723d993dcb5522432c0d4 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 1 Feb 2024 16:23:10 +0100 Subject: [PATCH 23/74] epics-base: 7.0.7 -> 7.0.8 --- pkgs/default.nix | 4 ++-- pkgs/epnix/epics-base/default.nix | 18 +++++------------- 2 files changed, 7 insertions(+), 15 deletions(-) diff --git a/pkgs/default.nix b/pkgs/default.nix index a56a169f..54a8b087 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -13,8 +13,8 @@ in # EPICS base epics-base7 = callPackage ./epnix/epics-base { - version = "7.0.7"; - hash = "sha256-VMiuwTuPykoMLcIphUAsjtLQZ8HLKr3LvGpje3lsIXc="; + version = "7.0.8"; + hash = "sha256-GEkUwlOkRhQ6LskxHV+eDvBe9UUzF2YWWmgiyuiHypM="; }; epics-base3 = callPackage ./epnix/epics-base { version = "3.15.9"; diff --git a/pkgs/epnix/epics-base/default.nix b/pkgs/epnix/epics-base/default.nix index 770de2ed..58524070 100644 --- a/pkgs/epnix/epics-base/default.nix +++ b/pkgs/epnix/epics-base/default.nix @@ -37,19 +37,11 @@ in inherit hash; }; - patches = - (optionals (atLeast "7.0.0") [ - # From: https://github.com/epics-base/epics-base/pull/395 - (fetchpatch { - url = "https://github.com/epics-base/epics-base/commit/d87fd0db0124faf450cff93226ae6a2cc02f02bf.patch"; - hash = "sha256-BQWFOPCfRjSowDSAbqe8ClqEWT1OtfbgRh4k5jmAjpU="; - }) - ]) - ++ (optionals (older "7.0.5") [ - # Support "undefine MYVAR" in convertRelease.pl - # Fixed by commit 79d7ac931502e1c25b247a43b7c4454353ac13a6 - ./handle-make-undefine-variable.patch - ]); + patches = optionals (older "7.0.5") [ + # Support "undefine MYVAR" in convertRelease.pl + # Fixed by commit 79d7ac931502e1c25b247a43b7c4454353ac13a6 + ./handle-make-undefine-variable.patch + ]; # "build" as in Nix terminology (the build machine) build_config_site = From 738179026fbc918c1fb13014ec77089ff976c7e4 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Wed, 7 Feb 2024 14:18:28 +0100 Subject: [PATCH 24/74] ioc/tests/pvxs: fix tests with epics-base 7.0.8 epics-base 7.0.8 changed the output of 'pvget my:pv -M json' from standard JSON to JSON5. see https://epics.anl.gov/core-talk/2024/msg00023.php --- ioc/tests/support/pvxs/ioc/default.nix | 8 ++++++-- ioc/tests/support/pvxs/qsrv2/default.nix | 15 +++++++++------ .../support/pvxs/standalone-server/default.nix | 8 ++++++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/ioc/tests/support/pvxs/ioc/default.nix b/ioc/tests/support/pvxs/ioc/default.nix index 242ef9b5..87a21b2e 100644 --- a/ioc/tests/support/pvxs/ioc/default.nix +++ b/ioc/tests/support/pvxs/ioc/default.nix @@ -31,15 +31,19 @@ in }; }; + extraPythonPackages = p: [p.json5]; + # Type checking on extra packages doesn't work yet + skipTypeCheck = true; + testScript = '' - import json + import json5 start_all() addr_list = "EPICS_PVA_ADDR_LIST=192.168.1.2" def pvget(name: str): - return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + return json5.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) def pvxget(name: str): output = client.succeed(f"{addr_list} pvxget {name}") diff --git a/ioc/tests/support/pvxs/qsrv2/default.nix b/ioc/tests/support/pvxs/qsrv2/default.nix index 732c8678..2738a818 100644 --- a/ioc/tests/support/pvxs/qsrv2/default.nix +++ b/ioc/tests/support/pvxs/qsrv2/default.nix @@ -31,8 +31,12 @@ in }; }; + extraPythonPackages = p: [p.json5]; + # Type checking on extra packages doesn't work yet + skipTypeCheck = true; + testScript = '' - import json + import json5 start_all() @@ -40,7 +44,7 @@ in p = "PVXS:QSRV2:" def pvget(name: str): - return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + return json5.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) def pvxget(name: str): output = client.succeed(f"{addr_list} pvxget {name}") @@ -60,10 +64,9 @@ in client.wait_until_succeeds(f"{addr_list} pvget {p}ai", timeout=60) with subtest("Check initial data"): - # JSON seems broken here? - #value = pvget(f"{p}ai") - #assert value["value"] == 42 - #assert value["display"]["description"] == "An ai" + value = pvget(f"{p}ai") + assert value["value"] == 42 + assert value["display"]["description"] == "An ai" value = pvget(f"{p}stringin") assert value["value"] == "hello" diff --git a/ioc/tests/support/pvxs/standalone-server/default.nix b/ioc/tests/support/pvxs/standalone-server/default.nix index 5878fde0..c0529854 100644 --- a/ioc/tests/support/pvxs/standalone-server/default.nix +++ b/ioc/tests/support/pvxs/standalone-server/default.nix @@ -40,15 +40,19 @@ in }; }; + extraPythonPackages = p: [p.json5]; + # Type checking on extra packages doesn't work yet + skipTypeCheck = true; + testScript = '' - import json + import json5 start_all() addr_list = "EPICS_PVA_ADDR_LIST=192.168.1.2" def pvget(name: str): - return json.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) + return json5.loads(client.succeed(f"{addr_list} pvget {name} -M json | cut -d' ' -f2-")) def pvxget(name: str): output = client.succeed(f"{addr_list} pvxget {name}") From 6200aff2633814cc4df46aa19fd1877f3bca36f7 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Wed, 7 Feb 2024 14:20:43 +0100 Subject: [PATCH 25/74] ioc/tests/pvxs: fix qsrv2 test name --- ioc/tests/support/pvxs/qsrv2/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ioc/tests/support/pvxs/qsrv2/default.nix b/ioc/tests/support/pvxs/qsrv2/default.nix index 2738a818..5f62cda2 100644 --- a/ioc/tests/support/pvxs/qsrv2/default.nix +++ b/ioc/tests/support/pvxs/qsrv2/default.nix @@ -12,7 +12,7 @@ ioc = result.outputs.build; in pkgs.nixosTest { - name = "support-pvxs-standalone-server"; + name = "support-pvxs-qsrv2"; meta.maintainers = with epnixLib.maintainers; [minijackson]; nodes = { From 41a3be16b6bcf03d89539707373350ce0ee24366 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 13 Feb 2024 13:54:06 +0100 Subject: [PATCH 26/74] nixos/phoebus/alarm-server: don't magically enable Kafka/ElasticSearch now the user must configure Kafka and ElasticSearch themselves --- nixos/modules/phoebus/alarm-logger.nix | 30 +-------- nixos/modules/phoebus/alarm-server.nix | 21 +----- nixos/tests/phoebus/alarm.nix | 92 ++++++++++++++++++++------ 3 files changed, 74 insertions(+), 69 deletions(-) diff --git a/nixos/modules/phoebus/alarm-logger.nix b/nixos/modules/phoebus/alarm-logger.nix index d8e49444..4e81d31d 100644 --- a/nixos/modules/phoebus/alarm-logger.nix +++ b/nixos/modules/phoebus/alarm-logger.nix @@ -4,13 +4,10 @@ lib, pkgs, ... -} @ moduleAttrs: let +}: let cfg = config.services.phoebus-alarm-logger; settingsFormat = pkgs.formats.javaProperties {}; configFile = settingsFormat.generate "phoebus-alarm-logger.properties" cfg.settings; - - localKafka = lib.hasPrefix "localhost:" cfg.settings."bootstrap.servers"; - localElasticsearch = cfg.settings.es_host == "localhost"; in { options.services.phoebus-alarm-logger = { enable = lib.mkEnableOption '' @@ -141,10 +138,6 @@ in { description = "Phoebus Alarm Logger"; wantedBy = ["multi-user.target"]; - after = lib.mkMerge [ - (lib.mkIf localKafka ["apache-kafka.service"]) - (lib.mkIf localElasticsearch ["elasticsearch.service"]) - ]; # Weirdly not "phoebus.user" environment.JAVA_OPTS = "-Djava.util.prefs.userRoot=/var/lib/phoebus-alarm-logger"; @@ -162,29 +155,10 @@ in { }; }; - services.apache-kafka = lib.mkIf localKafka { - enable = true; - localSetup.enable = true; - }; - # Port conflicts by default with phoebus-alarm-logger's port - services.zookeeper.extraConf = lib.mkIf localKafka '' - admin.enableServer=false - ''; - - services.elasticsearch = lib.mkIf localElasticsearch { - enable = true; - # Should be kept in sync with the phoebus-olog and phoebus-save-and-restore services - package = pkgs.elasticsearch7; - }; - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ (lib.toInt cfg.settings."server.port") ]; }; - meta = { - maintainers = with epnixLib.maintainers; [minijackson]; - # TODO: - # doc = ./alarm-logger.md; - }; + meta.maintainers = with epnixLib.maintainers; [minijackson]; } diff --git a/nixos/modules/phoebus/alarm-server.nix b/nixos/modules/phoebus/alarm-server.nix index 9319af53..2345f1a0 100644 --- a/nixos/modules/phoebus/alarm-server.nix +++ b/nixos/modules/phoebus/alarm-server.nix @@ -4,12 +4,10 @@ lib, pkgs, ... -} @ moduleAttrs: let +}: let cfg = config.services.phoebus-alarm-server; settingsFormat = pkgs.formats.javaProperties {}; configFile = settingsFormat.generate "phoebus-alarm-server.properties" cfg.settings; - - localKafka = lib.hasPrefix "localhost:" cfg.settings."org.phoebus.applications.alarm/server"; in { options.services.phoebus-alarm-server = { enable = lib.mkEnableOption '' @@ -34,7 +32,6 @@ in { Includes services: - - Apache Kafka (if configured locally) - Phoebus Alarm Logger (if not disabled) Warning: this opens the firewall on all network interfaces. @@ -168,7 +165,6 @@ in { description = "Phoebus Alarm Server"; wantedBy = ["multi-user.target"]; - after = lib.mkIf localKafka ["apache-kafka.service"]; environment.JAVA_OPTS = "-Dphoebus.user=/var/lib/phoebus-alarm-server"; @@ -191,20 +187,7 @@ in { enable = lib.mkDefault true; openFirewall = lib.mkIf cfg.openFirewall (lib.mkDefault true); }; - - services.apache-kafka = lib.mkIf localKafka { - enable = true; - localSetup.enable = true; - }; - - networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ - config.services.apache-kafka.port - ]; }; - meta = { - maintainers = with epnixLib.maintainers; [minijackson]; - # TODO: - # doc = ./alarm-server.md; - }; + meta.maintainers = with epnixLib.maintainers; [minijackson]; } diff --git a/nixos/tests/phoebus/alarm.nix b/nixos/tests/phoebus/alarm.nix index 60d5d565..4a5840b1 100644 --- a/nixos/tests/phoebus/alarm.nix +++ b/nixos/tests/phoebus/alarm.nix @@ -9,25 +9,11 @@ meta.maintainers = with epnixLib.maintainers; [minijackson]; nodes = { - server = {config, ...}: { - services.phoebus-alarm-server = { - enable = true; - openFirewall = true; - settings = { - "org.phoebus.pv.ca/addr_list" = ["ioc"]; - "org.phoebus.pv.ca/auto_addr_list" = false; - }; + client = { + environment = { + sessionVariables.EPICS_CA_ADDR_LIST = ["ioc"]; + systemPackages = [pkgs.kcat pkgs.epnix.epics-base]; }; - - nixpkgs.config.allowUnfreePredicate = pkg: - builtins.elem (lib.getName pkg) [ - # Elasticsearch can be used as an SSPL-licensed software, which is - # not open-source. But as we're using it run tests, not exposing - # any service, this should be fine. - "elasticsearch" - ]; - - virtualisation.memorySize = 3072; }; ioc = { @@ -44,11 +30,73 @@ }; }; - client = { - environment = { - sessionVariables.EPICS_CA_ADDR_LIST = ["ioc"]; - systemPackages = [pkgs.kcat pkgs.epnix.epics-base]; + server = { + config, + pkgs, + ... + }: let + kafkaPort = toString config.services.apache-kafka.port; + serverAddr = "192.168.1.3"; + kafkaListenSockAddr = "${serverAddr}:${kafkaPort}"; + in { + services.phoebus-alarm-server = { + enable = true; + openFirewall = true; + settings = { + "org.phoebus.pv.ca/addr_list" = ["ioc"]; + "org.phoebus.pv.ca/auto_addr_list" = false; + "org.phoebus.applications.alarm/server" = kafkaListenSockAddr; + }; + }; + + services.phoebus-alarm-logger.settings."bootstrap.servers" = kafkaListenSockAddr; + + services.elasticsearch = { + enable = true; + package = pkgs.elasticsearch7; + }; + + # Single-server Kafka setup + services.apache-kafka = { + enable = true; + logDirs = ["/var/lib/apache-kafka"]; + # Tell Apache Kafka to listen on this IP address + # If you don't have a DNS domain name, it's best to set a specific, non-local IP address. + extraProperties = '' + listeners=PLAINTEXT://${kafkaListenSockAddr} + offsets.topic.replication.factor=1 + transaction.state.log.replication.factor=1 + transaction.state.log.min.isr=1 + ''; }; + + systemd.services.apache-kafka = { + after = ["zookeeper.service"]; + unitConfig.StateDirectory = "apache-kafka"; + }; + + services.zookeeper = { + enable = true; + extraConf = '' + # Port conflicts by default with phoebus-alarm-logger's port + admin.enableServer=false + ''; + }; + + # Open kafka to the outside world + networking.firewall.allowedTCPPorts = [ + config.services.apache-kafka.port + ]; + + nixpkgs.config.allowUnfreePredicate = pkg: + builtins.elem (lib.getName pkg) [ + # Elasticsearch can be used as an SSPL-licensed software, which is + # not open-source. But as we're using it run tests, not exposing + # any service, this should be fine. + "elasticsearch" + ]; + + virtualisation.memorySize = 3072; }; }; From 3324a21328e0045a6f702080b397da15fb8f54ff Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 13 Feb 2024 14:02:27 +0100 Subject: [PATCH 27/74] nixos/tests/phoebus/alarm: improve test reliability test would fail because the the list returned by phoebus-alarm-logger wouldn't be sorted by time, which we assumed was the case. --- nixos/tests/phoebus/alarm.py | 36 ++++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 14 deletions(-) diff --git a/nixos/tests/phoebus/alarm.py b/nixos/tests/phoebus/alarm.py index 5c0c8466..c17125ef 100644 --- a/nixos/tests/phoebus/alarm.py +++ b/nixos/tests/phoebus/alarm.py @@ -4,15 +4,25 @@ start_all() -server.wait_for_unit("apache-kafka.service") -server.wait_for_unit("zookeeper.service") -server.wait_for_unit("phoebus-alarm-server.service") -server.wait_for_unit("phoebus-alarm-logger.service") -server.wait_for_open_port(8080) -ioc.wait_for_unit("ioc.service") +def wait_for_boot(): + with subtest("Machines boot correctly"): + server.wait_for_unit("apache-kafka.service") + server.wait_for_unit("elasticsearch.service") + server.wait_for_unit("phoebus-alarm-server.service") + server.wait_for_unit("phoebus-alarm-logger.service") + server.wait_for_open_port(9092, "192.168.1.3") + server.wait_for_open_port(9200) + server.wait_for_open_port(8080) + + ioc.wait_for_unit("ioc.service") + + client.wait_for_unit("multi-user.target") + + with subtest("Alarm logger is connected to Elasticsearch"): + status = get_logger("/") + assert status["elastic"]["status"] == "Connected" -client.wait_for_unit("multi-user.target") alarm_path = "/Accelerator/ALARM_TEST" alarm_config = f"config:{alarm_path}" @@ -43,9 +53,7 @@ def get_logger(uri: str): # ----- -with subtest("Alarm logger is connected to Elasticsearch"): - status = get_logger("/") - assert status["elastic"]["status"] == "Connected" +wait_for_boot() with subtest("We initialize the PV"): # This is done so that the PV is processed at least once, else the @@ -135,6 +143,7 @@ def logger_has_config(_): def logger_has_latest_state(_): global logger_alarms logger_alarms = get_logger("/search/alarm/pv/ALARM_TEST") + logger_alarms.sort(key=lambda event: event.get("time", ""), reverse=True) return ( logger_alarms[0]["current_severity"] == "OK" and logger_alarms[0]["severity"] == "OK" @@ -165,16 +174,15 @@ def logger_has_latest_state(_): with subtest("The data is still here after a server reboot"): server.shutdown() server.start() - server.wait_for_unit("apache-kafka.service") + + wait_for_boot() alarm = get_alarm() assert alarm["current_severity"] == "OK" assert alarm["severity"] == "OK" - server.wait_for_unit("phoebus-alarm-logger.service") - server.wait_for_open_port(8080) - logger_alarms = get_logger("/search/alarm/pv/ALARM_TEST") + logger_alarms.sort(key=lambda event: event.get("time", ""), reverse=True) alarm_states = [ alarm for alarm in logger_alarms if alarm["config"].startswith("state:") ] From 8a99eee9182682259a11195f7b4b88eb9c1ab010 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 13 Feb 2024 14:06:35 +0100 Subject: [PATCH 28/74] doc/nixos/phoebus-alarm: document how to configure Kafka+ElasticSearch --- doc/nixos/guides/phoebus-alarm.md | 51 +++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 9 deletions(-) diff --git a/doc/nixos/guides/phoebus-alarm.md b/doc/nixos/guides/phoebus-alarm.md index 1b07f19c..47c2ef9d 100644 --- a/doc/nixos/guides/phoebus-alarm.md +++ b/doc/nixos/guides/phoebus-alarm.md @@ -26,9 +26,9 @@ The Phoebus Alarm Logging Service can also be called the Phoebus Alarm Logger. {{< include _pre-requisites.md >}} -# Enabling the Phoebus Alarm services +# Single server Phoebus Alarm setup -To enable the Phoebus Alarm server and the Phoebus Alarm Logger, +To configure Phoebus Alarm, Phoebus Alarm Logger, Apache Kafka, and ElasticSearch on a single server, add this to your configuration: ``` nix @@ -37,20 +37,53 @@ add this to your configuration: # Replace this with your machine's IP address # or DNS domain name ip = "192.168.1.42"; - kafkaSock = "${ip}:${kafkaPort}"; + kafkaListenSockAddr = "${ip}:${kafkaPort}"; in { # The Phoebus Alarm server also automatically enables the Phoebus Alarm Logger services.phoebus-alarm-server = { enable = true; openFirewall = true; - settings."org.phoebus.applications.alarm/server" = "${kafkaSock}"; + settings."org.phoebus.applications.alarm/server" = kafkaListenSockAddr; }; - # Tell Apache Kafka to listen on this IP address - # If you don't have a DNS domain name, it's best to set a specific, non-local IP address. - services.apache-kafka.extraProperties = '' - listeners=PLAINTEXT://${kafkaSock} - ''; + services.phoebus-alarm-logger.settings."bootstrap.servers" = kafkaListenSockAddr; + + services.elasticsearch = { + enable = true; + package = pkgs.elasticsearch7; + }; + + # Single-server Kafka setup + services.apache-kafka = { + enable = true; + logDirs = ["/var/lib/apache-kafka"]; + # Tell Apache Kafka to listen on this IP address + # If you don't have a DNS domain name, it's best to set a specific, non-local IP address. + extraProperties = '' + listeners=PLAINTEXT://${kafkaListenSockAddr} + offsets.topic.replication.factor=1 + transaction.state.log.replication.factor=1 + transaction.state.log.min.isr=1 + ''; + }; + + systemd.services.apache-kafka = { + after = ["zookeeper.service"]; + unitConfig.StateDirectory = "apache-kafka"; + }; + + services.zookeeper = { + enable = true; + extraConf = '' + # Port conflicts by default with phoebus-alarm-logger's port + admin.enableServer=false + ''; + }; + + # Open kafka to the outside world + networking.firewall.allowedTCPPorts = [ + config.services.apache-kafka.port + ]; # Elasticsearch, needed by Phoebus Alarm Logger, is not free software (SSPL | Elastic License). # To accept the license, add the code below: From 4d3c896b461b10b2f94ace626a68e6bdcbc622db Mon Sep 17 00:00:00 2001 From: Minijackson Date: Fri, 8 Mar 2024 13:13:32 +0100 Subject: [PATCH 29/74] nixos/phoebus: remove unused local-kafka module --- nixos/module-list.nix | 1 - nixos/modules/phoebus/local-kafka.nix | 28 --------------------------- 2 files changed, 29 deletions(-) delete mode 100644 nixos/modules/phoebus/local-kafka.nix diff --git a/nixos/module-list.nix b/nixos/module-list.nix index af554d46..52cb3bae 100644 --- a/nixos/module-list.nix +++ b/nixos/module-list.nix @@ -3,7 +3,6 @@ ./modules/ca-gateway.nix ./modules/phoebus/alarm-logger.nix ./modules/phoebus/alarm-server.nix - ./modules/phoebus/local-kafka.nix ./modules/phoebus/olog.nix ./modules/phoebus/save-and-restore.nix ] diff --git a/nixos/modules/phoebus/local-kafka.nix b/nixos/modules/phoebus/local-kafka.nix deleted file mode 100644 index 4c5193df..00000000 --- a/nixos/modules/phoebus/local-kafka.nix +++ /dev/null @@ -1,28 +0,0 @@ -{ - config, - lib, - ... -}: { - # This is put as a separate file, so that both the phoebus-alarm-server and - # phoebus-alarm-service provide the same configuration, if used separately - options.services.apache-kafka.localSetup.enable = lib.mkEnableOption "Configure a local, non-replicated Kafka instance"; - - config = lib.mkIf config.services.apache-kafka.localSetup.enable { - # TODO: document replication setup - services.apache-kafka = { - logDirs = lib.mkDefault ["/var/lib/apache-kafka"]; - extraProperties = '' - offsets.topic.replication.factor=1 - transaction.state.log.replication.factor=1 - transaction.state.log.min.isr=1 - ''; - }; - - systemd.services.apache-kafka = { - after = ["zookeeper.service"]; - unitConfig.StateDirectory = lib.mkDefault "apache-kafka"; - }; - - services.zookeeper.enable = lib.mkDefault true; - }; -} From ef0f4ebaa0c3b9240a79c4f4318af60f6d48d6cc Mon Sep 17 00:00:00 2001 From: Alexis Gaget Date: Tue, 19 Mar 2024 17:40:30 +0100 Subject: [PATCH 30/74] add devlib2 support --- lib/maintainers/maintainer-list.nix | 4 ++++ pkgs/default.nix | 1 + pkgs/epnix/support/devlib2/default.nix | 32 ++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) create mode 100644 pkgs/epnix/support/devlib2/default.nix diff --git a/lib/maintainers/maintainer-list.nix b/lib/maintainers/maintainer-list.nix index 0061c4fb..a324399d 100644 --- a/lib/maintainers/maintainer-list.nix +++ b/lib/maintainers/maintainer-list.nix @@ -62,4 +62,8 @@ See `` for an ex email = "stephane.tzvetkov@cea.fr"; name = "Stéphane Tzvetkov"; }; + agaget = { + email = "alexis.gaget@cea.fr"; + name = "Alexis Gaget"; + }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index 54a8b087..4382fb9c 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -28,6 +28,7 @@ in asyn = callPackage ./epnix/support/asyn {}; autosave = callPackage ./epnix/support/autosave {}; calc = callPackage ./epnix/support/calc {}; + devlib2 = callPackage ./epnix/support/devlib2 {}; epics-systemd = callPackage ./epnix/support/epics-systemd {}; ipac = callPackage ./epnix/support/ipac {}; modbus = callPackage ./epnix/support/modbus {}; diff --git a/pkgs/epnix/support/devlib2/default.nix b/pkgs/epnix/support/devlib2/default.nix new file mode 100644 index 00000000..2dc3f4ed --- /dev/null +++ b/pkgs/epnix/support/devlib2/default.nix @@ -0,0 +1,32 @@ +{ + lib, + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + fetchpatch, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage rec { + pname = "devlib2"; + version = "2.12"; + varname = "DEVLIB2"; + #tests seems to need a PCI device to be validated. + doCheck = false; + + inherit local_config_site local_release; + + src = fetchFromGitHub { + owner = "epics-modules"; + repo = "devlib2"; + rev = version; + sha256 = "sha256-5rjilz+FO6ZM+Hn7AVwyFG2WWBoBUQA4WW5OHhhdXw4="; + }; + + meta = { + description = "devLib2 - Library for direct MMIO access to PCI and VME64x"; + homepage = "https://github.com/epics-modules/devlib2"; + license = epnixLib.licenses.epics; + maintainers = with epnixLib.maintainers; [agaget]; + }; +} From e3a65006a6ec2e7670a5f7be56f5e5210763eec5 Mon Sep 17 00:00:00 2001 From: Alexis Gaget Date: Tue, 19 Mar 2024 17:40:46 +0100 Subject: [PATCH 31/74] add mrfioc2 support --- lib/maintainers/maintainer-list.nix | 8 +++--- pkgs/default.nix | 1 + pkgs/epnix/support/mrfioc2/default.nix | 39 ++++++++++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) create mode 100644 pkgs/epnix/support/mrfioc2/default.nix diff --git a/lib/maintainers/maintainer-list.nix b/lib/maintainers/maintainer-list.nix index a324399d..d7f1d86a 100644 --- a/lib/maintainers/maintainer-list.nix +++ b/lib/maintainers/maintainer-list.nix @@ -45,6 +45,10 @@ Please keep the list alphabetically sorted. See `` for an example on how to work with this data. */ { + agaget = { + email = "alexis.gaget@cea.fr"; + name = "Alexis Gaget"; + }; minijackson = { email = "remi.nicole@cea.fr"; name = "Rémi Nicole"; @@ -62,8 +66,4 @@ See `` for an ex email = "stephane.tzvetkov@cea.fr"; name = "Stéphane Tzvetkov"; }; - agaget = { - email = "alexis.gaget@cea.fr"; - name = "Alexis Gaget"; - }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index 4382fb9c..adf63a10 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -32,6 +32,7 @@ in epics-systemd = callPackage ./epnix/support/epics-systemd {}; ipac = callPackage ./epnix/support/ipac {}; modbus = callPackage ./epnix/support/modbus {}; + mrfioc2 = callPackage ./epnix/support/mrfioc2 {}; pvxs = callPackage ./epnix/support/pvxs {}; seq = callPackage ./epnix/support/seq {}; snmp = callPackage ./epnix/support/snmp {}; diff --git a/pkgs/epnix/support/mrfioc2/default.nix b/pkgs/epnix/support/mrfioc2/default.nix new file mode 100644 index 00000000..a424cce0 --- /dev/null +++ b/pkgs/epnix/support/mrfioc2/default.nix @@ -0,0 +1,39 @@ +{ + lib, + epnix, + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + fetchpatch, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage rec { + pname = "mrfioc2"; + version = "2.6.0"; + varname = "MRFIOC2"; + + inherit local_config_site local_release; + + src = fetchFromGitHub { + owner = "epics-modules"; + repo = "mrfioc2"; + rev = version; + sha256 = "sha256-pmuM4HrHlZ63BcZACZOlMAPic1IOQ/kLpi9lo/raP0U="; + }; + + propagatedBuildInputs = with epnix.support; [devlib2]; + + postInstall = '' + if [[ -d iocBoot ]]; then + cp -rafv iocBoot -t "$out" + fi + ''; + + meta = { + description = "Driver EPICS for MRF cards"; + homepage = "https://github.com/epics-modules/mrfioc2"; + license = epnixLib.licenses.epics; + maintainers = with epnixLib.maintainers; [agaget]; + }; +} From f801fe19db48b38f3764a5d23585d875666402f7 Mon Sep 17 00:00:00 2001 From: Alexis Gaget Date: Tue, 2 Apr 2024 13:45:16 +0200 Subject: [PATCH 32/74] add EPICS module support 'busy' --- pkgs/default.nix | 1 + pkgs/epnix/support/busy/default.nix | 33 +++++++++++++++++++++++ pkgs/epnix/support/busy/fix-release.patch | 13 +++++++++ 3 files changed, 47 insertions(+) create mode 100644 pkgs/epnix/support/busy/default.nix create mode 100644 pkgs/epnix/support/busy/fix-release.patch diff --git a/pkgs/default.nix b/pkgs/default.nix index adf63a10..9cd1f15d 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -27,6 +27,7 @@ in support = recurseExtensible (_self: { asyn = callPackage ./epnix/support/asyn {}; autosave = callPackage ./epnix/support/autosave {}; + busy = callPackage ./epnix/support/busy {}; calc = callPackage ./epnix/support/calc {}; devlib2 = callPackage ./epnix/support/devlib2 {}; epics-systemd = callPackage ./epnix/support/epics-systemd {}; diff --git a/pkgs/epnix/support/busy/default.nix b/pkgs/epnix/support/busy/default.nix new file mode 100644 index 00000000..7a31a0db --- /dev/null +++ b/pkgs/epnix/support/busy/default.nix @@ -0,0 +1,33 @@ +{ + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + epnix, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage rec { + pname = "busy"; + version = "1-7-4"; + varname = "BUSY"; + + inherit local_config_site local_release; + + src = fetchFromGitHub { + owner = "epics-modules"; + repo = "busy"; + rev = "R${version}"; + sha256 = "sha256-mSzFLj42iXkyWGWaxplfLehoQcULLpf745trYMd1XT4="; + }; + + patches = [./fix-release.patch]; + + buildInputs = with epnix.support; [calc asyn autosave]; + + meta = { + description = "APS BCDA synApps module: busy"; + homepage = "https://epics.anl.gov/bcda/synApps/busy/busy.html"; + license = epnixLib.licenses.epics; + maintainers = with epnixLib.maintainers; [agaget]; + }; +} diff --git a/pkgs/epnix/support/busy/fix-release.patch b/pkgs/epnix/support/busy/fix-release.patch new file mode 100644 index 00000000..5fa017ac --- /dev/null +++ b/pkgs/epnix/support/busy/fix-release.patch @@ -0,0 +1,13 @@ +diff --git a/configure/RELEASE b/configure/RELEASE +index 4d24f2c..61a1d60 100644 +--- a/configure/RELEASE ++++ b/configure/RELEASE +@@ -13,7 +13,7 @@ ASYN=$(SUPPORT)/asyn-4-33 + AUTOSAVE=$(SUPPORT)/autosave-5-9 + + # BUSY is this module +-BUSY=$(SUPPORT)/busy-1-7 ++# BUSY=$(SUPPORT)/busy-1-7 + + # EPICS_BASE usually appears last so other apps can override stuff: + EPICS_BASE=/corvette/usr/local/epics-devel/base-7.0.2 From 1ade2e773547b5845418e3d644010056ea717a36 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 22 Feb 2024 09:26:07 +0100 Subject: [PATCH 33/74] pkgs/scanf: init at 1.5.2 --- pkgs/default.nix | 4 ++++ pkgs/epnix/tools/scanf/default.nix | 31 ++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 pkgs/epnix/tools/scanf/default.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index adf63a10..c51664e0 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -9,6 +9,10 @@ in mkEpicsPackage = callPackage ./build-support/mk-epics-package.nix {}; + python3Packages = prev.python3Packages.overrideScope (final: prev: { + scanf = final.callPackage ./epnix/tools/scanf {}; + }); + epnix = recurseExtensible (self: { # EPICS base diff --git a/pkgs/epnix/tools/scanf/default.nix b/pkgs/epnix/tools/scanf/default.nix new file mode 100644 index 00000000..959b33a3 --- /dev/null +++ b/pkgs/epnix/tools/scanf/default.nix @@ -0,0 +1,31 @@ +{ + lib, + buildPythonPackage, + fetchPypi, + setuptools, + wheel, +}: +buildPythonPackage rec { + pname = "scanf"; + version = "1.5.2"; + pyproject = true; + + src = fetchPypi { + inherit pname version; + hash = "sha256-V2M0QKAqE4zRS2k9CScK8KA7sBfo1M/SSMeYizG4y4E="; + }; + + nativeBuildInputs = [ + setuptools + wheel + ]; + + pythonImportsCheck = ["scanf"]; + + meta = with lib; { + description = "A small scanf implementation"; + homepage = "https://pypi.org/project/scanf/"; + license = licenses.mit; + maintainers = with maintainers; [minijackson]; + }; +} From 51a23e1e59178d9ff4104875573f8c617cbba369 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Thu, 22 Feb 2024 09:26:44 +0100 Subject: [PATCH 34/74] pkgs/lewis: init at 1.3.1 --- pkgs/default.nix | 3 ++ pkgs/epnix/tools/lewis/default.nix | 55 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) create mode 100644 pkgs/epnix/tools/lewis/default.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index c51664e0..3a91ab28 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -10,6 +10,7 @@ in mkEpicsPackage = callPackage ./build-support/mk-epics-package.nix {}; python3Packages = prev.python3Packages.overrideScope (final: prev: { + lewis = final.callPackage ./epnix/tools/lewis {}; scanf = final.callPackage ./epnix/tools/scanf {}; }); @@ -50,6 +51,8 @@ in ca-gateway = callPackage ./epnix/tools/ca-gateway {}; + inherit (final.python3Packages) lewis; + pcas = callPackage ./epnix/tools/pcas {}; phoebus = callPackage ./epnix/tools/phoebus/client { diff --git a/pkgs/epnix/tools/lewis/default.nix b/pkgs/epnix/tools/lewis/default.nix new file mode 100644 index 00000000..1a67da55 --- /dev/null +++ b/pkgs/epnix/tools/lewis/default.nix @@ -0,0 +1,55 @@ +{ + lib, + buildPythonPackage, + fetchFromGitHub, + approvaltests, + setuptools, + wheel, + json-rpc, + mock, + pytest, + pyyaml, + pyzmq, + scanf, + semantic-version, +}: +buildPythonPackage rec { + pname = "lewis"; + version = "1.3.1"; + pyproject = true; + + src = fetchFromGitHub { + owner = "ess-dmsc"; + repo = "lewis"; + rev = "v${version}"; + hash = "sha256-7iMREHt6W26IzCFsRmojHqGuqIUHaCuvsKMMHuYflz0="; + }; + + nativeBuildInputs = [ + setuptools + wheel + ]; + + propagatedBuildInputs = [ + json-rpc + pyyaml + pyzmq + scanf + semantic-version + ]; + + checkInputs = [ + approvaltests + mock + pytest + ]; + + pythonImportsCheck = ["lewis"]; + + meta = with lib; { + description = "Let's write intricate simulators"; + homepage = "https://github.com/ess-dmsc/lewis"; + license = licenses.gpl3Only; + maintainers = with maintainers; [minijackson]; + }; +} From 08f87fb899ba92490bb3f5a971d7a0eca16b4894 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 12 Mar 2024 08:53:01 +0100 Subject: [PATCH 35/74] pkgs: add mkLewisSimulator utility function --- pkgs/default.nix | 1 + pkgs/epnix/tools/lewis/lib.nix | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 pkgs/epnix/tools/lewis/lib.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index 3a91ab28..547eed24 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -52,6 +52,7 @@ in ca-gateway = callPackage ./epnix/tools/ca-gateway {}; inherit (final.python3Packages) lewis; + inherit (callPackage ./epnix/tools/lewis/lib.nix {}) mkLewisSimulator; pcas = callPackage ./epnix/tools/pcas {}; diff --git a/pkgs/epnix/tools/lewis/lib.nix b/pkgs/epnix/tools/lewis/lib.nix new file mode 100644 index 00000000..f6a61586 --- /dev/null +++ b/pkgs/epnix/tools/lewis/lib.nix @@ -0,0 +1,19 @@ +{ + lib, + epnix, + writeShellApplication, +}: { + mkLewisSimulator = { + name, + device ? name, + package, + source, + }: + writeShellApplication { + inherit name; + runtimeInputs = [epnix.lewis]; + text = '' + lewis -a "${source}" -k "${package}" "${device}" "$@" + ''; + }; +} From 9599bacd4cca98e03172575ff1ac4a016e63377b Mon Sep 17 00:00:00 2001 From: Minijackson Date: Wed, 3 Apr 2024 09:12:01 +0200 Subject: [PATCH 36/74] lib/documentation: more robust markdown generation --- lib/documentation.nix | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/documentation.nix b/lib/documentation.nix index aa25dc24..090bcad2 100644 --- a/lib/documentation.nix +++ b/lib/documentation.nix @@ -72,7 +72,7 @@ package2pandoc = headingLevel: path: pkg: let header = lib.fixedWidthString headingLevel "#" ""; in '' - ${header} ${pkg.pname} + ${header} ${pkg.pname or pkg.name} Path : `epnix.${path}` @@ -86,16 +86,17 @@ Homepage : <${pkg.meta.homepage}> - Declared in - : ${let + ${lib.optionalString (pkg.meta ? position) (let filePath = lib.head (lib.splitString ":" pkg.meta.position); relativePath = lib.pipe filePath [ (lib.splitString "/") (lib.sublist 4 255) (lib.concatStringsSep "/") ]; - in - self.markdown.inDefList "[${relativePath}](file://${filePath})"} + in '' + Declared in + : ${self.markdown.inDefList "[${relativePath}](file://${filePath})"} + '')} License(s) : ${self.markdown.inDefList (self.licenseList pkg)} From db030c1b1976c5fa427529efb83225efecb8587c Mon Sep 17 00:00:00 2001 From: Minijackson Date: Tue, 12 Mar 2024 08:52:32 +0100 Subject: [PATCH 37/74] pkgs/psu-simulator: migrate to lewis --- pkgs/doc-support/psu-simulator/default.nix | 15 +- pkgs/doc-support/psu-simulator/poetry.lock | 83 ---- .../psu-simulator/psu_simulator/__init__.py | 206 ---------- .../psu_simulator/psu_simulator.py | 367 ++++++++++++++++++ pkgs/doc-support/psu-simulator/pyproject.toml | 18 +- 5 files changed, 379 insertions(+), 310 deletions(-) delete mode 100644 pkgs/doc-support/psu-simulator/poetry.lock create mode 100644 pkgs/doc-support/psu-simulator/psu_simulator/psu_simulator.py diff --git a/pkgs/doc-support/psu-simulator/default.nix b/pkgs/doc-support/psu-simulator/default.nix index 2f233396..2a850e08 100644 --- a/pkgs/doc-support/psu-simulator/default.nix +++ b/pkgs/doc-support/psu-simulator/default.nix @@ -1,13 +1,20 @@ { - poetry2nix, lib, + epnix, epnixLib, }: -poetry2nix.mkPoetryApplication { - projectDir = ./.; +(epnix.mkLewisSimulator { + name = "psu_simulator"; + package = "psu_simulator"; + source = ./.; +}) +// { + pname = "psu_simulator"; + version = "0.2.0"; meta = { - homepage = "https://epics-extensions.github.io/EPNix/"; + description = "A power supply simulator for the StreamDevice tutorial"; + homepage = "https://epics-extensions.github.io/EPNix/ioc/tutorials/streamdevice.html"; license = lib.licenses.asl20; maintainers = with epnixLib.maintainers; [minijackson]; }; diff --git a/pkgs/doc-support/psu-simulator/poetry.lock b/pkgs/doc-support/psu-simulator/poetry.lock deleted file mode 100644 index fde1b804..00000000 --- a/pkgs/doc-support/psu-simulator/poetry.lock +++ /dev/null @@ -1,83 +0,0 @@ -# This file is automatically @generated by Poetry and should not be changed by hand. - -[[package]] -name = "click" -version = "8.1.7" -description = "Composable command line interface toolkit" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, -] - -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - -[[package]] -name = "colorama" -version = "0.4.6" -description = "Cross-platform colored terminal text." -category = "main" -optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -files = [ - {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, - {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, -] - -[[package]] -name = "importlib-metadata" -version = "6.7.0" -description = "Read metadata from Python packages" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, - {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, -] - -[package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -perf = ["ipython"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] - -[[package]] -name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, -] - -[[package]] -name = "zipp" -version = "3.15.0" -description = "Backport of pathlib-compatible object wrapper for zip files" -category = "main" -optional = false -python-versions = ">=3.7" -files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, -] - -[package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] - -[metadata] -lock-version = "2.0" -python-versions = ">=3.7.0" -content-hash = "1e70b172657bdbef13c5d18991199035640ab2ff4e638ec047db7a4c7a18602c" diff --git a/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py b/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py index cae3015b..e69de29b 100644 --- a/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py +++ b/pkgs/doc-support/psu-simulator/psu_simulator/__init__.py @@ -1,206 +0,0 @@ -"""A simple power supply simulator.""" - -import logging -import random -import socketserver - -import click - -__version__ = "0.1.0" - -# We don't need cryptographically secure RNG -# ruff: noqa: S311 - -logging.basicConfig(level="INFO", format="%(levelname)s %(message)s") -logger = logging.getLogger(__package__) - -class Server(socketserver.ThreadingMixIn, socketserver.TCPServer): - """TCP server.""" - - allow_reuse_address = True - - current: int = 0 - voltage: int = 0 - resistance: int = 0 - - -class PowerSupply(socketserver.StreamRequestHandler): - """The power supply protocol handler.""" - - def set_current(self: "PowerSupply", val: float) -> None: - """Set the current.""" - self.server.current = val - self.server.voltage = self.server.current * self.server.resistance - - def set_voltage(self: "PowerSupply", val: float) -> None: - """Set the voltage.""" - self.server.voltage = val - self.server.current = self.server.voltage / self.server.resistance - - def handle(self: "PowerSupply") -> None: - """Handle incoming connections.""" - logger.info("received connection") - - self._dispatch = { - b"help": self.cmd_help, - b":idn?": self.cmd_get_identification, - b"meas:curr?": self.cmd_get_measured_current, - b":curr?": self.cmd_get_current, - b":curr": self.cmd_set_current, - b"meas:volt?": self.cmd_get_measured_voltage, - b":volt?": self.cmd_get_voltage, - b":volt": self.cmd_set_voltage, - } - - while True: - try: - args = self.rfile.readline().strip().split() - except BrokenPipeError: - return - - if args == []: - try: - self.wfile.write(b".\n") - except BrokenPipeError: - return - continue - - command = args[0].lower() - params = args[1:] - - decoded_params = [param.decode() for param in params] - logger.info("received command: %s%s", command.decode(), decoded_params) - - if command in self._dispatch: - result = self._dispatch[command](*params) - self.wfile.write(str(result).encode()) - self.wfile.write(b"\n") - else: - self.wfile.write(f"command not found: {command.decode()}\n".encode()) - - def finish(self: "PowerSupply") -> None: - """Clean up connections.""" - logger.info("closed connection") - - def cmd_help(self: "PowerSupply", *args: str) -> str: - """Get help about various commands. - - Usage: help . - """ - if len(args) >= 1: - command = args[0] - if command in self._dispatch: - doc = self._dispatch[command].__doc__ - self.wfile.write(doc.encode()) - else: - self.wfile.write(f"command not found: {command!s}".encode()) - return "" - - self.wfile.write(b"Available commands:\n") - for command, func in self._dispatch.items(): - doc = func.__doc__.splitlines()[0].encode() - self.wfile.write(b" - '" + command + b"': " + doc + b"\n") - - return "" - - def cmd_get_identification(self: "PowerSupply", *_args: str) -> int: - """Return the identification of the power supply. - - Usage: :idn? - Returns: string - """ - return f"psu-simulator {__version__}" - - def cmd_get_measured_current(self: "PowerSupply", *_args: str) -> int: - """Return the measured current, in Amps. - - Usage: meas:curr? - Returns: float - """ - return self.server.current + random.uniform(-1.5, 1.5) - - def cmd_get_current(self: "PowerSupply", *_args: str) -> int: - """Return the current current command, in Amps. - - Usage: :curr? - Returns: float - """ - return self.server.current - - def cmd_set_current(self: "PowerSupply", *args: str) -> str: - """Set the current, in Amps. - - Usage: :curr - Returns: 'OK' | 'ERR' - """ - try: - val = float(args[0]) - except ValueError: - return "ERR" - else: - self.set_current(val) - return "OK" - - def cmd_get_measured_voltage(self: "PowerSupply", *_args: str) -> int: - """Return the measured voltage, in Volts. - - Usage: meas:volt? - Returns: float - """ - return self.server.voltage + random.uniform(-1.5, 1.5) - - def cmd_get_voltage(self: "PowerSupply", *_args: str) -> int: - """Return the voltage voltage command, in Volts. - - Usage: :volt? - Returns: float - """ - return self.server.voltage - - def cmd_set_voltage(self: "PowerSupply", *args: str) -> str: - """Set the voltage, in Volts. - - Usage: :volt - Returns: 'OK' | 'ERR' - """ - try: - val = float(args[0]) - except ValueError: - return "ERR" - else: - self.set_voltage(val) - return "OK" - - -@click.command() -@click.option( - "-l", - "--listen-address", - default="localhost", - show_default=True, - help="Listening address", -) -@click.option( - "-p", - "--port", - default=8727, - show_default=True, - help="Listening TCP port", -) -@click.option( - "--resistance", - default=20, - show_default=True, - help="Resistance of the circuit connected to the power supply, in Ohms.", -) -def main(listen_address: str, port: int, resistance: int) -> None: - """Start a power supply simulator server.""" - with Server((listen_address, port), PowerSupply) as server: - logger.info("Listening on %s:%s", listen_address, port) - server.resistance = resistance - logger.info("Resistance is %s Ohms", resistance) - - try: - server.serve_forever() - except KeyboardInterrupt: - return diff --git a/pkgs/doc-support/psu-simulator/psu_simulator/psu_simulator.py b/pkgs/doc-support/psu-simulator/psu_simulator/psu_simulator.py new file mode 100644 index 00000000..58fc066d --- /dev/null +++ b/pkgs/doc-support/psu-simulator/psu_simulator/psu_simulator.py @@ -0,0 +1,367 @@ +"""A simulated power supply. + +The power supply protocol is inspired by the one from genesys power supplies. +""" + +import random +from collections import OrderedDict +from enum import IntEnum + +from lewis.adapters.stream import Cmd, StreamInterface, scanf +from lewis.core import approaches +from lewis.core.statemachine import State +from lewis.devices import StateMachineDevice + +__version__ = "0.1.0" + +# We don't need cryptographically secure RNG +# ruff: noqa: S311 + + +class ConstantMode(IntEnum): + """Whether the power supply is in constant voltage of constant current.""" + + CONSTANT_VOLTAGE = 1 + CONSTANT_CURRENT = 2 + + +class RampMode(IntEnum): + """The type of ramp for approaching the programmed current / voltage.""" + + IMMEDIATE = 0 + BOTH = 1 + UPWARDS = 2 + DOWNWARDS = 3 + + +class ApproachingCurrentState(State): + """The state when the target current is not the programmed current.""" + + def in_state(self: "ApproachingCurrentState", dt: float) -> None: + """Make a step towards the programmed current.""" + old_actual_current = self._context.actual_current + match self._context.current_ramp_mode: + case RampMode.IMMEDIATE: + self._context.actual_current = self._context.programmed_current + case RampMode.BOTH: + self._context.actual_current = approaches.linear( + old_actual_current, + self._context.programmed_current, + self._context.current_ramp, + dt, + ) + + self.log.info( + "Current changed (%s -> %s), programmed=%s, mode=%s, ramp=%s", + old_actual_current, + self._context.actual_current, + self._context.programmed_current, + self._context.current_ramp_mode.name, + self._context.current_ramp, + ) + + +class ApproachingVoltageState(State): + """The state when the target voltage is not the programmed current.""" + + def in_state(self: "ApproachingVoltageState", dt: float) -> None: + """Make a step towards the programmed voltage.""" + old_actual_voltage = self._context.actual_voltage + match self._context.voltage_ramp_mode: + case RampMode.IMMEDIATE: + self._context.actual_voltage = self._context.programmed_voltage + case RampMode.BOTH: + self._context.actual_voltage = approaches.linear( + old_actual_voltage, + self._context.programmed_voltage, + self._context.voltage_ramp, + dt, + ) + + self.log.info( + "Voltage changed (%s -> %s), programmed=%s, mode=%s, ramp=%s", + old_actual_voltage, + self._context.actual_voltage, + self._context.programmed_voltage, + self._context.voltage_ramp_mode.name, + self._context.voltage_ramp, + ) + + +class SimulatedPowerSupply(StateMachineDevice): + """The simulated power supply.""" + + def _initialize_data(self: "SimulatedPowerSupply") -> None: + self.serial: str = f"psu-simulator {__version__}" + + self.powered: bool = True + self.mode: ConstantMode = ConstantMode.CONSTANT_VOLTAGE + self.resistance: float = 2.0 + + self.programmed_voltage: float = 0.0 + self.actual_voltage: float = 0.0 + self.voltage_ramp_mode: RampMode = RampMode.IMMEDIATE + self.voltage_ramp: float = 0.0 + + self.programmed_current: float = 0.0 + self.actual_current: float = 0.0 + self.current_ramp_mode: RampMode = RampMode.IMMEDIATE + self.current_ramp: float = 0.0 + + def _get_state_handlers(self: "SimulatedPowerSupply") -> dict[str, State]: + return { + "off": State(), + "constant_voltage": State(), + "approaching_voltage": ApproachingVoltageState(), + "constant_current": State(), + "approaching_current": ApproachingCurrentState(), + } + + def _get_initial_state(self: "SimulatedPowerSupply") -> str: + return "off" + + @property + def measured_current(self: "SimulatedPowerSupply") -> float: + """The currently measured output current.""" + if not self.powered: + return 0 + + match self.mode: + case ConstantMode.CONSTANT_VOLTAGE: + return self.actual_voltage / self.resistance + case ConstantMode.CONSTANT_CURRENT: + return self.actual_current + + @property + def measured_voltage(self: "SimulatedPowerSupply") -> float: + """The currently measured output voltage.""" + if not self.powered: + return 0 + + match self.mode: + case ConstantMode.CONSTANT_VOLTAGE: + return self.actual_voltage + case ConstantMode.CONSTANT_CURRENT: + return self.actual_current * self.resistance + + def _get_transition_handlers(self: "SimulatedPowerSupply") -> OrderedDict: + return OrderedDict( + [ + ( + ("off", "constant_voltage"), + lambda: self.powered and self.mode == ConstantMode.CONSTANT_VOLTAGE, + ), + ( + ("off", "constant_current"), + lambda: self.powered and self.mode == ConstantMode.CONSTANT_CURRENT, + ), + (("constant_voltage", "off"), lambda: not self.powered), + (("constant_current", "off"), lambda: not self.powered), + (("approaching_voltage", "off"), lambda: not self.powered), + (("approaching_current", "off"), lambda: not self.powered), + ( + ("constant_voltage", "approaching_voltage"), + lambda: self.programmed_voltage != self.actual_voltage, + ), + ( + ("approaching_voltage", "constant_voltage"), + lambda: self.programmed_voltage == self.actual_voltage, + ), + ( + ("constant_current", "approaching_current"), + lambda: self.programmed_current != self.actual_current, + ), + ( + ("approaching_current", "constant_current"), + lambda: self.programmed_current == self.actual_current, + ), + ] + ) + + +class PowerSupplyInterface(StreamInterface): + """The TCP/IP interface to the power supply.""" + + commands = frozenset( + { + Cmd("help", "help( .+)?"), + Cmd("get_idn", scanf(":idn?")), + Cmd("get_powered", scanf("outp:pon?")), + Cmd("set_powered", scanf("outp:pon %s"), argument_mappings=(bytes,)), + Cmd("get_mode", scanf("outp:mode?")), + Cmd("_set_mode", scanf("outp:mode %s"), argument_mappings=(bytes,)), + Cmd("get_measured_current", scanf("meas:curr?")), + Cmd("get_programmed_current", scanf(":curr?")), + Cmd( + "set_programmed_current", + scanf(r":curr %f"), + argument_mappings=(float,), + ), + Cmd("get_measured_voltage", scanf("meas:volt?")), + Cmd("get_programmed_voltage", scanf(":volt?")), + Cmd( + "_set_programmed_voltage", + scanf(r":volt %f"), + argument_mappings=(float,), + ), + }, + ) + + in_terminator = "\n" + out_terminator = "\n" + + def help(self: "PowerSupplyInterface", arg: bytes) -> str: + """Print help about the various commands. + + Usage: help + Usage: help + """ + result = "" + + if arg is not None: + return self._help_about(arg.decode().strip()) + + def _sort_key(cmd: Cmd) -> str: + return getattr(cmd.pattern, "pattern", "help") + + for cmd in sorted(self.commands, key=_sort_key): + cmd_name = "help (%s)" if cmd.func == "help" else cmd.pattern.pattern + doc = getattr(self, cmd.func).__doc__ + if doc is None: + continue + summary = doc.splitlines()[0] + + result += " - '" + cmd_name + "': " + summary + "\n" + + return result + + def _help_about(self: "PowerSupplyInterface", command: str) -> str: + if command == "help": + return self.help.__doc__ + + doc = None + for cmd in self.commands: + if cmd.func == "help": + continue + cmd_name = cmd.pattern.pattern.split()[0] + if cmd_name == command: + doc = getattr(self, cmd.func).__doc__ + break + + if doc is None: + return "Unknown command" + + return doc + + def get_idn(self: "PowerSupplyInterface") -> str: + """Return the identification of the power supply. + + Usage: :idn? + Returns: string + """ + return self.device.serial + + def get_powered(self: "PowerSupplyInterface") -> str: + """Return whether the output of the power supply is powered on. + + Usage: outp:pon? + Returns: "ON" | "OFF" + """ + return "ON" if self.device.powered else "OFF" + + def set_powered(self: "PowerSupplyInterface", val: bytes) -> str: + """Enable or disable the output. + + Usage: outp:pon <"ON" | "1" | "OFF" | "0"> + Returns: "OK" | "ERR" + """ + match val.lower(): + case b"on" | b"1": + self.device.powered = True + return "OK" + case b"off" | b"0": + self.device.powered = False + return "OK" + case _: + return "ERR" + + def get_mode(self: "PowerSupplyInterface") -> str: + """Return whether the power supply is in constant voltage or constant current. + + Usage: outp:mode? + Returns: "CV" (the default) | "CC" + """ + match self.device.mode: + case ConstantMode.CONSTANT_CURRENT: + return "CC" + case ConstantMode.CONSTANT_VOLTAGE: + return "CV" + + def _set_mode(self: "PowerSupplyInterface", val: bytes) -> str: + """Set whether the power supply is in constant current or constant voltage. + + Usage: outp:mode <"CV" | "CC"> + Returns: "OK" | "ERR" + """ + match val.lower(): + case b"cc": + self.device.mode = ConstantMode.CONSTANT_CURRENT + return "OK" + case b"cv": + self.device.mode = ConstantMode.CONSTANT_VOLTAGE + return "OK" + case _: + return "ERR" + + def get_measured_current(self: "PowerSupplyInterface") -> str: + """Return the measured current, in Amps. + + Usage: meas:curr? + Returns: float + """ + try: + return self.device.measured_current + random.uniform(-1.5, 1.5) + except Exception as e: + return str(e) + + def get_programmed_current(self: "PowerSupplyInterface") -> str: + """Return the current current command, in Amps. + + Usage: :curr? + Returns: float + """ + return self.device.programmed_current + + def set_programmed_current(self: "PowerSupplyInterface", val: float) -> str: + """Set the current, in Amps. + + Usage: :curr + Returns: "OK" | "ERR" + """ + self.device.programmed_current = val + return "OK" + + def get_measured_voltage(self: "PowerSupplyInterface") -> str: + """Return the measured voltage, in Volts. + + Usage: meas:volt? + Returns: float + """ + return self.device.measured_voltage + random.uniform(-1.5, 1.5) + + def get_programmed_voltage(self: "PowerSupplyInterface") -> str: + """Return the voltage voltage command, in Volts. + + Usage: :volt? + Returns: float + """ + return self.device.programmed_voltage + + def _set_programmed_voltage(self: "PowerSupplyInterface", val: float) -> str: + """Set the voltage, in Volts. + + Usage: :volt + Returns: "OK" | "ERR" + """ + self.device.programmed_voltage = val + return "OK" diff --git a/pkgs/doc-support/psu-simulator/pyproject.toml b/pkgs/doc-support/psu-simulator/pyproject.toml index cc599d2f..f5a0ff5f 100644 --- a/pkgs/doc-support/psu-simulator/pyproject.toml +++ b/pkgs/doc-support/psu-simulator/pyproject.toml @@ -1,19 +1,3 @@ -[tool.poetry] -name = "psu-simulator" -version = "0.1.0" -description = "A power supply simulator for the StreamDevice tutorial" -authors = ["Rémi NICOLE "] - -[tool.poetry.scripts] -psu-simulator = "psu_simulator:main" - -[tool.poetry.dependencies] -python = ">=3.7.0" -click = "^8.1.7" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - [tool.ruff] select = ["ALL"] +target-version = "py310" From e7a835f436655f25d46efc3a5cc400f2e6503961 Mon Sep 17 00:00:00 2001 From: Minijackson Date: Wed, 3 Apr 2024 08:54:18 +0200 Subject: [PATCH 38/74] ioc/tests/StreamDevice: use psu-simulator as "mock server" --- .../support/StreamDevice/simple/default.nix | 82 ++++----- .../simple/mock-server/.gitignore | 158 ------------------ .../mock-server/mock_server/__init__.py | 66 -------- .../simple/mock-server/poetry.lock | 8 - .../simple/mock-server/pyproject.toml | 15 -- .../simple/top/iocBoot/iocsimple/st.cmd | 2 +- .../simple/top/simpleApp/Db/simple.db | 91 +++++----- .../simple/top/simpleApp/Db/simple.proto | 71 ++++---- 8 files changed, 113 insertions(+), 380 deletions(-) delete mode 100644 ioc/tests/support/StreamDevice/simple/mock-server/.gitignore delete mode 100644 ioc/tests/support/StreamDevice/simple/mock-server/mock_server/__init__.py delete mode 100644 ioc/tests/support/StreamDevice/simple/mock-server/poetry.lock delete mode 100644 ioc/tests/support/StreamDevice/simple/mock-server/pyproject.toml diff --git a/ioc/tests/support/StreamDevice/simple/default.nix b/ioc/tests/support/StreamDevice/simple/default.nix index dc2ddcc3..45eeaf6e 100644 --- a/ioc/tests/support/StreamDevice/simple/default.nix +++ b/ioc/tests/support/StreamDevice/simple/default.nix @@ -2,10 +2,6 @@ inherit (pkgs) epnixLib; inherit (pkgs.stdenv.hostPlatform) system; - mock_server = pkgs.poetry2nix.mkPoetryApplication { - projectDir = ./mock-server; - }; - result = epnixLib.evalEpnixModules { nixpkgsConfig.system = system; epnixConfig.imports = [./top/epnix.nix]; @@ -19,70 +15,60 @@ in name = "support-StreamDevice-simple"; meta.maintainers = with epnixLib.maintainers; [minijackson]; - nodes.machine = let - listenAddr = "127.0.0.1:1234"; - in - {lib, ...}: { - environment.systemPackages = [pkgs.epnix.epics-base]; + nodes.machine = {lib, ...}: { + environment.systemPackages = [pkgs.epnix.epics-base]; - systemd.sockets.mock-server = { + systemd.services = { + "psu-simulator" = { wantedBy = ["multi-user.target"]; - listenStreams = [listenAddr]; - socketConfig.Accept = true; - }; - - systemd.services = { - "mock-server@".serviceConfig = { - ExecStart = "${mock_server}/bin/mock_server"; - StandardInput = "socket"; - StandardError = "journal"; + serviceConfig = { + ExecStart = lib.getExe pkgs.epnix.psu-simulator; }; - - ioc = lib.mkMerge [ - service - {environment.STREAM_PS1 = listenAddr;} - ]; }; + + ioc = lib.mkMerge [ + service + {environment.STREAM_PS1 = "localhost:9999";} + ]; }; + }; testScript = '' machine.wait_for_unit("default.target") machine.wait_for_unit("ioc.service") - with subtest("getting fixed values"): - machine.wait_until_succeeds("caget -t FLOAT:IN | grep -qxF '42.1234'") - machine.wait_until_succeeds("caget -t FLOAT_WITH_PREFIX:IN | grep -qxF '69.1337'") - machine.wait_until_succeeds("caget -t ENUM:IN | grep -qxF '1'") + def assert_caget(pv: str, expected: str) -> None: + machine.wait_until_succeeds(f"caget -t '{pv}' | grep -qxF '{expected}'", timeout=10) - with subtest("setting values"): - machine.wait_until_succeeds("caget -t VARFLOAT:IN | grep -qxF '0'") - - # Caput can simply not go through - def put_check_varfloat(_) -> bool: - machine.succeed("caput VARFLOAT:OUT 123.456") - status, _output = machine.execute("caget -t VARFLOAT:IN | grep -qxF '123.456'") + def assert_caput(pv: str, value: str) -> None: + def do_caput(_) -> bool: + machine.succeed(f"caput '{pv}' '{value}'") + status, _output = machine.execute(f"caget -t '{pv}' | grep -qxF '{value}'") return status == 0 - retry(put_check_varfloat) + retry(do_caput, timeout=10) - with subtest("calc integration"): - machine.wait_until_succeeds("caget -t SCALC:IN | grep -qxF '10A'") + with subtest("getting initial values"): + assert_caget("UCmd", "0") + assert_caget("URb", "0") + assert_caget("PowerCmd", "ON") + assert_caget("PowerRb", "ON") - def put_check_scalc(_) -> bool: - machine.succeed("caput SCALC:OUT.A 2") - status, _output = machine.execute("caget -t SCALC:IN | grep -qxF '14A'") - return status == 0 - - retry(put_check_scalc) + with subtest("setting values"): + assert_caput("UCmd", "10") + assert_caget("URb", "10") - machine.wait_until_succeeds("caget -t SCALC:OUT.SVAL | grep -qxF 'sent'") + with subtest("calc integration"): + assert_caput("2UCmd.A", "42") + assert_caget("2UCmd.SVAL", "184") + assert_caget("URb", "184") with subtest("regular expressions"): - machine.wait_until_succeeds("caget -t REGEX_TITLE:IN | grep -qxF 'Hello, World!'") - machine.wait_until_succeeds("caget -t REGEX_SUB:IN | grep -qxF 'abcXcXcabc'") + assert_caget("VersionNum", "0.1.0") + assert_caget("VersionCat", "010") ''; passthru = { - inherit mock_server ioc; + inherit ioc; }; } diff --git a/ioc/tests/support/StreamDevice/simple/mock-server/.gitignore b/ioc/tests/support/StreamDevice/simple/mock-server/.gitignore deleted file mode 100644 index 13189553..00000000 --- a/ioc/tests/support/StreamDevice/simple/mock-server/.gitignore +++ /dev/null @@ -1,158 +0,0 @@ -# Created by https://www.toptal.com/developers/gitignore/api/python -# Edit at https://www.toptal.com/developers/gitignore?templates=python - -### Python ### -# Byte-compiled / optimized / DLL files -__pycache__/ -*.py[cod] -*$py.class - -# C extensions -*.so - -# Distribution / packaging -.Python -build/ -develop-eggs/ -dist/ -downloads/ -eggs/ -.eggs/ -lib/ -lib64/ -parts/ -sdist/ -var/ -wheels/ -share/python-wheels/ -*.egg-info/ -.installed.cfg -*.egg -MANIFEST - -# PyInstaller -# Usually these files are written by a python script from a template -# before PyInstaller builds the exe, so as to inject date/other infos into it. -*.manifest -*.spec - -# Installer logs -pip-log.txt -pip-delete-this-directory.txt - -# Unit test / coverage reports -htmlcov/ -.tox/ -.nox/ -.coverage -.coverage.* -.cache -nosetests.xml -coverage.xml -*.cover -*.py,cover -.hypothesis/ -.pytest_cache/ -cover/ - -# Translations -*.mo -*.pot - -# Django stuff: -*.log -local_settings.py -db.sqlite3 -db.sqlite3-journal - -# Flask stuff: -instance/ -.webassets-cache - -# Scrapy stuff: -.scrapy - -# Sphinx documentation -docs/_build/ - -# PyBuilder -.pybuilder/ -target/ - -# Jupyter Notebook -.ipynb_checkpoints - -# IPython -profile_default/ -ipython_config.py - -# pyenv -# For a library or package, you might want to ignore these files since the code is -# intended to run in multiple environments; otherwise, check them in: -# .python-version - -# pipenv -# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. -# However, in case of collaboration, if having platform-specific dependencies or dependencies -# having no cross-platform support, pipenv may install dependencies that don't work, or not -# install all needed dependencies. -#Pipfile.lock - -# poetry -# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. -# This is especially recommended for binary packages to ensure reproducibility, and is more -# commonly ignored for libraries. -# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control -#poetry.lock - -# PEP 582; used by e.g. github.com/David-OConnor/pyflow -__pypackages__/ - -# Celery stuff -celerybeat-schedule -celerybeat.pid - -# SageMath parsed files -*.sage.py - -# Environments -.env -.venv -env/ -venv/ -ENV/ -env.bak/ -venv.bak/ - -# Spyder project settings -.spyderproject -.spyproject - -# Rope project settings -.ropeproject - -# mkdocs documentation -/site - -# mypy -.mypy_cache/ -.dmypy.json -dmypy.json - -# Pyre type checker -.pyre/ - -# pytype static type analyzer -.pytype/ - -# Cython debug symbols -cython_debug/ - -# PyCharm -# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can -# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore -# and can be added to the global gitignore or merged into this file. For a more nuclear -# option (not recommended) you can uncomment the following to ignore the entire idea folder. -#.idea/ - -# End of https://www.toptal.com/developers/gitignore/api/python diff --git a/ioc/tests/support/StreamDevice/simple/mock-server/mock_server/__init__.py b/ioc/tests/support/StreamDevice/simple/mock-server/mock_server/__init__.py deleted file mode 100644 index 92fb10c6..00000000 --- a/ioc/tests/support/StreamDevice/simple/mock-server/mock_server/__init__.py +++ /dev/null @@ -1,66 +0,0 @@ -"""A simple server mocking an ASCII communication.""" - -import sys - -__version__ = "0.1.0" - - -def log(*args: str, **kwargs: str) -> None: - """Print a message to stderr.""" - print(*args, file=sys.stderr, **kwargs) - - -def send(*args: str, **kwargs: str) -> None: - """Send a message.""" - print(*args, end="\r\n", flush=True, **kwargs) - - -def main() -> None: - """Start the mock server.""" - log("received connection") - - varfloat = 0.0 - scalc = "" - - while True: - data = sys.stdin.readline().strip() - - if not data: - break - - log("received command:", data) - - # TODO(minijackson): change that with a command-line parsing tool? - - if data == "FLOAT": - send("42.1234") - elif data == "FLOAT_WITH_PREFIX": - send("VALUE: 69.1337") - elif data == "ENUM": - send("TWO") - elif data.startswith("SET_VARFLOAT "): - varfloat = float(data.split(" ", maxsplit=1)[1]) - elif data == "GET_VARFLOAT": - send(str(varfloat)) - elif data == "REGEX_TITLE": - send( - """ - - - Hello, World! - - -

Hello, World!

- - -""", - ) - elif data == "REGEX_SUB": - send("abcabcabcabc") - elif data.startswith("SET_SCALC "): - send("sent") - scalc = data.split(" ", maxsplit=1)[1] - elif data == "GET_SCALC": - send(scalc) - else: - log("unknown command") diff --git a/ioc/tests/support/StreamDevice/simple/mock-server/poetry.lock b/ioc/tests/support/StreamDevice/simple/mock-server/poetry.lock deleted file mode 100644 index d9af7385..00000000 --- a/ioc/tests/support/StreamDevice/simple/mock-server/poetry.lock +++ /dev/null @@ -1,8 +0,0 @@ -package = [] - -[metadata] -lock-version = "1.1" -python-versions = "*" -content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" - -[metadata.files] diff --git a/ioc/tests/support/StreamDevice/simple/mock-server/pyproject.toml b/ioc/tests/support/StreamDevice/simple/mock-server/pyproject.toml deleted file mode 100644 index d248b538..00000000 --- a/ioc/tests/support/StreamDevice/simple/mock-server/pyproject.toml +++ /dev/null @@ -1,15 +0,0 @@ -[tool.poetry] -name = "mock-server" -version = "0.1.0" -description = "Mock Server for the simple StreamDevice support test" -authors = ["Rémi NICOLE "] - -[tool.poetry.scripts] -mock_server = "mock_server:main" - -[build-system] -requires = ["poetry-core>=1.0.0"] -build-backend = "poetry.core.masonry.api" - -[tool.ruff] -select = ["ALL"] diff --git a/ioc/tests/support/StreamDevice/simple/top/iocBoot/iocsimple/st.cmd b/ioc/tests/support/StreamDevice/simple/top/iocBoot/iocsimple/st.cmd index e170880f..d3ca8c76 100755 --- a/ioc/tests/support/StreamDevice/simple/top/iocBoot/iocsimple/st.cmd +++ b/ioc/tests/support/StreamDevice/simple/top/iocBoot/iocsimple/st.cmd @@ -13,6 +13,6 @@ epicsEnvSet("STREAM_PROTOCOL_PATH", ".:${TOP}/db") drvAsynIPPortConfigure("PS1", "${STREAM_PS1}") ## Load record instances -dbLoadRecords("../../db/simple.db", "PORT=PS1") +dbLoadRecords("../../db/simple.db", "PORT=PS1,P=") iocInit() diff --git a/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.db b/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.db index e68e5ebc..3a44589e 100644 --- a/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.db +++ b/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.db @@ -1,81 +1,82 @@ -# Fixed values +# Normal flow -record(ai, "FLOAT:IN") { - field(DESC, "A fixed float") +record(ao, "${P}UCmd") { + field(DESC, "Voltage command") field(DTYP, "stream") - field(INP, "@simple.proto getFloat $(PORT)") - field(PINI, "YES") - field(SCAN, "5 second") + field(OUT, "@simple.proto setUCmd $(PORT)") + field(EGU, "V") + + field(FLNK, "${P}URb") } -record(ai, "FLOAT_WITH_PREFIX:IN") { - field(DESC, "A fixed float with a returned prefix") +record(ai, "${P}URb") { + field(DESC, "Voltage read-back") field(DTYP, "stream") - field(INP, "@simple.proto getFloatWithPrefix $(PORT)") + field(INP, "@simple.proto getURb $(PORT)") + field(EGU, "V") field(PINI, "YES") - field(SCAN, "5 second") } -record(longin, "ENUM:IN") { - field(DESC, "An fixed enum parsed as integer") +record(ai, "${P}UMes") { + field(DESC, "Measure of voltage intensity") field(DTYP, "stream") - field(INP, "@simple.proto getEnum $(PORT)") + field(INP, "@simple.proto getUMes $(PORT)") + field(EGU, "V") field(PINI, "YES") field(SCAN, "5 second") } -# Variable values - -record(ai, "VARFLOAT:IN") { - field(DESC, "A variable float") +record(bo, "${P}PowerCmd") { + field(DESC, "Command for enabling output") field(DTYP, "stream") - field(INP, "@simple.proto getVarFloat $(PORT)") - field(PINI, "YES") - field(SCAN, "5 second") + field(OUT, "@simple.proto setPowerCmd $(PORT)") + field(ZNAM, "OFF") + field(ONAM, "ON") + + field(FLNK, "${P}PowerRb") } -record(ao, "VARFLOAT:OUT") { - field(DESC, "A variable float") +record(bi, "${P}PowerRb") { + field(DESC, "Read back of power supply is enabled") field(DTYP, "stream") - field(OUT, "@simple.proto setVarFloat $(PORT)") - field(FLNK, "VARFLOAT:IN") -} + field(INP, "@simple.proto getPowerRb $(PORT)") + field(PINI, YES) + field(ZNAM, "OFF") + field(ONAM, "ON") -# Calc + # field(FLNK, "${P}Status") +} -record(stringin, "SCALC:IN") { - field(DESC, "Result of scalcout record") +record(stringin, "${P}Version") { + field(DESC, "A fixed float with a returned prefix") field(DTYP, "stream") - field(INP, "@simple.proto getSCalc $(PORT)") + field(INP, "@simple.proto getVersion $(PORT)") field(PINI, "YES") - field(SCAN, "5 second") } -record(scalcout, "SCALC:OUT") { - field(DESC, "An scalcout record") +# Calc + +record(scalcout, "${P}2UCmd") { + field(DESC, "Twice the voltage command") field(A, "0") - field(CALC, "printf('1%i', A*A) + 'A'") + field(CALC, "printf('1%i', A*2)") field(DTYP, "stream") - field(OUT, "@simple.proto setSCalc $(PORT)") - field(FLNK, "SCALC:IN") - field(PINI, "YES") - field(SCAN, "5 second") + field(OUT, "@simple.proto setUCmd $(PORT)") + field(FLNK, "${P}URb") } # Regular Expressions -record(stringin, "REGEX_TITLE:IN") { - field(DESC, "A regex test") +record(stringin, "${P}VersionNum") { + field(DESC, "Just the version number") field(DTYP, "stream") - field(INP, "@simple.proto getRegexTitle $(PORT)") + field(INP, "@simple.proto getVersionNum $(PORT)") field(PINI, "YES") - field(SCAN, "5 second") } -record(stringin, "REGEX_SUB:IN") { - field(DESC, "A regex substitution test") +record(stringin, "${P}VersionCat") { + field(DESC, "Just the version numbers, concatenated") field(DTYP, "stream") - field(INP, "@simple.proto getRegexSub $(PORT)") + field(INP, "@simple.proto getVersionCat $(PORT)") field(PINI, "YES") - field(SCAN, "5 second") } diff --git a/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.proto b/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.proto index f7c28e6b..86b07964 100644 --- a/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.proto +++ b/ioc/tests/support/StreamDevice/simple/top/simpleApp/Db/simple.proto @@ -1,59 +1,52 @@ -Terminator = CR LF; +Terminator = LF; -# Fixed values +# Normal flow -getFloat { - out "FLOAT"; - in "%f"; +getURb { + out ":volt?"; + in "%f"; } -getFloatWithPrefix { - out "FLOAT_WITH_PREFIX"; - in "VALUE: %f"; -} +setUCmd { + out ":volt %f"; + in "OK"; -getEnum { - out "ENUM"; - in "%{ONE|TWO|THREE}"; + @init { getURb; } } -# Variable values - -setVarFloat { - out "SET_VARFLOAT %f"; +getUMes { + out "meas:volt?"; + in "%f"; } -getVarFloat { - out "GET_VARFLOAT"; - in "%f"; +# Checks parsing enums +getPowerRb { + out "outp:pon?"; + in "%{OFF|ON}"; } -# Calc +# Checks writing enums +setPowerCmd { + out "outp:pon %{OFF|ON}"; + in "OK"; -getSCalc { - out "GET_SCALC"; - in "%s"; + @init { getPowerRb; } } -setSCalc { - out "SET_SCALC %s"; - in "%s"; +# Checks parsing with prefix +getVersion { + out ":idn?"; + in "psu-simulator %s"; } -# Regular Expressions +# Checks regular expressions -getRegexTitle { - out "REGEX_TITLE"; - # Added `[\s\S]+$` at the end to silence warning of extra input - in "%.1/(.*)<\/title>[\s\S]+$/" +getVersionNum { + out ":idn?"; + in "%.1/^psu-simulator (\d+\.\d+\.\d+)$/" } -getRegexSub { - out "REGEX_SUB"; - # TODO: weirdness in StreamDevice, the `+.2` here means "replace a maximum of - # 2", but it also needs 2 regex sub-expression, hence the "(())", as if it - # were a normal regex converter ("%/regex/"). - # - # Also %s needed to be after instead of before. - in "%#+-10.2/((ab))/X/%s"; +getVersionCat { + out ":idn?"; + in "%#/^psu-simulator (\d+)\.(\d+)\.(\d+)$/\1\2\3/%s"; } From 9e2e00683dbb8b1243420e25719408e4bfe1c14f Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Tue, 13 Feb 2024 08:36:38 +0100 Subject: [PATCH 39/74] flake: upgrade NixOS 23.05 -> 23.11 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit in flake, in template, and in documentation also add poetry2nix overlay, since it was removed from nixpkgs in 23.11 Flake lock file updates: • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/e5f018cf150e29aac26c61dac0790ea023c46b24' (2023-09-12) → 'github:NixOS/nixpkgs/809cca784b9f72a5ad4b991e0e7bcf8890f9c3a6' (2024-02-11) • Added input 'poetry2nix': 'github:nix-community/poetry2nix/4eb2ac54029af42a001c9901194e9ce19cbd8a40' (2024-02-06) • Added input 'poetry2nix/flake-utils': 'github:numtide/flake-utils/ff7b65b44d01cf9ba6a71320833626af21126384' (2023-09-12) • Added input 'poetry2nix/flake-utils/systems': 'github:nix-systems/default/da67096a3b9bf56a91d16901293e51ba5b49a27e' (2023-04-09) • Added input 'poetry2nix/nix-github-actions': 'github:nix-community/nix-github-actions/4bb5e752616262457bc7ca5882192a564c0472d2' (2023-11-03) • Added input 'poetry2nix/nix-github-actions/nixpkgs': follows 'poetry2nix/nixpkgs' • Added input 'poetry2nix/nixpkgs': follows 'nixpkgs' • Added input 'poetry2nix/systems': 'github:nix-systems/default/da67096a3b9bf56a91d16901293e51ba5b49a27e' (2023-04-09) • Added input 'poetry2nix/treefmt-nix': 'github:numtide/treefmt-nix/e82f32aa7f06bbbd56d7b12186d555223dc399d1' (2023-11-12) • Added input 'poetry2nix/treefmt-nix/nixpkgs': follows 'poetry2nix/nixpkgs' --- doc/nixos/guides/_pre-requisites.md | 2 +- doc/nixos/tutorials/archiver-appliance.md | 8 +- flake.lock | 124 +++++++++++++++++++++- flake.nix | 22 ++-- ioc/modules/common.nix | 6 +- pkgs/epnix/tools/phoebus/deps/default.nix | 2 +- pkgs/epnix/tools/phoebus/olog/default.nix | 2 +- 7 files changed, 145 insertions(+), 21 deletions(-) diff --git a/doc/nixos/guides/_pre-requisites.md b/doc/nixos/guides/_pre-requisites.md index 67a77503..82b49c70 100644 --- a/doc/nixos/guides/_pre-requisites.md +++ b/doc/nixos/guides/_pre-requisites.md @@ -18,7 +18,7 @@ For example: ``` {.diff filename="flake.nix"} { # ... -+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; ++ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + inputs.epnix.url = "github:epics-extensions/EPNix"; # ... diff --git a/doc/nixos/tutorials/archiver-appliance.md b/doc/nixos/tutorials/archiver-appliance.md index a1cdbbee..41681332 100644 --- a/doc/nixos/tutorials/archiver-appliance.md +++ b/doc/nixos/tutorials/archiver-appliance.md @@ -57,7 +57,7 @@ Fill the file with these lines: { description = "Configuration for running Archiver Appliance in a VM"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; inputs.epnix.url = "github:epics-extensions/EPNix"; outputs = { self, nixpkgs, epnix }: { @@ -72,11 +72,7 @@ Fill the file with these lines: } ``` -```{=html} -<!-- TODO: replace raw html with the kbd shortcode once we are using Quarto 1.3 --> -<!-- https://quarto.org/docs/authoring/markdown-basics.html#keyboard-shortcuts --> -``` -Save and quit by typing `<kbd>`{=html}Ctrl-x`</kbd>`{=html}, `<kbd>`{=html}y`</kbd>`{=html}, and `<kbd>`{=html}Enter`</kbd>`{=html}, +Save and quit by typing {{< kbd Ctrl-x >}}, {{< kbd y >}}, and {{< kbd Enter >}}, and run `nixos-rebuild test` to test your changes. Some explanations: diff --git a/flake.lock b/flake.lock index b3c2619a..acc7ae62 100644 --- a/flake.lock +++ b/flake.lock @@ -51,27 +51,141 @@ "type": "github" } }, + "flake-utils_3": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1694529238, + "narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "ff7b65b44d01cf9ba6a71320833626af21126384", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1698974481, + "narHash": "sha256-yPncV9Ohdz1zPZxYHQf47S8S0VrnhV7nNhCawY46hDA=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "4bb5e752616262457bc7ca5882192a564c0472d2", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, "nixpkgs": { "locked": { - "lastModified": 1694499547, - "narHash": "sha256-R7xMz1Iia6JthWRHDn36s/E248WB1/je62ovC/dUVKI=", + "lastModified": 1707650010, + "narHash": "sha256-dOhphIA4MGrH4ElNCy/OlwmN24MsnEqFjRR6+RY7jZw=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "e5f018cf150e29aac26c61dac0790ea023c46b24", + "rev": "809cca784b9f72a5ad4b991e0e7bcf8890f9c3a6", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.05", + "ref": "nixos-23.11", "repo": "nixpkgs", "type": "github" } }, + "poetry2nix": { + "inputs": { + "flake-utils": "flake-utils_3", + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "nixpkgs" + ], + "systems": "systems_2", + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1707195113, + "narHash": "sha256-xPFxTMe4rKE/ZWLlOWv22qpGwpozpR+U1zhyf1040Zk=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "4eb2ac54029af42a001c9901194e9ce19cbd8a40", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, "root": { "inputs": { "bash-lib": "bash-lib", "flake-utils": "flake-utils_2", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix" + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + }, + "systems_2": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "id": "systems", + "type": "indirect" + } + }, + "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1699786194, + "narHash": "sha256-3h3EH1FXQkIeAuzaWB+nK0XK54uSD46pp+dMD3gAcB4=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "e82f32aa7f06bbbd56d7b12186d555223dc399d1", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" } } }, diff --git a/flake.nix b/flake.nix index a8980512..f9291101 100644 --- a/flake.nix +++ b/flake.nix @@ -1,12 +1,18 @@ { description = "A Nix flake containing EPICS-related modules and packages"; - inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.05"; - inputs.bash-lib = { - url = "github:minijackson/bash-lib"; - inputs.nixpkgs.follows = "nixpkgs"; + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + bash-lib = { + url = "github:minijackson/bash-lib"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; + poetry2nix = { + url = "github:nix-community/poetry2nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - inputs.flake-utils.url = "github:numtide/flake-utils"; outputs = { self, @@ -19,7 +25,11 @@ systemDependentOutputs = system: let pkgs = import nixpkgs { inherit system; - overlays = [overlay inputs.bash-lib.overlay]; + overlays = [ + overlay + inputs.bash-lib.overlay + inputs.poetry2nix.overlays.default + ]; }; in { packages = flake-utils.lib.flattenTree pkgs.epnix; diff --git a/ioc/modules/common.nix b/ioc/modules/common.nix index d98303da..11838b6b 100644 --- a/ioc/modules/common.nix +++ b/ioc/modules/common.nix @@ -51,6 +51,10 @@ with lib; { }; config = { - nixpkgs.overlays = [epnix.inputs.bash-lib.overlay epnix.overlays.default]; + nixpkgs.overlays = [ + epnix.inputs.poetry2nix.overlays.default + epnix.inputs.bash-lib.overlay + epnix.overlays.default + ]; }; } diff --git a/pkgs/epnix/tools/phoebus/deps/default.nix b/pkgs/epnix/tools/phoebus/deps/default.nix index cafe6038..ed7a43da 100644 --- a/pkgs/epnix/tools/phoebus/deps/default.nix +++ b/pkgs/epnix/tools/phoebus/deps/default.nix @@ -58,7 +58,7 @@ stdenv.mkDerivation { outputHashAlgo = "sha256"; outputHashMode = "recursive"; - outputHash = "sha256-9MJdmIVAqjPW5ihZYWCh+zsWlxrtoHBH7NFwPh01pRc="; + outputHash = "sha256-6pUHn6tU54e4r5tJwoailVX3YEqO9BouWM3fweAdyt8="; doCheck = false; diff --git a/pkgs/epnix/tools/phoebus/olog/default.nix b/pkgs/epnix/tools/phoebus/olog/default.nix index 9bf50d96..213667ea 100644 --- a/pkgs/epnix/tools/phoebus/olog/default.nix +++ b/pkgs/epnix/tools/phoebus/olog/default.nix @@ -56,7 +56,7 @@ in outputHashAlgo = "sha256"; outputHashMode = "recursive"; - outputHash = "sha256-feT4qSN7B+KSUIoCmBkjDjsib39QfUW/4PxsU3Jx2Gs="; + outputHash = "sha256-40n06R2KBuuzqvVq1bWsd1jjQtcNQfK/4RbgtFmxTf8="; doCheck = false; }; From c1de3d7252ac1772be651a4a09186e88e0a6f59f Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 13:33:43 +0100 Subject: [PATCH 40/74] pkgs/epics-base: fix "buffer overflow detected" runtime issue it seems that _FORTIFY_SOURCE=3 caused a miscompilation, fall back to _FORTIFY_SOURCE=2 --- pkgs/epnix/epics-base/default.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/pkgs/epnix/epics-base/default.nix b/pkgs/epnix/epics-base/default.nix index 58524070..988ee2af 100644 --- a/pkgs/epnix/epics-base/default.nix +++ b/pkgs/epnix/epics-base/default.nix @@ -136,6 +136,12 @@ in # TODO: Some tests fail doCheck = false; + # _FORTIFY_SOURCE=3 causes a buffer overflow in some cases: + # *** buffer overflow detected ***: terminated + # + # Fall back to _FORTIFY_SOURCE=2 + hardeningDisable = ["fortify3"]; + meta = { description = "The Experimental Physics and Industrial Control System"; homepage = "https://epics-controls.org/"; From 90a984b913cc96908082de6ff01f361f58b9d474 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 13:36:29 +0100 Subject: [PATCH 41/74] pkgs/book: switch quarto -> quartoMinimal has a lot less dependencies, we didn't use any of them --- flake.nix | 2 +- pkgs/book/default.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index f9291101..63c68160 100644 --- a/flake.nix +++ b/flake.nix @@ -56,7 +56,7 @@ category = "development tools"; } { - package = pkgs.quarto; + package = pkgs.quartoMinimal; category = "development tools"; } { diff --git a/pkgs/book/default.nix b/pkgs/book/default.nix index bd519688..23fcc96d 100644 --- a/pkgs/book/default.nix +++ b/pkgs/book/default.nix @@ -3,7 +3,7 @@ lib, epnixLib, epnix, - quarto, + quartoMinimal, writeText, documentedEpnixPkgs ? epnix, iocConfig ? {}, @@ -70,7 +70,7 @@ in name = "epnix-book"; src = ../../doc; - nativeBuildInputs = [quarto]; + nativeBuildInputs = [quartoMinimal]; dontConfigure = true; From 56f1caaac4d748caf1153076b45daa180707c360 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 13:44:10 +0100 Subject: [PATCH 42/74] gitignore: add some history files --- .gitignore | 6 ++++++ templates/top/.gitignore | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/.gitignore b/.gitignore index 5e40e6e5..faaae889 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,9 @@ outputs # Some files generated by CI, to ensure the working tree is clean on CI /manpage /public + +# Created by running IOCs +.iocsh_history + +# Created by running NixOS tests in interactive mode +.nixos-test-history diff --git a/templates/top/.gitignore b/templates/top/.gitignore index 4030d251..abf0cd0f 100644 --- a/templates/top/.gitignore +++ b/templates/top/.gitignore @@ -27,3 +27,9 @@ envPaths # Compilation database generated by bear or other compile_commands.json + +# Created by running IOCs +.iocsh_history + +# Created by running NixOS tests in interactive mode +.nixos-test-history From 64e8185130ed2a632d27501c51cc1c3a5da724f7 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 13:47:03 +0100 Subject: [PATCH 43/74] templates/top: fix wrong commented overlay option --- templates/top/flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templates/top/flake.nix b/templates/top/flake.nix index 3be88393..b0aaa1d8 100644 --- a/templates/top/flake.nix +++ b/templates/top/flake.nix @@ -33,7 +33,7 @@ # If you have a support module as a separate EPNix repository, # uncomment this line to make the package available: # --- - #overlays = [inputs.mySupportModule.overlays.default]; + #nixpkgs.overlays = [inputs.mySupportModule.overlays.default]; epnix = { inherit inputs; From 81121cad704539193d1f00b04c96eed220260780 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 14:03:00 +0100 Subject: [PATCH 44/74] nixos/phoebus/alarm: don't set kafka address by default --- nixos/modules/phoebus/alarm-logger.nix | 2 -- nixos/modules/phoebus/alarm-server.nix | 2 -- 2 files changed, 4 deletions(-) diff --git a/nixos/modules/phoebus/alarm-logger.nix b/nixos/modules/phoebus/alarm-logger.nix index 4e81d31d..47af9914 100644 --- a/nixos/modules/phoebus/alarm-logger.nix +++ b/nixos/modules/phoebus/alarm-logger.nix @@ -87,8 +87,6 @@ in { "bootstrap.servers" = lib.mkOption { description = "Location of the Kafka server"; type = lib.types.str; - default = "localhost:${toString config.services.apache-kafka.port}"; - defaultText = lib.literalExpression ''"localhost:''${toString config.services.apache-kafka.port}"''; }; date_span_units = lib.mkOption { diff --git a/nixos/modules/phoebus/alarm-server.nix b/nixos/modules/phoebus/alarm-server.nix index 2345f1a0..d7ed08f4 100644 --- a/nixos/modules/phoebus/alarm-server.nix +++ b/nixos/modules/phoebus/alarm-server.nix @@ -69,8 +69,6 @@ in { "org.phoebus.applications.alarm/server" = lib.mkOption { description = "Kafka server host:port"; type = lib.types.str; - default = "localhost:${toString config.services.apache-kafka.port}"; - defaultText = lib.literalExpression ''"localhost:''${toString config.services.apache-kafka.port}"''; }; # Waiting for: https://github.com/ControlSystemStudio/phoebus/issues/2843 From e97802d3bf6677a691af40925aa4c81d3247ede5 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 8 Mar 2024 14:04:25 +0100 Subject: [PATCH 45/74] nixos/tests/phoebus/alarm: use Kraft-mode Kafka --- nixos/tests/phoebus/alarm.nix | 74 +++++++++++++++++------------------ 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/nixos/tests/phoebus/alarm.nix b/nixos/tests/phoebus/alarm.nix index 4a5840b1..5db6467b 100644 --- a/nixos/tests/phoebus/alarm.nix +++ b/nixos/tests/phoebus/alarm.nix @@ -1,22 +1,17 @@ # This tests both the phoebus-alarm-server, and phoebus-alarm-logger services -{ - epnixLib, - lib, - pkgs, - ... -}: { +{epnixLib, ...}: { name = "phoebus-alarm-server-simple-check"; meta.maintainers = with epnixLib.maintainers; [minijackson]; nodes = { - client = { + client = {pkgs, ...}: { environment = { sessionVariables.EPICS_CA_ADDR_LIST = ["ioc"]; systemPackages = [pkgs.kcat pkgs.epnix.epics-base]; }; }; - ioc = { + ioc = {pkgs, ...}: { systemd.services.ioc = { description = "Test IOC to be monitored with the Phoebus Alarm server"; serviceConfig.ExecStart = "${pkgs.epnix.epics-base}/bin/softIoc -S -d ${./ioc.db}"; @@ -32,12 +27,13 @@ server = { config, + lib, pkgs, ... }: let - kafkaPort = toString config.services.apache-kafka.port; serverAddr = "192.168.1.3"; - kafkaListenSockAddr = "${serverAddr}:${kafkaPort}"; + kafkaListenSockAddr = "${serverAddr}:9092"; + kafkaControllerListenSockAddr = "${serverAddr}:9093"; in { services.phoebus-alarm-server = { enable = true; @@ -51,43 +47,43 @@ services.phoebus-alarm-logger.settings."bootstrap.servers" = kafkaListenSockAddr; - services.elasticsearch = { - enable = true; - package = pkgs.elasticsearch7; - }; - - # Single-server Kafka setup services.apache-kafka = { enable = true; - logDirs = ["/var/lib/apache-kafka"]; - # Tell Apache Kafka to listen on this IP address - # If you don't have a DNS domain name, it's best to set a specific, non-local IP address. - extraProperties = '' - listeners=PLAINTEXT://${kafkaListenSockAddr} - offsets.topic.replication.factor=1 - transaction.state.log.replication.factor=1 - transaction.state.log.min.isr=1 - ''; - }; + clusterId = "Wwbk0wwKTueL2hJD0IGGdQ"; + formatLogDirs = true; + settings = { + listeners = [ + "PLAINTEXT://${kafkaListenSockAddr}" + "CONTROLLER://${kafkaControllerListenSockAddr}" + ]; + "listener.security.protocol.map" = [ + "PLAINTEXT:PLAINTEXT" + "CONTROLLER:PLAINTEXT" + ]; + "controller.quorum.voters" = [ + "1@${kafkaControllerListenSockAddr}" + ]; + "controller.listener.names" = ["CONTROLLER"]; - systemd.services.apache-kafka = { - after = ["zookeeper.service"]; - unitConfig.StateDirectory = "apache-kafka"; + "node.id" = 1; + "process.roles" = ["broker" "controller"]; + + "log.dirs" = ["/var/lib/apache-kafka"]; + "offsets.topic.replication.factor" = 1; + "transaction.state.log.replication.factor" = 1; + "transaction.state.log.min.isr" = 1; + }; }; - services.zookeeper = { + systemd.services.apache-kafka.unitConfig.StateDirectory = ["apache-kafka"]; + + networking.firewall.allowedTCPPorts = [9092]; + + services.elasticsearch = { enable = true; - extraConf = '' - # Port conflicts by default with phoebus-alarm-logger's port - admin.enableServer=false - ''; + package = pkgs.elasticsearch7; }; - # Open kafka to the outside world - networking.firewall.allowedTCPPorts = [ - config.services.apache-kafka.port - ]; - nixpkgs.config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [ # Elasticsearch can be used as an SSPL-licensed software, which is From 0eba5e148abe01be3c4ea1233fbe86e0fc088d03 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 5 Apr 2024 09:48:06 +0200 Subject: [PATCH 46/74] doc/nixos/phoebus-alarm: use kraft mode Kafka --- doc/nixos/guides/phoebus-alarm.md | 74 +++++++++++++++++-------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/doc/nixos/guides/phoebus-alarm.md b/doc/nixos/guides/phoebus-alarm.md index 47c2ef9d..6c941b50 100644 --- a/doc/nixos/guides/phoebus-alarm.md +++ b/doc/nixos/guides/phoebus-alarm.md @@ -29,15 +29,17 @@ The Phoebus Alarm Logging Service can also be called the Phoebus Alarm Logger. # Single server Phoebus Alarm setup To configure Phoebus Alarm, Phoebus Alarm Logger, Apache Kafka, and ElasticSearch on a single server, -add this to your configuration: +add this to your configuration, +while taking care of replacing the IP address +and Kafka's `clusterId`: ``` nix -{config, lib, ...}: let - kafkaPort = toString config.services.apache-kafka.port; - # Replace this with your machine's IP address +{lib, pkgs, ...}: let + # Replace this with your machine's external IP address # or DNS domain name ip = "192.168.1.42"; - kafkaListenSockAddr = "${ip}:${kafkaPort}"; + kafkaListenSockAddr = "${ip}:9092"; + kafkaControllerListenSockAddr = "${ip}:9093"; in { # The Phoebus Alarm server also automatically enables the Phoebus Alarm Logger services.phoebus-alarm-server = { @@ -48,43 +50,48 @@ in { services.phoebus-alarm-logger.settings."bootstrap.servers" = kafkaListenSockAddr; - services.elasticsearch = { - enable = true; - package = pkgs.elasticsearch7; - }; - # Single-server Kafka setup services.apache-kafka = { enable = true; - logDirs = ["/var/lib/apache-kafka"]; - # Tell Apache Kafka to listen on this IP address - # If you don't have a DNS domain name, it's best to set a specific, non-local IP address. - extraProperties = '' - listeners=PLAINTEXT://${kafkaListenSockAddr} - offsets.topic.replication.factor=1 - transaction.state.log.replication.factor=1 - transaction.state.log.min.isr=1 - ''; + # Replace with a randomly generated uuid. You can get one by running: + # nix shell 'nixpkgs#apacheKafka' -c kafka-storage.sh random-uuid + clusterId = "xxxxxxxxxxxxxxxxxxxxxx"; + formatLogDirs = true; + settings = { + listeners = [ + "PLAINTEXT://${kafkaListenSockAddr}" + "CONTROLLER://${kafkaControllerListenSockAddr}" + ]; + # Adapt depending on your security constraints + "listener.security.protocol.map" = [ + "PLAINTEXT:PLAINTEXT" + "CONTROLLER:PLAINTEXT" + ]; + "controller.quorum.voters" = [ + "1@${kafkaControllerListenSockAddr}" + ]; + "controller.listener.names" = ["CONTROLLER"]; + + "node.id" = 1; + "process.roles" = ["broker" "controller"]; + + "log.dirs" = ["/var/lib/apache-kafka"]; + "offsets.topic.replication.factor" = 1; + "transaction.state.log.replication.factor" = 1; + "transaction.state.log.min.isr" = 1; + }; }; - systemd.services.apache-kafka = { - after = ["zookeeper.service"]; - unitConfig.StateDirectory = "apache-kafka"; - }; + systemd.services.apache-kafka.unitConfig.StateDirectory = "apache-kafka"; + + # Open kafka to the outside world + networking.firewall.allowedTCPPorts = [9092]; - services.zookeeper = { + services.elasticsearch = { enable = true; - extraConf = '' - # Port conflicts by default with phoebus-alarm-logger's port - admin.enableServer=false - ''; + package = pkgs.elasticsearch7; }; - # Open kafka to the outside world - networking.firewall.allowedTCPPorts = [ - config.services.apache-kafka.port - ]; - # Elasticsearch, needed by Phoebus Alarm Logger, is not free software (SSPL | Elastic License). # To accept the license, add the code below: nixpkgs.config.allowUnfreePredicate = pkg: @@ -205,4 +212,3 @@ Here is a list of options you might want to set: ::: callout-warning Currently, Phoebus Alarm Server only supports plain SMTP. ::: - From f6b9a09fae4fec9740f821b35ec79c89c433f7a8 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 5 Apr 2024 10:31:14 +0200 Subject: [PATCH 47/74] pkgs/psu-simulator: keep meta.mainProgram This fixes a warning in the StreamDevice check: > Package psu_simulator does not have the meta.mainProgram attribute --- pkgs/doc-support/psu-simulator/default.nix | 9 ++++++--- pkgs/epnix/tools/lewis/lib.nix | 1 - 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/pkgs/doc-support/psu-simulator/default.nix b/pkgs/doc-support/psu-simulator/default.nix index 2a850e08..ec2776ec 100644 --- a/pkgs/doc-support/psu-simulator/default.nix +++ b/pkgs/doc-support/psu-simulator/default.nix @@ -3,12 +3,15 @@ epnix, epnixLib, }: +# Use recursiveUpdate so that it doesn't override meta.mainProgram +lib.recursiveUpdate (epnix.mkLewisSimulator { - name = "psu_simulator"; - package = "psu_simulator"; + name = "psu-simulator"; source = ./.; + package = "psu_simulator"; + device = "psu_simulator"; }) -// { +{ pname = "psu_simulator"; version = "0.2.0"; diff --git a/pkgs/epnix/tools/lewis/lib.nix b/pkgs/epnix/tools/lewis/lib.nix index f6a61586..e90fd59e 100644 --- a/pkgs/epnix/tools/lewis/lib.nix +++ b/pkgs/epnix/tools/lewis/lib.nix @@ -1,5 +1,4 @@ { - lib, epnix, writeShellApplication, }: { From 3f5615f88892ddd0eb109970bc37db4d8bb05b1f Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 5 Apr 2024 16:35:43 +0200 Subject: [PATCH 48/74] lib/documentation: don't require licenses to have an URL lib.licenses.free for example doesn't have an URL Fixes #46 --- lib/documentation.nix | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/documentation.nix b/lib/documentation.nix index 090bcad2..f3a6e1b0 100644 --- a/lib/documentation.nix +++ b/lib/documentation.nix @@ -46,14 +46,21 @@ in mapRecursiveDrvsToList' "" f attrset; + maybeUrl = text: destination: + if destination == null + then text + else "[${text}](${destination})"; + + licenseLink = license: self.maybeUrl license.fullName (license.url or null); + licenseList = pkg: if lib.isList pkg.meta.license then lib.concatMapStringsSep "\n" - (license: " - [${license.fullName}](${license.url})") + (license: " - ${self.licenseLink license}") pkg.meta.license - else " - [${pkg.meta.license.fullName}](${pkg.meta.license.url})"; + else " - ${self.licenseLink pkg.meta.license}"; maintainerInfo = maintainer: if maintainer ? github From a1c758e66e8d4f5089b94c43e2afb2a2f48ad7d6 Mon Sep 17 00:00:00 2001 From: Patrick Hilhorst <philhorst@highvolteng.com> Date: Mon, 15 Apr 2024 13:15:18 +0000 Subject: [PATCH 49/74] Add Patrick Hilhorst (@synthetica9) as maintainer --- lib/maintainers/maintainer-list.nix | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/maintainers/maintainer-list.nix b/lib/maintainers/maintainer-list.nix index d7f1d86a..b875cc1e 100644 --- a/lib/maintainers/maintainer-list.nix +++ b/lib/maintainers/maintainer-list.nix @@ -66,4 +66,10 @@ See `<nixpkgs/maintainers/scripts/check-maintainer-github-handles.sh>` for an ex email = "stephane.tzvetkov@cea.fr"; name = "Stéphane Tzvetkov"; }; + synthetica = { + email = "philhorst@highvolteng.com"; + name = "Patrick Hilhorst"; + github = "Synthetica9"; + githubId = 7075751; + }; } From 569e62943f6dc7f277411310c84e12d850d2d3e8 Mon Sep 17 00:00:00 2001 From: Patrick Hilhorst <philhorst@highvolteng.com> Date: Mon, 15 Apr 2024 13:16:56 +0000 Subject: [PATCH 50/74] Add autoparamDriver support module https://epics.cosylab.com/documentation/autoparamDriver/ https://github.com/Cosylab/autoparamDriver --- pkgs/default.nix | 1 + .../epnix/support/autoparamDriver/default.nix | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 pkgs/epnix/support/autoparamDriver/default.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index 547eed24..d1dc2626 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -31,6 +31,7 @@ in support = recurseExtensible (_self: { asyn = callPackage ./epnix/support/asyn {}; + autoparamDriver = callPackage ./epnix/support/autoparamDriver {}; autosave = callPackage ./epnix/support/autosave {}; calc = callPackage ./epnix/support/calc {}; devlib2 = callPackage ./epnix/support/devlib2 {}; diff --git a/pkgs/epnix/support/autoparamDriver/default.nix b/pkgs/epnix/support/autoparamDriver/default.nix new file mode 100644 index 00000000..359b20a4 --- /dev/null +++ b/pkgs/epnix/support/autoparamDriver/default.nix @@ -0,0 +1,29 @@ +{ + mkEpicsPackage, + fetchFromGitHub, + epnix, + lib, + epnixLib, +}: +mkEpicsPackage rec { + pname = "autoparamDriver"; + version = "2.0.0"; + + varname = "AUTOPARAM"; + + src = fetchFromGitHub { + owner = "Cosylab"; + repo = pname; + rev = "v${version}"; + hash = "sha256-J2fy/pMwrbwVFULfANuJBl6iE3wju5bQkhkxxk8zRYs="; + }; + + propagatedBuildInputs = with epnix.support; [asyn]; + + meta = { + description = "An asyn driver that creates parameters dynamically based on content of record links"; + homepage = "https://epics.cosylab.com/documentation/autoparamDriver/"; + license = lib.licenses.mit; + maintainers = with epnixLib.maintainers; [synthetica]; + }; +} From 308cfab4822db64e94d499e904405eacab3418ef Mon Sep 17 00:00:00 2001 From: Patrick Hilhorst <philhorst@highvolteng.com> Date: Mon, 15 Apr 2024 13:17:45 +0000 Subject: [PATCH 51/74] Add adsDriver support module https://epics.cosylab.com/documentation/adsDriver/ https://github.com/Cosylab/adsDriver --- pkgs/default.nix | 1 + pkgs/epnix/support/adsDriver/default.nix | 36 ++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 pkgs/epnix/support/adsDriver/default.nix diff --git a/pkgs/default.nix b/pkgs/default.nix index d1dc2626..accd1ca0 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -30,6 +30,7 @@ in # EPICS support modules support = recurseExtensible (_self: { + adsDriver = callPackage ./epnix/support/adsDriver {}; asyn = callPackage ./epnix/support/asyn {}; autoparamDriver = callPackage ./epnix/support/autoparamDriver {}; autosave = callPackage ./epnix/support/autosave {}; diff --git a/pkgs/epnix/support/adsDriver/default.nix b/pkgs/epnix/support/adsDriver/default.nix new file mode 100644 index 00000000..1be4ed89 --- /dev/null +++ b/pkgs/epnix/support/adsDriver/default.nix @@ -0,0 +1,36 @@ +{ + mkEpicsPackage, + fetchFromGitHub, + epnix, + boost, + epnixLib, + lib, +}: +mkEpicsPackage rec { + pname = "adsDriver"; + version = "3.1.0"; + + varname = "ADS_DRIVER"; + + src = fetchFromGitHub { + owner = "Cosylab"; + repo = pname; + rev = "v${version}"; + fetchSubmodules = true; + hash = "sha256-Ruzi+H8MmIgv23pzFXZlvkk3HtbDzQ9LTTVzmeGWrSI=="; + }; + + nativeBuildInputs = [boost]; + buildInputs = [boost]; + propagatedBuildInputs = with epnix.support; [ + asyn + autoparamDriver + ]; + + meta = { + description = "EPICS support module for integrating Beckhoff PLC using the ADS protocol"; + homepage = "https://epics.cosylab.com/documentation/adsDriver/"; + license = lib.licenses.mit; + maintainers = with epnixLib.maintainers; [synthetica]; + }; +} From 25d4892624713bffe96a7ea0626518b281c4f74e Mon Sep 17 00:00:00 2001 From: Vivien Loriot <vivien.loriot@cea.fr> Date: Mon, 22 Apr 2024 15:30:23 +0200 Subject: [PATCH 52/74] gtest: init at 1.0.1 and add myself as maintainer --- lib/maintainers/maintainer-list.nix | 4 ++++ pkgs/default.nix | 1 + pkgs/epnix/support/gtest/default.nix | 29 ++++++++++++++++++++++++++++ 3 files changed, 34 insertions(+) create mode 100644 pkgs/epnix/support/gtest/default.nix diff --git a/lib/maintainers/maintainer-list.nix b/lib/maintainers/maintainer-list.nix index b875cc1e..8a293113 100644 --- a/lib/maintainers/maintainer-list.nix +++ b/lib/maintainers/maintainer-list.nix @@ -72,4 +72,8 @@ See `<nixpkgs/maintainers/scripts/check-maintainer-github-handles.sh>` for an ex github = "Synthetica9"; githubId = 7075751; }; + vivien = { + email = "vivien.loriot@cea.fr"; + name = "Vivien Loriot"; + }; } diff --git a/pkgs/default.nix b/pkgs/default.nix index c81dfa20..f25b8e18 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -38,6 +38,7 @@ in calc = callPackage ./epnix/support/calc {}; devlib2 = callPackage ./epnix/support/devlib2 {}; epics-systemd = callPackage ./epnix/support/epics-systemd {}; + gtest = callPackage ./epnix/support/gtest {}; ipac = callPackage ./epnix/support/ipac {}; modbus = callPackage ./epnix/support/modbus {}; mrfioc2 = callPackage ./epnix/support/mrfioc2 {}; diff --git a/pkgs/epnix/support/gtest/default.nix b/pkgs/epnix/support/gtest/default.nix new file mode 100644 index 00000000..6b83bdbd --- /dev/null +++ b/pkgs/epnix/support/gtest/default.nix @@ -0,0 +1,29 @@ +{ + lib, + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage { + pname = "gtest"; + version = "1.0.1"; + varname = "GTEST"; + + src = fetchFromGitHub { + owner = "epics-modules"; + repo = "gtest"; + rev = "v1.0.1"; + hash = "sha256-cDZ4++AkUiOvsw4KkobyqKWLk2GzUSdDdWjLL7dr1ac="; + }; + + inherit local_release local_config_site; + + meta = { + description = "EPICS module to adds the Google Test and Google Mock frameworks to EPICS"; + homepage = "https://github.com/epics-modules/gtest"; + license = epnixLib.licenses.epics; + maintainers = with epnixLib.maintainers; [vivien]; + }; +} From f663d91e269c7a796270fb4288aa8c574038ffdb Mon Sep 17 00:00:00 2001 From: Vivien Loriot <vivien.loriot@cea.fr> Date: Mon, 22 Apr 2024 15:31:27 +0200 Subject: [PATCH 53/74] opcua: init at 0.10.0-dev --- pkgs/default.nix | 1 + pkgs/epnix/support/opcua/default.nix | 53 +++++++++++++++++++++++++ pkgs/epnix/support/opcua/dir_xml2.patch | 29 ++++++++++++++ 3 files changed, 83 insertions(+) create mode 100644 pkgs/epnix/support/opcua/default.nix create mode 100644 pkgs/epnix/support/opcua/dir_xml2.patch diff --git a/pkgs/default.nix b/pkgs/default.nix index f25b8e18..7a8353de 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -42,6 +42,7 @@ in ipac = callPackage ./epnix/support/ipac {}; modbus = callPackage ./epnix/support/modbus {}; mrfioc2 = callPackage ./epnix/support/mrfioc2 {}; + opcua = callPackage ./epnix/support/opcua {}; pvxs = callPackage ./epnix/support/pvxs {}; seq = callPackage ./epnix/support/seq {}; snmp = callPackage ./epnix/support/snmp {}; diff --git a/pkgs/epnix/support/opcua/default.nix b/pkgs/epnix/support/opcua/default.nix new file mode 100644 index 00000000..73eaa9f3 --- /dev/null +++ b/pkgs/epnix/support/opcua/default.nix @@ -0,0 +1,53 @@ +{ + lib, + epnixLib, + mkEpicsPackage, + fetchFromGitHub, + pkg-config, + epnix, + open62541, + openssl, + libxml2, + local_config_site ? {}, + local_release ? {}, +}: +mkEpicsPackage { + pname = "opcua"; + version = "0.10.0-dev"; + varname = "OPCUA"; + + src = fetchFromGitHub { + owner = "epics-modules"; + repo = "opcua"; + rev = "3d10053"; + hash = "sha256-EQra8PesO7Rlhj+pBlAfiqh5yjJwRkuh7gbGziY58iI="; + }; + + inherit local_release; + local_config_site = + local_config_site + // { + OPEN62541 = "${open62541}"; + OPEN62541_DEPLOY_MODE = "PROVIDED"; + OPEN62541_LIB_DIR = "${open62541}/lib"; + OPEN62541_SHRLIB_DIR = "${open62541}/lib"; + #for the moment, we're not able to use the last version of openssl to manage a safety connection with the open62541 librairy + OPEN62541_USE_CRYPTO = "NO"; + OPEN62541_USE_XMLPARSER = "YES"; + }; + + patches = [./dir_xml2.patch]; + + depsBuildBuild = [pkg-config]; + nativeBuildInputs = [pkg-config open62541 openssl libxml2]; + buildInputs = [open62541 openssl libxml2]; + propagatedNativeBuildInputs = [pkg-config]; + propagatedBuildInputs = [libxml2] ++ (with epnix.support; [gtest]); + + meta = { + description = "EPICS support for communication with OPC UA protocol"; + homepage = "https://github.com/epics-modules/opcua"; + license = epnixLib.licenses.epics; + maintainers = with epnixLib.maintainers; [vivien]; + }; +} diff --git a/pkgs/epnix/support/opcua/dir_xml2.patch b/pkgs/epnix/support/opcua/dir_xml2.patch new file mode 100644 index 00000000..1184c861 --- /dev/null +++ b/pkgs/epnix/support/opcua/dir_xml2.patch @@ -0,0 +1,29 @@ +diff --git a/devOpcuaSup/open62541/Makefile.config b/devOpcuaSup/open62541/Makefile.config +index d1b82cb..5d81dc2 100644 +--- a/devOpcuaSup/open62541/Makefile.config ++++ b/devOpcuaSup/open62541/Makefile.config +@@ -25,7 +25,7 @@ USR_CXXFLAGS += -DHAS_XMLPARSER + ifneq ($(filter -D_MINGW,$(OP_SYS_CPPFLAGS)),) + USR_INCLUDES += -I$(MSYSTEM_PREFIX)/include/libxml2 + else +-USR_INCLUDES += -I/usr/include/libxml2 ++USR_INCLUDES += `pkg-config --cflags libxml-2.0` + endif + + opcua_SRCS += Session.cpp +diff --git a/unitTestApp/src/Makefile b/unitTestApp/src/Makefile +index c52a727..8c2556b 100644 +--- a/unitTestApp/src/Makefile ++++ b/unitTestApp/src/Makefile +@@ -28,9 +28,9 @@ USR_CXXFLAGS += -DHAS_SECURITY + endif + ifeq ($($(CLIENT)_USE_XMLPARSER),YES) + USR_CXXFLAGS += -DHAS_XMLPARSER +-USR_INCLUDES_Linux += -I/usr/include/libxml2 ++USR_INCLUDES += `pkg-config --cflags libxml-2.0` + ifneq ($(filter -D_MINGW,$(OP_SYS_CPPFLAGS)),) +-USR_INCLUDES += -I$(MSYSTEM_PREFIX)/include/libxml2 ++USR_INCLUDES += `pkg-config --cflags libxml-2.0` + USR_SYS_LIBS += xml2 + endif + endif From 76ad5ecc2ddedb262080d60ab3400a9c932eb393 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Thu, 23 May 2024 09:00:32 +0200 Subject: [PATCH 54/74] github: add backport action --- .github/workflows/backport.yml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/backport.yml diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000..d1ae9068 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,33 @@ +name: Backport +on: + pull_request_target: + types: [closed, labeled] + +# WARNING: +# When extending this action, be aware that $GITHUB_TOKEN allows write access to +# the GitHub repository. This means that it should not evaluate user input in a +# way that allows code injection. + +permissions: + contents: read + +jobs: + backport: + permissions: + contents: write # for korthout/backport-action to create branch + pull-requests: write # for korthout/backport-action to create PR to backport + name: Backport Pull Request + if: github.repository_owner == 'epics-extensions' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + with: + ref: ${{ github.event.pull_request.head.sha }} + - name: Create backport PRs + uses: korthout/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0 + with: + # Config README: https://github.com/korthout/backport-action#backport-action + branch_name: backport/${pull_number}-to-${target_branch} + copy_labels_pattern: 'severity:\ssecurity' + pull_description: |- + Bot-based backport to `${target_branch}`, triggered by a label in #${pull_number}. From f568452a885669a0361457eb6ceb021ef9316d2e Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Thu, 23 May 2024 09:20:42 +0200 Subject: [PATCH 55/74] dependabot: init for updating GitHub actions --- .github/dependabot.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..5ace4600 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" From 3cd82a6f57e957b7f4bcdcbab0bdca38b40ff1e2 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Thu, 23 May 2024 10:16:57 +0200 Subject: [PATCH 56/74] gitlab-ci: make pipeline/jobs interruptible --- .gitlab-ci.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 84cb8a60..43c0ff54 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,9 @@ +workflow: + auto_cancel: + on_new_commit: interruptible + default: + interruptible: true tags: - nix From ef17941879137b6514edfbcf44b87824974f2d38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 11:58:43 +0000 Subject: [PATCH 57/74] build(deps): bump actions/configure-pages from 4.0.0 to 5.0.0 Bumps [actions/configure-pages](https://github.com/actions/configure-pages) from 4.0.0 to 5.0.0. - [Release notes](https://github.com/actions/configure-pages/releases) - [Commits](https://github.com/actions/configure-pages/compare/1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d...983d7736d9b0ae728b81ab479565c72886d7745b) --- updated-dependencies: - dependency-name: actions/configure-pages dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/book-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index bf929f35..e15f7781 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -30,7 +30,7 @@ jobs: nix build '.#book' --print-build-logs cp -Lr --no-preserve=mode,ownership ./result/ ./book - name: Setup Pages - uses: actions/configure-pages@1f0c5cde4bc74cd7e1254d0cb4de8d49e9068c7d # v4.0.0 + uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Upload artifact uses: actions/upload-pages-artifact@0252fc4ba7626f0298f0cf00902a25c6afc77fa8 # v3.0.0 with: From 93cbf2b80ad3878611138267c99c83facdbaa543 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 11:58:46 +0000 Subject: [PATCH 58/74] build(deps): bump actions/checkout from 4.1.1 to 4.1.6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.1 to 4.1.6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/b4ffde65f46336ab88eb53be808477a3936bae11...a5ac7e51b41094c92402da3b24376905380afc29) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/book-gh-pages.yml | 2 +- .github/workflows/editorconfig.yml | 2 +- .github/workflows/formatting.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index bf929f35..6191ac8a 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -23,7 +23,7 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Build documentation book" run: | diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml index a201b54e..5c67a4ee 100644 --- a/.github/workflows/editorconfig.yml +++ b/.github/workflows/editorconfig.yml @@ -10,7 +10,7 @@ jobs: editorconfig: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Check EditorConfig" run: nix run 'nixpkgs#eclint' --inputs-from . diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index cc41641e..2efa962c 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -10,7 +10,7 @@ jobs: alejandra: runs-on: ubuntu-latest steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 - name: "Check Formatting" run: nix fmt -- --check . From 6874d4e26e9f971ff9e9003e1de285b9a5c05143 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 11:58:55 +0000 Subject: [PATCH 59/74] build(deps): bump actions/deploy-pages from 4.0.3 to 4.0.5 Bumps [actions/deploy-pages](https://github.com/actions/deploy-pages) from 4.0.3 to 4.0.5. - [Release notes](https://github.com/actions/deploy-pages/releases) - [Commits](https://github.com/actions/deploy-pages/compare/87c3283f01cd6fe19a0ab93a23b2f6fcba5a8e42...d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e) --- updated-dependencies: - dependency-name: actions/deploy-pages dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/book-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index bf929f35..5b170887 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -37,4 +37,4 @@ jobs: path: './book' - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@87c3283f01cd6fe19a0ab93a23b2f6fcba5a8e42 # v4.0.3 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 From 6d8b52db84771e6ef4a77251cf9a77d80e96d1bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 12:02:23 +0000 Subject: [PATCH 60/74] build(deps): bump cachix/install-nix-action from 25 to 27 Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 25 to 27. - [Release notes](https://github.com/cachix/install-nix-action/releases) - [Commits](https://github.com/cachix/install-nix-action/compare/6004951b182f8860210c8d6f0d808ec5b1a33d28...ba0dd844c9180cbf77aa72a116d6fbc515d0e87b) --- updated-dependencies: - dependency-name: cachix/install-nix-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/book-gh-pages.yml | 2 +- .github/workflows/editorconfig.yml | 2 +- .github/workflows/formatting.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index 6191ac8a..5b0ba086 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -24,7 +24,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Build documentation book" run: | nix build '.#book' --print-build-logs diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml index 5c67a4ee..3c52c652 100644 --- a/.github/workflows/editorconfig.yml +++ b/.github/workflows/editorconfig.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Check EditorConfig" run: nix run 'nixpkgs#eclint' --inputs-from . diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index 2efa962c..f672e922 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -11,6 +11,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 - - uses: cachix/install-nix-action@6004951b182f8860210c8d6f0d808ec5b1a33d28 # v25 + - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Check Formatting" run: nix fmt -- --check . From e37f748ab7b1f97fe469c74447fdea605186c5ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 May 2024 12:08:15 +0000 Subject: [PATCH 61/74] build(deps): bump actions/upload-pages-artifact from 3.0.0 to 3.0.1 Bumps [actions/upload-pages-artifact](https://github.com/actions/upload-pages-artifact) from 3.0.0 to 3.0.1. - [Release notes](https://github.com/actions/upload-pages-artifact/releases) - [Commits](https://github.com/actions/upload-pages-artifact/compare/0252fc4ba7626f0298f0cf00902a25c6afc77fa8...56afc609e74202658d3ffba0e8f6dda462b719fa) --- updated-dependencies: - dependency-name: actions/upload-pages-artifact dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/book-gh-pages.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index 0992ec7b..d97abc9c 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -32,7 +32,7 @@ jobs: - name: Setup Pages uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0 - name: Upload artifact - uses: actions/upload-pages-artifact@0252fc4ba7626f0298f0cf00902a25c6afc77fa8 # v3.0.0 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3.0.1 with: path: './book' - name: Deploy to GitHub Pages From 72bed6147f692d5ef75c59ca0009fc2fc1643255 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Fri, 24 May 2024 12:57:42 +0200 Subject: [PATCH 62/74] phoebus-client: add webkit to openjfx fixes some applications, like the Log Entry Table, which couldn't be opened --- pkgs/epnix/tools/phoebus/client/default.nix | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pkgs/epnix/tools/phoebus/client/default.nix b/pkgs/epnix/tools/phoebus/client/default.nix index 1c8de60e..44c58ad1 100644 --- a/pkgs/epnix/tools/phoebus/client/default.nix +++ b/pkgs/epnix/tools/phoebus/client/default.nix @@ -8,6 +8,7 @@ copyDesktopItems, epnix, jdk, + openjfx, }: let buildDate = "2022-02-24T07:56:00Z"; in @@ -21,6 +22,14 @@ in copyDesktopItems makeWrapper (epnix.phoebus-setup-hook.override {jdk = jdk.override {enableJavaFX = true;};}) + (epnix.phoebus-setup-hook.override { + jdk = jdk.override { + enableJavaFX = true; + openjfx = openjfx.override { + withWebKit = true; + }; + }; + }) ]; desktopItems = [ From d93270a85d32886500a7da096355743388c4a35d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 08:59:09 +0000 Subject: [PATCH 63/74] build(deps): bump korthout/backport-action from 2.5.0 to 3.0.0 Bumps [korthout/backport-action](https://github.com/korthout/backport-action) from 2.5.0 to 3.0.0. - [Release notes](https://github.com/korthout/backport-action/releases) - [Commits](https://github.com/korthout/backport-action/compare/ef20d86abccbac3ee3a73cb2efbdc06344c390e5...7e7cb1977d64d20339e8fdec12c0a1a065371de7) --- updated-dependencies: - dependency-name: korthout/backport-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index d1ae9068..3958c0b0 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@ef20d86abccbac3ee3a73cb2efbdc06344c390e5 # v2.5.0 + uses: korthout/backport-action@7e7cb1977d64d20339e8fdec12c0a1a065371de7 # v3.0.0 with: # Config README: https://github.com/korthout/backport-action#backport-action branch_name: backport/${pull_number}-to-${target_branch} From e83eff1c4f60a7e33ad2943318575cc0320f098a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 May 2024 08:59:12 +0000 Subject: [PATCH 64/74] build(deps): bump actions/checkout from 4.1.5 to 4.1.6 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.5 to 4.1.6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v4.1.5...a5ac7e51b41094c92402da3b24376905380afc29) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index d1ae9068..12933cd5 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -20,7 +20,7 @@ jobs: if: github.repository_owner == 'epics-extensions' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) runs-on: ubuntu-latest steps: - - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs From 6535d50e646d89b5c0f0755f4ba8270a1d0b04cd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Jun 2024 09:00:17 +0000 Subject: [PATCH 65/74] build(deps): bump korthout/backport-action from 3.0.0 to 3.0.2 Bumps [korthout/backport-action](https://github.com/korthout/backport-action) from 3.0.0 to 3.0.2. - [Release notes](https://github.com/korthout/backport-action/releases) - [Commits](https://github.com/korthout/backport-action/compare/7e7cb1977d64d20339e8fdec12c0a1a065371de7...bd410d37cdcae80be6d969823ff5a225fe5c833f) --- updated-dependencies: - dependency-name: korthout/backport-action dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/backport.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index 8cf872f4..a9c0d3d6 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -24,7 +24,7 @@ jobs: with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs - uses: korthout/backport-action@7e7cb1977d64d20339e8fdec12c0a1a065371de7 # v3.0.0 + uses: korthout/backport-action@bd410d37cdcae80be6d969823ff5a225fe5c833f # v3.0.2 with: # Config README: https://github.com/korthout/backport-action#backport-action branch_name: backport/${pull_number}-to-${target_branch} From c52318c0a2b2f3ff8183ce26acf0ef4eb03bce6e Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 5 Jun 2024 10:37:04 +0200 Subject: [PATCH 66/74] templates/top: make EPNix release branch 23.11 the default --- templates/top/flake.nix | 51 ++++++++++++++++++++--------------------- 1 file changed, 25 insertions(+), 26 deletions(-) diff --git a/templates/top/flake.nix b/templates/top/flake.nix index b0aaa1d8..e934504b 100644 --- a/templates/top/flake.nix +++ b/templates/top/flake.nix @@ -2,7 +2,7 @@ description = "EPICS IOC for <...>"; inputs.flake-utils.url = "github:numtide/flake-utils"; - inputs.epnix.url = "github:epics-extensions/epnix"; + inputs.epnix.url = "github:epics-extensions/epnix/nixos-23.11"; # If you have a support module as a separate EPNix repository, # add it as an input here: @@ -80,35 +80,34 @@ # --- # "x86_64-linux" should still be specified so that the development # environment can be built on your machine. - flake-utils.lib.eachSystem ["x86_64-linux"] (system: - with epnix.lib; let - epnixDistribution = evalEpnixModules { - nixpkgsConfig = { - # This specifies the build architecture - inherit system; - - # This specifies the host architecture, uncomment for cross-compiling - # - # The complete of example architectures is here: - # https://github.com/NixOS/nixpkgs/blob/nixos-22.11/lib/systems/examples.nix - # --- - #crossSystem = epnix.inputs.nixpkgs.lib.systems.examples.armv7l-hf-multiplatform; - }; - epnixConfig = myEpnixConfig; + flake-utils.lib.eachSystem ["x86_64-linux"] (system: let + epnixDistribution = epnix.lib.evalEpnixModules { + nixpkgsConfig = { + # This specifies the build architecture + inherit system; + + # This specifies the host architecture, uncomment for cross-compiling + # + # The complete of example architectures is here: + # https://github.com/NixOS/nixpkgs/blob/nixos-22.11/lib/systems/examples.nix + # --- + #crossSystem = epnix.inputs.nixpkgs.lib.systems.examples.armv7l-hf-multiplatform; + }; + epnixConfig = myEpnixConfig; + }; + in { + packages = + epnixDistribution.outputs + // { + default = self.packages.${system}.build; }; - in { - packages = - epnixDistribution.outputs - // { - default = self.packages.${system}.build; - }; - inherit epnixDistribution; + inherit epnixDistribution; - devShells.default = self.packages.${system}.devShell; + devShells.default = self.packages.${system}.devShell; - checks = epnixDistribution.config.epnix.checks.derivations; - }) + checks = epnixDistribution.config.epnix.checks.derivations; + }) // { overlays.default = final: prev: self.epnixDistribution.x86_64-linux.generatedOverlay final prev; From 342c15968a76d8d2dd7aa57f4e66733b0f42fb4a Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 5 Jun 2024 10:54:14 +0200 Subject: [PATCH 67/74] doc/index: explain the concept of release branches --- doc/index.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/doc/index.md b/doc/index.md index cfb55370..d67fb159 100644 --- a/doc/index.md +++ b/doc/index.md @@ -41,11 +41,25 @@ However, since EPNix is a git repository, you will be able, through Nix, to use ```{=html} <!-- TODO: link to an explanation, from the IOC side, and from the NixOS side --> ``` + ## The epics-base package The epics-base package has no significant modification compared to the upstream version at [Launchpad]. One goal of EPNix is to keep those modifications to a minimum, and upstream what's possible. +# Release branches + +EPNix has a `master` branch, +which is considered unstable, +meaning breaking changes might happen without notice. + +EPNix also has release branches, +such as `nixos-23.11`, +tied to the nixpkgs release branches, +where breaking changes are forbidden. + +Backporting changes to older release branches is done on a "best-effort" basis. + ------------------------------------------------------------------------ This documentation follows the [Diátaxis] documentation framework. From 072198684d9706bc70533d6d6184b5f86d562a10 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 5 Jun 2024 10:54:47 +0200 Subject: [PATCH 68/74] doc: use EPNix release branches in code excerpts --- doc/nixos/guides/_pre-requisites.md | 4 ++-- doc/nixos/tutorials/archiver-appliance.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/nixos/guides/_pre-requisites.md b/doc/nixos/guides/_pre-requisites.md index 82b49c70..d13fe83a 100644 --- a/doc/nixos/guides/_pre-requisites.md +++ b/doc/nixos/guides/_pre-requisites.md @@ -18,8 +18,8 @@ For example: ``` {.diff filename="flake.nix"} { # ... -+ inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; -+ inputs.epnix.url = "github:epics-extensions/EPNix"; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; ++ inputs.epnix.url = "github:epics-extensions/EPNix/nixos-23.11"; # ... outputs = { diff --git a/doc/nixos/tutorials/archiver-appliance.md b/doc/nixos/tutorials/archiver-appliance.md index 41681332..1e4a7e57 100644 --- a/doc/nixos/tutorials/archiver-appliance.md +++ b/doc/nixos/tutorials/archiver-appliance.md @@ -58,7 +58,7 @@ Fill the file with these lines: description = "Configuration for running Archiver Appliance in a VM"; inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; - inputs.epnix.url = "github:epics-extensions/EPNix"; + inputs.epnix.url = "github:epics-extensions/EPNix/nixos-23.11"; outputs = { self, nixpkgs, epnix }: { nixosConfigurations.nixos = nixpkgs.lib.nixosSystem { From 6d88fc0a787803ffd558b2f06f43e4c287665977 Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 5 Jun 2024 10:55:22 +0200 Subject: [PATCH 69/74] doc/_vale: move vale vocabulary to new location --- doc/_vale/{Vocab => config/vocabularies}/EPNix/accept.txt | 0 doc/_vale/{Vocab => config/vocabularies}/EPNix/reject.txt | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename doc/_vale/{Vocab => config/vocabularies}/EPNix/accept.txt (100%) rename doc/_vale/{Vocab => config/vocabularies}/EPNix/reject.txt (100%) diff --git a/doc/_vale/Vocab/EPNix/accept.txt b/doc/_vale/config/vocabularies/EPNix/accept.txt similarity index 100% rename from doc/_vale/Vocab/EPNix/accept.txt rename to doc/_vale/config/vocabularies/EPNix/accept.txt diff --git a/doc/_vale/Vocab/EPNix/reject.txt b/doc/_vale/config/vocabularies/EPNix/reject.txt similarity index 100% rename from doc/_vale/Vocab/EPNix/reject.txt rename to doc/_vale/config/vocabularies/EPNix/reject.txt From e72cbb41ded45b0c167299209389479e649e910e Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 5 Jun 2024 11:08:16 +0200 Subject: [PATCH 70/74] doc: fix dead link to old tutorial --- doc/ioc/faq.md | 4 ++-- doc/ioc/tutorials/integration-tests.md | 5 ++--- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/doc/ioc/faq.md b/doc/ioc/faq.md index 3b521b9f..7d6b1b43 100644 --- a/doc/ioc/faq.md +++ b/doc/ioc/faq.md @@ -22,7 +22,7 @@ Use `<consumerApp>_DEPEND_DIRS += <producerApp>`{.makefile} in your top-level `M Meaning, not versioning an App separate from the top. This might be justified if you don't intend to share an App in any other top. -1. First, create a top and an App, as in the [Getting Started] guide. +1. First, create a top and an App, as in the [StreamDevice tutorial]. 2. Make sure to add an exception for the `exampleApp` folder at the end of the top's `.gitignore` file: @@ -46,4 +46,4 @@ git add -N . 4. Finally, in your `flake.nix`, you can remove any input and value in `epnix.applications.apps` that refers to this directory. - [Getting Started]: ./tutorials/getting-started.md + [StreamDevice tutorial]: ./tutorials/streamdevice.md diff --git a/doc/ioc/tutorials/integration-tests.md b/doc/ioc/tutorials/integration-tests.md index c7b72773..0db48a66 100644 --- a/doc/ioc/tutorials/integration-tests.md +++ b/doc/ioc/tutorials/integration-tests.md @@ -6,7 +6,7 @@ title: Integration tests Through the [NixOS testing framework], EPNix provides a way of specifying a machine configuration, and running a Python script that can do various kind of testing. -If you created your IOC using the EPNix template, like suggested in the [Getting Started] documentation, you will see a `checks/` directory. +If you created your IOC using the EPNix template, like suggested in the [StreamDevice tutorial], you will see a `checks/` directory. This directory should contain the integration tests you want to run. To add an integration test to EPNix, record it in your `flake.nix` under the `epnix.checks.files` option. @@ -43,7 +43,7 @@ For an overview of what you can input in the machine configuration, please refer You can also read about the Python test script API [here][NixOS testing framework]. [NixOS testing framework]: https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests - [Getting Started]: ./getting-started.md + [StreamDevice tutorial]: ./streamdevice.md [NixOS documentation]: https://nixos.org/manual/nixos/stable/index.html#sec-configuration-syntax # Starting your IOC through systemd @@ -115,7 +115,6 @@ You can also look at examples either in the EPNix repository under the [`checks` ``` [here]: https://search.nixos.org/options?channel=21.11&from=0&size=50&sort=alpha_asc&type=packages&query=systemd.services. - [epics-systemd]: https://github.com/minijackson/epics-systemd [Packaging Python scripts]: ../guides/testing/packaging-python-scripts.md [NixOS tests documentation]: https://nixos.org/manual/nixos/stable/index.html#sec-nixos-tests [`checks` folder]: https://github.com/epics-extensions/epnix/tree/master/checks From 6d90961082771f80cfa55394cde9056c5f43ffdb Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Thu, 23 May 2024 09:55:57 +0200 Subject: [PATCH 71/74] phoebus-alarm-server: set meta.mainProgram --- pkgs/epnix/tools/phoebus/alarm-server/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/epnix/tools/phoebus/alarm-server/default.nix b/pkgs/epnix/tools/phoebus/alarm-server/default.nix index 1563c8c1..9213422d 100644 --- a/pkgs/epnix/tools/phoebus/alarm-server/default.nix +++ b/pkgs/epnix/tools/phoebus/alarm-server/default.nix @@ -53,6 +53,7 @@ in meta = { description = "Monitor a configurable set of PVs and track their alarm state"; homepage = "https://control-system-studio.readthedocs.io/en/latest/services/alarm-server/doc/index.html"; + mainProgram = "phoebus-alarm-server"; license = lib.licenses.epl10; maintainers = with epnixLib.maintainers; [minijackson]; inherit (jdk.meta) platforms; From cfd42087efb726757702421b0425183eaa23f2cd Mon Sep 17 00:00:00 2001 From: Minijackson <minijackson@riseup.net> Date: Wed, 22 May 2024 10:43:49 +0200 Subject: [PATCH 72/74] nixos/phoebus-alarm-server: put config in /etc, install package useful for importing / exporting configs fixes #81 --- nixos/modules/phoebus/alarm-server.nix | 11 +++++++++-- nixos/tests/phoebus/alarm.py | 5 +++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/nixos/modules/phoebus/alarm-server.nix b/nixos/modules/phoebus/alarm-server.nix index d7ed08f4..736fc0b2 100644 --- a/nixos/modules/phoebus/alarm-server.nix +++ b/nixos/modules/phoebus/alarm-server.nix @@ -8,6 +8,7 @@ cfg = config.services.phoebus-alarm-server; settingsFormat = pkgs.formats.javaProperties {}; configFile = settingsFormat.generate "phoebus-alarm-server.properties" cfg.settings; + configLocation = "phoebus/alarm-server.properties"; in { options.services.phoebus-alarm-server = { enable = lib.mkEnableOption '' @@ -159,6 +160,12 @@ in { } ]; + environment = { + etc."${configLocation}".source = configFile; + # Useful for importing alarm sets + systemPackages = [pkgs.epnix.phoebus-alarm-server]; + }; + systemd.services.phoebus-alarm-server = { description = "Phoebus Alarm Server"; @@ -171,10 +178,10 @@ in { args = [ "-noshell" - "-settings ${configFile}" + "-settings /etc/${configLocation}" ] ++ (lib.optional cfg.createTopics "-create_topics"); - in "${pkgs.epnix.phoebus-alarm-server}/bin/phoebus-alarm-server ${lib.concatStringsSep " " args}"; + in "${lib.getExe pkgs.epnix.phoebus-alarm-server} ${lib.concatStringsSep " " args}"; DynamicUser = true; StateDirectory = "phoebus-alarm-server"; # TODO: systemd hardening diff --git a/nixos/tests/phoebus/alarm.py b/nixos/tests/phoebus/alarm.py index c17125ef..e6212a96 100644 --- a/nixos/tests/phoebus/alarm.py +++ b/nixos/tests/phoebus/alarm.py @@ -190,3 +190,8 @@ def logger_has_latest_state(_): assert alarm_states[2]["current_severity"] == "MAJOR" assert alarm_states[2]["severity"] == "MAJOR" assert alarm_states[2]["value"] == "4.0" + +with subtest("Can export alarm configuration"): + server.succeed("phoebus-alarm-server -settings /etc/phoebus/alarm-server.properties -export export.xml") + server.succeed("grep ALARM_TEST export.xml") + server.copy_from_vm("export.xml") From a6516b001dfb4d6c4c7ae73965ab81491080d903 Mon Sep 17 00:00:00 2001 From: Patrick Hilhorst <philhorst@highvolteng.com> Date: Thu, 13 Jun 2024 09:59:59 +0000 Subject: [PATCH 73/74] Archiver appliance: move to new owner --- pkgs/epnix/tools/archiver-appliance/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/epnix/tools/archiver-appliance/default.nix b/pkgs/epnix/tools/archiver-appliance/default.nix index b28754b9..e27f5b03 100644 --- a/pkgs/epnix/tools/archiver-appliance/default.nix +++ b/pkgs/epnix/tools/archiver-appliance/default.nix @@ -14,7 +14,7 @@ stdenvNoCC.mkDerivation (self: { version = "1.1.0"; src = fetchFromGitHub { - owner = "slacmshankar"; + owner = "archiver-appliance"; repo = "epicsarchiverap"; rev = self.version; fetchSubmodules = true; From bb1f2b88d049f8cc91ab71245cb849c468faf104 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Jun 2024 08:15:20 +0000 Subject: [PATCH 74/74] build(deps): bump actions/checkout from 4.1.6 to 4.1.7 Bumps [actions/checkout](https://github.com/actions/checkout) from 4.1.6 to 4.1.7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/a5ac7e51b41094c92402da3b24376905380afc29...692973e3d937129bcbf40652eb9f2f61becf3332) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/backport.yml | 2 +- .github/workflows/book-gh-pages.yml | 2 +- .github/workflows/editorconfig.yml | 2 +- .github/workflows/formatting.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml index a9c0d3d6..3968462f 100644 --- a/.github/workflows/backport.yml +++ b/.github/workflows/backport.yml @@ -20,7 +20,7 @@ jobs: if: github.repository_owner == 'epics-extensions' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 with: ref: ${{ github.event.pull_request.head.sha }} - name: Create backport PRs diff --git a/.github/workflows/book-gh-pages.yml b/.github/workflows/book-gh-pages.yml index e3b8873c..96b3b6c3 100644 --- a/.github/workflows/book-gh-pages.yml +++ b/.github/workflows/book-gh-pages.yml @@ -23,7 +23,7 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Build documentation book" run: | diff --git a/.github/workflows/editorconfig.yml b/.github/workflows/editorconfig.yml index 3c52c652..73bb11e0 100644 --- a/.github/workflows/editorconfig.yml +++ b/.github/workflows/editorconfig.yml @@ -10,7 +10,7 @@ jobs: editorconfig: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Check EditorConfig" run: nix run 'nixpkgs#eclint' --inputs-from . diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml index f672e922..bc9e9142 100644 --- a/.github/workflows/formatting.yml +++ b/.github/workflows/formatting.yml @@ -10,7 +10,7 @@ jobs: alejandra: runs-on: ubuntu-latest steps: - - uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6 + - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 - uses: cachix/install-nix-action@ba0dd844c9180cbf77aa72a116d6fbc515d0e87b # v27 - name: "Check Formatting" run: nix fmt -- --check .