diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yaml similarity index 75% rename from .github/workflows/cmake.yml rename to .github/workflows/cmake.yaml index 9826f4b13..00d6a4b86 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yaml @@ -1,4 +1,4 @@ -name: CMake +name: Native CMake Build on: [push, pull_request] @@ -14,7 +14,13 @@ jobs: runs-on: ubuntu-latest name: Configure and build using cmake steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: 3.12 + cache: 'pip' + - run: pip install pytest numpy + - uses: awalsh128/cache-apt-pkgs-action@latest with: packages: libhdf5-dev qtbase5-dev qt5-qmake libqt5svg5-dev libpng-dev libtiff-dev @@ -27,12 +33,15 @@ jobs: - name: Build # Build your program with the given configuration - run: cmake --build ${{github.workspace}}/build -j2 --config ${{env.BUILD_TYPE}} + run: cmake --build ${{github.workspace}}/build -j4 --config ${{env.BUILD_TYPE}} - - name: Test + - name: C++ unit tests working-directory: ${{github.workspace}}/build - # Execute tests defined by the CMake configuration. - # See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail run: ctest -C ${{env.BUILD_TYPE}} -j1 + - name: Python unit tests + working-directory: ${{github.workspace}}/build/bin + run: | + python -m pytest ${{github.workspace}}/python/tests + diff --git a/.github/workflows/conda_library.yaml b/.github/workflows/conda_library.yaml new file mode 100644 index 000000000..23f94d467 --- /dev/null +++ b/.github/workflows/conda_library.yaml @@ -0,0 +1,42 @@ +name: Build slsdetlib + +on: [pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, ] # macos-12, windows-2019] + python-version: ["3.12",] + + runs-on: ${{ matrix.platform }} + + # The setup-miniconda action needs this to activate miniconda + defaults: + run: + shell: "bash -l {0}" + + steps: + - uses: actions/checkout@v4 + + - name: Get conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + python-version: ${{ matrix.python-version }} + channels: conda-forge + + - name: Prepare + run: conda install conda-build conda-verify pytest anaconda-client + + - name: Disable upload + run: conda config --set anaconda_upload no + + - name: Build + run: conda build conda-recipes/main-library --output-folder build_output + + - name: Upload all Conda packages + uses: actions/upload-artifact@v4 + with: + name: conda-packages + path: build_output/** # Uploads all packages \ No newline at end of file diff --git a/.github/workflows/conda_python.yaml b/.github/workflows/conda_python.yaml new file mode 100644 index 000000000..4b12cb3ff --- /dev/null +++ b/.github/workflows/conda_python.yaml @@ -0,0 +1,42 @@ +name: slsdet + +on: [pull_request] + +jobs: + build: + strategy: + fail-fast: false + matrix: + platform: [ubuntu-latest, ] # macos-12, windows-2019] + python-version: ["3.12",] + + runs-on: ${{ matrix.platform }} + + # The setup-miniconda action needs this to activate miniconda + defaults: + run: + shell: "bash -l {0}" + + steps: + - uses: actions/checkout@v4 + + - name: Get conda + uses: conda-incubator/setup-miniconda@v3.0.4 + with: + python-version: ${{ matrix.python-version }} + channels: conda-forge + + - name: Prepare + run: conda install conda-build conda-verify pytest anaconda-client + + - name: Disable upload + run: conda config --set anaconda_upload no + + - name: Build + run: conda build conda-recipes/python-client --output-folder build_output + + - name: Upload all Conda packages + uses: actions/upload-artifact@v4 + with: + name: conda-packages + path: build_output/** # Uploads all packages \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 5676ec92d..b1d035d76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,6 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package -cmake_minimum_required(VERSION 3.14) +cmake_minimum_required(VERSION 3.15) project(slsDetectorPackage) # Read VERSION file into project version @@ -29,20 +29,40 @@ include(FetchContent) option(SLS_FETCH_ZMQ_FROM_GITHUB "Fetch zmq from github" OFF) option(SLS_FETCH_PYBIND11_FROM_GITHUB "Fetch pybind11 from github" OFF) + + +# Allow FetchContent_Populate to be called with a single argument +# otherwise deprecated warning is issued +# Note: From cmake 3.28 we can pass EXCLUDE_FROM_ALL to FetchContent_Declare +# and avoid direct use of Populate +if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.30") + cmake_policy(SET CMP0169 OLD) +endif() + +# Patch libzmq to set minimum cmake version to 3.15 to avoid warnings +# with newer cmake versions +# Patch is applied in the FetchContent_Declare +set(SLS_LIBZMQ_VERSION "4.3.4") + + if(SLS_FETCH_ZMQ_FROM_GITHUB) # Opt in to pull down a zmq version from github instead of - # using the bundled verison + # using the bundled version FetchContent_Declare( libzmq GIT_REPOSITORY https://github.com/zeromq/libzmq.git - GIT_TAG v4.3.4 + GIT_TAG v${SLS_LIBZMQ_VERSION} + PATCH_COMMAND ${CMAKE_COMMAND} -E chdir patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/libs/libzmq/libzmq_cmake_version.patch + UPDATE_DISCONNECTED 1 ) else() # Standard behaviour use libzmq included in this repo (libs/libzmq) FetchContent_Declare( libzmq - URL ${CMAKE_CURRENT_SOURCE_DIR}/libs/libzmq/libzmq-4.3.4.tar.gz + URL ${CMAKE_CURRENT_SOURCE_DIR}/libs/libzmq/libzmq-${SLS_LIBZMQ_VERSION}.tar.gz URL_HASH MD5=cc20b769ac10afa352e5ed2769bb23b3 + PATCH_COMMAND ${CMAKE_COMMAND} -E chdir patch -p1 < ${CMAKE_CURRENT_SOURCE_DIR}/libs/libzmq/libzmq_cmake_version.patch + UPDATE_DISCONNECTED 1 ) endif() @@ -54,6 +74,11 @@ set(ENABLE_CPACK OFF CACHE BOOL "") set(ENABLE_CLANG OFF CACHE BOOL "") set(ENABLE_CURVE OFF CACHE BOOL "") set(ENABLE_DRAFTS OFF CACHE BOOL "") +set(ENABLE_PRECOMPILED OFF CACHE BOOL "") +set(WITH_DOC OFF CACHE BOOL "") +set(WITH_DOCS OFF CACHE BOOL "") + + # Using GetProperties and Populate to be able to exclude zmq # from install (not possible with FetchContent_MakeAvailable(libzmq)) @@ -191,7 +216,7 @@ endif() # to control options for the libraries if(NOT TARGET slsProjectOptions) add_library(slsProjectOptions INTERFACE) - target_compile_features(slsProjectOptions INTERFACE cxx_std_11) + target_compile_features(slsProjectOptions INTERFACE cxx_std_11) endif() if (NOT TARGET slsProjectWarnings) @@ -329,9 +354,15 @@ if (SLS_USE_CTBGUI) add_subdirectory(pyctbgui) endif(SLS_USE_CTBGUI) -configure_file( .clang-tidy - ${CMAKE_BINARY_DIR}/.clang-tidy -) +# Workaround for file note being copied to build directory +# when issuing a python -m build +# TODO! Proper fix +if(EXISTS ".clang-tidy") + configure_file(.clang-tidy + ${CMAKE_BINARY_DIR}/.clang-tidy + ) +endif() + if (SLS_BUILD_EXAMPLES) add_subdirectory(sample) diff --git a/RELEASE.txt b/RELEASE.txt index b9ff9c4d1..fb94c95cc 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -1,13 +1,13 @@ -SLS Detector Package Bug Fix Release 9.1.1 released on 22.05.2025 +SLS Detector Package Minor Release 9.2.0 released on 02.06.2025 ================================================================== -This document describes the differences between v9.1.1 and v9.1.0 +This document describes the differences between v9.2.0 and v9.1.1 CONTENTS -------- - 1 Resolved Features + 1 New or Changed Features 2 On-board Detector Server Compatibility 3 Firmware Requirements 4 Kernel Requirements @@ -16,32 +16,21 @@ This document describes the differences between v9.1.1 and v9.1.0 -1 Resolved Features -====================== +1 New or Changed Features +========================= - Detector Server - --------------- + Python + ------ - * [Mythen3] Fix trimbits and badchannels - They were shifted by 1. Fixed. + * Python module is now built using scikit-build-core + + + * slsdet is available on PyPI from this release onwards - Receiver - -------- - - - * slsFrameSynchronizer - does not stream out frames - It streamed out start and stop zmq packets but did - not stream out frames with no error message. Fixed. - Updated documentation. - - - * slsMultiReceiver - 3rd Command line argument (vebose option) - When this option to print headers is enabled, the sample call back - headers update the image size to a random number 26112. This - is fixed and left commented out for easy reference for users. + * Updated documentation on python module installation diff --git a/VERSION b/VERSION index 8ce0f0f36..85f864fe8 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -9.1.1 \ No newline at end of file +9.2.0 \ No newline at end of file diff --git a/conda-recipe/build_pylib.sh b/conda-recipe/build_pylib.sh deleted file mode 100755 index 18b0615ab..000000000 --- a/conda-recipe/build_pylib.sh +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package - -echo "|<-------- starting python build" - -cd python - -# copy VERSION into slsdet for installation -cp ../VERSION slsdet/VERSION - -${PYTHON} setup.py install diff --git a/conda-recipe/conda_build_config.yaml b/conda-recipe/conda_build_config.yaml deleted file mode 100644 index 6e37cf5c5..000000000 --- a/conda-recipe/conda_build_config.yaml +++ /dev/null @@ -1,14 +0,0 @@ -python: - - 3.8 - - 3.9 - - 3.10 - - 3.11 - - 3.12 - - 3.13 - - -c_stdlib: - - sysroot # [linux] - -c_stdlib_version: # [linux] - - 2.17 # [linux] diff --git a/conda-recipe/copy_ctbgui.sh b/conda-recipe/copy_ctbgui.sh deleted file mode 100644 index b4f52efce..000000000 --- a/conda-recipe/copy_ctbgui.sh +++ /dev/null @@ -1,11 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package -mkdir $PREFIX/lib -mkdir $PREFIX/bin -mkdir $PREFIX/include - - - -cp build/bin/ctbGui $PREFIX/bin/. -cp build/bin/libctbRootLib.so $PREFIX/lib/. - diff --git a/conda-recipe/run_test.sh b/conda-recipe/run_test.sh deleted file mode 100755 index 24068d625..000000000 --- a/conda-recipe/run_test.sh +++ /dev/null @@ -1,3 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package -ctest -j2 \ No newline at end of file diff --git a/conda-recipe/build.sh b/conda-recipes/main-library/build.sh similarity index 93% rename from conda-recipe/build.sh rename to conda-recipes/main-library/build.sh index 251b04477..229067c3b 100755 --- a/conda-recipe/build.sh +++ b/conda-recipes/main-library/build.sh @@ -8,7 +8,7 @@ if [ ! -d "install" ]; then mkdir install fi cd build -cmake .. \ +cmake .. -G Ninja \ -DCMAKE_PREFIX_PATH=$CONDA_PREFIX \ -DCMAKE_INSTALL_PREFIX=install \ -DSLS_USE_TEXTCLIENT=ON \ @@ -18,7 +18,7 @@ cmake .. \ -DSLS_USE_TESTS=ON \ -DSLS_USE_PYTHON=OFF \ -DCMAKE_BUILD_TYPE=Release \ - -DSLS_USE_HDF5=OFF\ + -DSLS_USE_HDF5=OFF \ NCORES=$(getconf _NPROCESSORS_ONLN) echo "Building using: ${NCORES} cores" diff --git a/conda-recipes/main-library/conda_build_config.yaml b/conda-recipes/main-library/conda_build_config.yaml new file mode 100644 index 000000000..149897ca1 --- /dev/null +++ b/conda-recipes/main-library/conda_build_config.yaml @@ -0,0 +1,13 @@ + +c_compiler: + - gcc # [linux] + +c_stdlib: + - sysroot # [linux] + +cxx_compiler: + - gxx # [linux] + + +c_stdlib_version: # [linux] + - 2.17 # [linux] \ No newline at end of file diff --git a/conda-recipe/copy_gui.sh b/conda-recipes/main-library/copy_gui.sh similarity index 100% rename from conda-recipe/copy_gui.sh rename to conda-recipes/main-library/copy_gui.sh diff --git a/conda-recipe/copy_lib.sh b/conda-recipes/main-library/copy_lib.sh similarity index 87% rename from conda-recipe/copy_lib.sh rename to conda-recipes/main-library/copy_lib.sh index 5836146f6..88beafdfe 100755 --- a/conda-recipe/copy_lib.sh +++ b/conda-recipes/main-library/copy_lib.sh @@ -4,7 +4,6 @@ mkdir -p $PREFIX/lib mkdir -p $PREFIX/bin mkdir -p $PREFIX/include/sls -# mkdir $PREFIX/include/slsDetectorPackage #Shared and static libraries cp build/install/lib/* $PREFIX/lib/ @@ -15,8 +14,10 @@ cp build/install/bin/sls_detector_acquire_zmq $PREFIX/bin/. cp build/install/bin/sls_detector_get $PREFIX/bin/. cp build/install/bin/sls_detector_put $PREFIX/bin/. cp build/install/bin/sls_detector_help $PREFIX/bin/. +cp build/install/bin/sls_detector $PREFIX/bin/. cp build/install/bin/slsReceiver $PREFIX/bin/. cp build/install/bin/slsMultiReceiver $PREFIX/bin/. +cp build/install/bin/slsFrameSynchronizer $PREFIX/bin/. cp build/install/include/sls/* $PREFIX/include/sls diff --git a/conda-recipe/copy_moench.sh b/conda-recipes/main-library/copy_moench.sh similarity index 100% rename from conda-recipe/copy_moench.sh rename to conda-recipes/main-library/copy_moench.sh diff --git a/conda-recipe/meta.yaml b/conda-recipes/main-library/meta.yaml similarity index 55% rename from conda-recipe/meta.yaml rename to conda-recipes/main-library/meta.yaml index 8dde14f70..fd53933c1 100755 --- a/conda-recipe/meta.yaml +++ b/conda-recipes/main-library/meta.yaml @@ -1,11 +1,11 @@ +source: + path: ../.. + +{% set version = load_file_regex(load_file = 'VERSION', regex_pattern = '(\d+(?:\.\d+)*(?:[\+\w\.]+))').group(1) %} package: name: sls_detector_software - version: {{ environ.get('GIT_DESCRIBE_TAG', '') }} - - -source: - path: .. - + version: {{ version }} + build: number: 0 binary_relocation: True @@ -15,20 +15,21 @@ build: requirements: build: - {{ compiler('c') }} - - {{stdlib('c')}} - - {{compiler('cxx')}} - - cmake<=3.28 + - {{ stdlib("c") }} + - {{ compiler('cxx') }} + - git + - cmake - ninja - qt 5.* host: - libstdcxx-ng - libgcc-ng - - libgl-devel + - libgl-devel # [linux] - libtiff - zlib - expat - + run: - libstdcxx-ng - libgcc-ng @@ -41,44 +42,13 @@ outputs: requirements: build: - {{ compiler('c') }} - - {{compiler('cxx')}} - - libstdcxx-ng - - libgcc-ng + - {{ stdlib("c") }} + - {{ compiler('cxx') }} run: - libstdcxx-ng - libgcc-ng - - name: slsdet - script: build_pylib.sh - - requirements: - build: - - python - - {{ compiler('c') }} - - {{compiler('cxx')}} - - {{ pin_subpackage('slsdetlib', exact=True) }} - - setuptools - - pybind11=2.13 - - host: - - python - - {{ pin_subpackage('slsdetlib', exact=True) }} - - setuptools - - pybind11=2.13 - - - run: - - libstdcxx-ng - - libgcc-ng - - python - - numpy - - {{ pin_subpackage('slsdetlib', exact=True) }} - - test: - imports: - - slsdet - - name: slsdetgui script: copy_gui.sh @@ -88,12 +58,11 @@ outputs: - {{ compiler('c') }} - {{compiler('cxx')}} - {{ pin_subpackage('slsdetlib', exact=True) }} - run: - {{ pin_subpackage('slsdetlib', exact=True) }} - qt 5.* - - expat + - name: moenchzmq script: copy_moench.sh @@ -107,5 +76,3 @@ outputs: run: - {{ pin_subpackage('slsdetlib', exact=True) }} - - expat - diff --git a/conda-recipes/python-client/conda_build_config.yaml b/conda-recipes/python-client/conda_build_config.yaml new file mode 100644 index 000000000..0c957b631 --- /dev/null +++ b/conda-recipes/python-client/conda_build_config.yaml @@ -0,0 +1,16 @@ +python: + - 3.11 + - 3.12 + - 3.13 + +c_compiler: + - gcc # [linux] + +c_stdlib: + - sysroot # [linux] + +cxx_compiler: + - gxx # [linux] + +c_stdlib_version: # [linux] + - 2.17 # [linux] \ No newline at end of file diff --git a/conda-recipes/python-client/meta.yaml b/conda-recipes/python-client/meta.yaml new file mode 100644 index 000000000..c86f401ef --- /dev/null +++ b/conda-recipes/python-client/meta.yaml @@ -0,0 +1,45 @@ +source: + path: ../.. + +{% set version = load_file_regex(load_file = 'VERSION', regex_pattern = '(\d+(?:\.\d+)*(?:[\+\w\.]+))').group(1) %} +package: + name: slsdet + version: {{ version }} + +build: + number: 0 + script: + - unset CMAKE_GENERATOR && {{ PYTHON }} -m pip install . -vv # [not win] + +requirements: + build: + - python {{python}} + - {{ compiler('c') }} + - {{ stdlib("c") }} + - {{ compiler('cxx') }} + + host: + - cmake + - ninja + - python {{python}} + - pip + - scikit-build-core + - pybind11 >=2.13.0 + - fmt + - zeromq + - nlohmann_json + - catch2 + + run: + - python {{python}} + - numpy + + +test: + imports: + - slsdet + + +about: + summary: An example project built with pybind11 and scikit-build. + # license_file: LICENSE \ No newline at end of file diff --git a/docs/src/installation.rst b/docs/src/installation.rst index 2f1dca474..82128f9e5 100644 --- a/docs/src/installation.rst +++ b/docs/src/installation.rst @@ -6,18 +6,33 @@ Installation =============== -One can either install pre-built binaries using conda or build from source. +.. contents:: + :local: + :depth: 2 + :backlinks: top + + +Overview +-------------- + +The ``slsDetectorPackage`` provides core detector software implemented in C++, along with Python bindings packaged as the ``slsdet`` Python extension module. Choose the option that best fits your environment and use case. + +:ref:`conda pre-built binaries`: +Install pre-built binaries for the C++ client, receiver, GUI and the Python API (``slsdet``), simplifying setup across platforms. + +:ref:`pip`: +Install only the Python extension module, either by downloading the pre-built library from PyPI or by building the extension locally from source. Available only from v9.2.0 onwards. + +:ref:`build from source`: +Compile the entire package yourself, including both the C++ core and the Python bindings, for maximum control and customization. However, make sure that you have the :doc:`dependencies <../dependencies>` installed. If installing using conda, conda will manage the dependencies. Avoid installing packages with pip and conda simultaneously. + + -.. warning :: - - Before building from source make sure that you have the - :doc:`dependencies <../dependencies>` installed. If installing using conda, conda will - manage the dependencies. Avoid also installing packages with pip. +.. _conda pre-built binaries: - -Install binaries using conda ----------------------------------- +1. Install pre-built binaries using conda (Recommended) +-------------------------------------------------------- Conda is not only useful to manage python environments but can also be used as a user space package manager. Dates in the tag (for eg. 2020.07.23.dev0) @@ -63,12 +78,29 @@ We have four different packages available: conda search moenchzmq +.. _pip: + +2. Pip +------- +The Python extension module ``slsdet`` can be installed using pip. This is available from v9.2.0 onwards. + +.. code-block:: bash + + #Install the Python extension module from PyPI + pip install slsdet + + # or install the python extension locally from source + git clone https://github.com/slsdetectorgroup/slsDetectorPackage.git --branch 9.2.0 + cd slsDetectorPackage + pip install . -Build from source ----------------------- +.. _build from source: -1. Download Source Code from github +3. Build from source +------------------------- + +3.1. Download Source Code from github ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash @@ -83,12 +115,12 @@ Build from source -2. Build from Source +3.2. Build from Source ^^^^^^^^^^^^^^^^^^^^^^^^^^ One can either build using cmake or use the in-built cmk.sh script. -Build using CMake +3.2.1. Build using CMake ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: bash @@ -135,7 +167,7 @@ Example cmake options Comment For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmake option to hint library location. ` -Build using in-built cmk.sh script +3.2.2. Build using in-built cmk.sh script ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -185,8 +217,8 @@ Build using in-built cmk.sh script For v7.x.x of slsDetectorPackage and older, refer :ref:`zeromq notes for cmk script option to hint library location. ` -Build on old distributions -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +3.3. Build on old distributions using conda +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ If your linux distribution doesn't come with a C++11 compiler (gcc>4.8) then it's possible to install a newer gcc using conda and build the slsDetectorPackage @@ -210,7 +242,7 @@ using this compiler -Build slsDetectorGui (Qt5) +3.4. Build slsDetectorGui (Qt5) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 1. Using pre-built binary on conda @@ -271,7 +303,7 @@ Build slsDetectorGui (Qt5) -Build this documentation +3.5. Build this documentation ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The documentation for the slsDetectorPackage is build using a combination @@ -294,8 +326,8 @@ is to use conda make rst # rst only, saves time in case the API did not change -Pybind and Zeromq -^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +4. Pybind and Zeromq +------------------------- .. _pybind for different slsDetectorPackage versions: diff --git a/libs/libzmq/libzmq_cmake_version.patch b/libs/libzmq/libzmq_cmake_version.patch new file mode 100644 index 000000000..4e421d322 --- /dev/null +++ b/libs/libzmq/libzmq_cmake_version.patch @@ -0,0 +1,18 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index dd3d8eb9..c0187747 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -1,11 +1,8 @@ + # CMake build script for ZeroMQ + project(ZeroMQ) + +-if(${CMAKE_SYSTEM_NAME} STREQUAL Darwin) +- cmake_minimum_required(VERSION 3.0.2) +-else() +- cmake_minimum_required(VERSION 2.8.12) +-endif() ++cmake_minimum_required(VERSION 3.15) ++message(STATUS "Patched cmake version") + + include(CheckIncludeFiles) + include(CheckCCompilerFlag) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..15833499c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,37 @@ +[tool.scikit-build.metadata.version] +provider = "scikit_build_core.metadata.regex" +input = "VERSION" +regex = '^(?P\d+(?:\.\d+)*(?:[\.\+\w]+)?)$' +result = "{version}" + +[build-system] +requires = [ "scikit-build-core>=0.10", "pybind11", "numpy",] +build-backend = "scikit_build_core.build" + +[project] +name = "slsdet" +dynamic = ["version"] +dependencies = [ + "numpy", +] + +[tool.cibuildwheel] +before-all = "uname -a" +build = "cp{311,312,313}-manylinux_x86_64" + +[tool.scikit-build.build] +verbose = true + +[tool.scikit-build.cmake] +build-type = "Release" + +[tool.scikit-build.install] +components = [ "python",] + +[tool.scikit-build.cmake.define] +SLS_USE_RECEIVER = "OFF" +SLS_USE_RECEIVER_BINARIES = "OFF" +SLS_USE_TEXTCLIENT = "OFF" +SLS_BUILD_SHARED_LIBRARIES = "OFF" +SLS_USE_PYTHON = "ON" +SLS_INSTALL_PYTHONEXT = "ON" diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt index 9765e55d1..2e6a485e7 100755 --- a/python/CMakeLists.txt +++ b/python/CMakeLists.txt @@ -20,7 +20,7 @@ target_link_libraries(_slsdet PUBLIC set_target_properties(_slsdet PROPERTIES - LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin + LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin/slsdet ) #Copy Python code @@ -75,10 +75,18 @@ configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/../VERSION if(SLS_INSTALL_PYTHONEXT) install(TARGETS _slsdet EXPORT "${TARGETS_EXPORT_NAME}" - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/python + LIBRARY DESTINATION slsdet + COMPONENT python ) + install( + FILES ${PYTHON_FILES} + DESTINATION slsdet + COMPONENT python + ) + install( + FILES ../VERSION + DESTINATION slsdet + COMPONENT python + ) - install(FILES ${PYTHON_FILES} DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet) - install(FILES ../VERSION DESTINATION ${CMAKE_INSTALL_PREFIX}/python/slsdet) endif() - diff --git a/python/setup.py b/python/setup.py deleted file mode 100755 index 1be1ac809..000000000 --- a/python/setup.py +++ /dev/null @@ -1,77 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package -""" -Setup file for slsdet -Build upon the pybind11 example found here: https://github.com/pybind/python_example -""" - -import os -import sys -from setuptools import setup, find_packages -from pybind11.setup_helpers import Pybind11Extension, build_ext - -def read_version(): - try: - version_file = os.path.join(os.path.dirname(__file__), 'slsdet', 'VERSION') - with open(version_file, "r") as f: - return f.read().strip() - except: - raise RuntimeError("VERSION file not found in slsdet package from setup.py.") - -__version__ = read_version() - - -def get_conda_path(): - """ - Keep this a function if we need some fancier logic later - """ - print('Prefix: ', os.environ['CONDA_PREFIX']) - return os.environ['CONDA_PREFIX'] - - -#TODO migrate to CMake build or fetch files from cmake? -ext_modules = [ - Pybind11Extension( - '_slsdet', - ['src/main.cpp', - 'src/enums.cpp', - 'src/current.cpp', - 'src/detector.cpp', - 'src/network.cpp', - 'src/pattern.cpp', - 'src/scan.cpp', - 'src/duration.cpp', - 'src/DurationWrapper.cpp', - 'src/pedestal.cpp', - ] - - - , - include_dirs=[ - os.path.join(get_conda_path(), 'include'), - - ], - libraries=['SlsDetector', 'SlsSupport', 'SlsReceiver'], - library_dirs=[ - os.path.join(get_conda_path(), 'lib'), - ], - language='c++' - ), -] - -setup( - name='slsdet', - version=__version__, - author='Erik Frojdh', - author_email='erik.frojdh@psi.ch', - url='https://github.com/slsdetectorgroup/slsDetectorPackage', - description='Detector API for SLS Detector Group detectors', - long_description='', - packages=find_packages(exclude=['contrib', 'docs', 'tests']), - package_data={ - 'slsdet': ['VERSION'], - }, - ext_modules=ext_modules, - cmdclass={"build_ext": build_ext}, - zip_safe=False, -) diff --git a/python/slsdet/__init__.py b/python/slsdet/__init__.py index 96a734ff9..18921735b 100755 --- a/python/slsdet/__init__.py +++ b/python/slsdet/__init__.py @@ -14,7 +14,7 @@ from .moench import Moench from .pattern import Pattern, patternParameters from .gaincaps import Mythen3GainCapsWrapper -import _slsdet +from . import _slsdet xy = _slsdet.xy defs = _slsdet.slsDetectorDefs @@ -41,3 +41,6 @@ def read_version(): __version__ = read_version() + + + diff --git a/python/slsdet/ctb.py b/python/slsdet/ctb.py index ad671a93e..1295af9cb 100644 --- a/python/slsdet/ctb.py +++ b/python/slsdet/ctb.py @@ -4,7 +4,7 @@ from .detector import Detector, freeze from .utils import element_if_equal from .dacs import DetectorDacs, NamedDacs from .powers import DetectorPowers, NamedPowers -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/dacs.py b/python/slsdet/dacs.py index 961d0bebe..547a43277 100755 --- a/python/slsdet/dacs.py +++ b/python/slsdet/dacs.py @@ -3,7 +3,7 @@ from .detector_property import DetectorProperty from functools import partial import numpy as np -import _slsdet +from . import _slsdet from .detector import freeze dacIndex = _slsdet.slsDetectorDefs.dacIndex class Dac(DetectorProperty): diff --git a/python/slsdet/detector.py b/python/slsdet/detector.py index 5a070b011..da2901ed6 100755 --- a/python/slsdet/detector.py +++ b/python/slsdet/detector.py @@ -1,8 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package -from _slsdet import CppDetectorApi -from _slsdet import slsDetectorDefs -from _slsdet import IpAddr, MacAddr +from ._slsdet import CppDetectorApi +from ._slsdet import slsDetectorDefs +from ._slsdet import IpAddr, MacAddr runStatus = slsDetectorDefs.runStatus timingMode = slsDetectorDefs.timingMode @@ -15,7 +15,7 @@ defs = slsDetectorDefs from .utils import element_if_equal, all_equal, get_set_bits, list_to_bitmask from .utils import Geometry, to_geo, element, reduce_time, is_iterable, hostname_list -from _slsdet import xy +from ._slsdet import xy from .gaincaps import Mythen3GainCapsWrapper from . import utils as ut from .proxy import JsonProxy, SlowAdcProxy, ClkDivProxy, MaxPhaseProxy, ClkFreqProxy, PatLoopProxy, PatNLoopProxy, PatWaitProxy, PatWaitTimeProxy diff --git a/python/slsdet/eiger.py b/python/slsdet/eiger.py index a65532677..db12b7909 100755 --- a/python/slsdet/eiger.py +++ b/python/slsdet/eiger.py @@ -11,7 +11,7 @@ Created on Wed Dec 6 11:51:18 2017 from .detector import Detector from .temperature import Temperature, DetectorTemperature from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/enums.py b/python/slsdet/enums.py index 02e3c5126..41dcd5dec 100644 --- a/python/slsdet/enums.py +++ b/python/slsdet/enums.py @@ -15,8 +15,8 @@ if dt === detectorType.EIGER: """ -import _slsdet +from . import _slsdet for name, cls in _slsdet.slsDetectorDefs.__dict__.items(): if isinstance(cls, type): - exec(f'{name} = {cls.__module__}.{cls.__qualname__}') + exec(f'{name} = _slsdet.{cls.__qualname__}') diff --git a/python/slsdet/gaincaps.py b/python/slsdet/gaincaps.py index ab3acd381..900503624 100644 --- a/python/slsdet/gaincaps.py +++ b/python/slsdet/gaincaps.py @@ -1,6 +1,6 @@ -import _slsdet +from . import _slsdet gc = _slsdet.slsDetectorDefs.M3_GainCaps diff --git a/python/slsdet/gotthard.py b/python/slsdet/gotthard.py index 9468c78a3..c7aa29d73 100644 --- a/python/slsdet/gotthard.py +++ b/python/slsdet/gotthard.py @@ -9,7 +9,7 @@ This file contains the specialization for the Moench detector from .detector import Detector, freeze from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/gotthard2.py b/python/slsdet/gotthard2.py index bdb36097f..fb2786faf 100644 --- a/python/slsdet/gotthard2.py +++ b/python/slsdet/gotthard2.py @@ -11,7 +11,7 @@ from .detector import Detector, freeze # from .adcs import Adc, DetectorAdcs from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/jungfrau.py b/python/slsdet/jungfrau.py index c8e3f43f9..1021a55f1 100644 --- a/python/slsdet/jungfrau.py +++ b/python/slsdet/jungfrau.py @@ -11,7 +11,7 @@ from .detector import Detector, freeze # from .adcs import Adc, DetectorAdcs from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/moench.py b/python/slsdet/moench.py index 6ed49a43d..7e93bee65 100644 --- a/python/slsdet/moench.py +++ b/python/slsdet/moench.py @@ -9,7 +9,7 @@ This file contains the specialization for the Moench detector from .detector import Detector, freeze from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex from .detector_property import DetectorProperty diff --git a/python/slsdet/mythen3.py b/python/slsdet/mythen3.py index 369d6ac99..14e1294ea 100644 --- a/python/slsdet/mythen3.py +++ b/python/slsdet/mythen3.py @@ -11,7 +11,7 @@ from .detector import Detector, freeze # from .adcs import Adc, DetectorAdcs from .dacs import DetectorDacs -import _slsdet +from . import _slsdet dacIndex = _slsdet.slsDetectorDefs.dacIndex gc_enums = _slsdet.slsDetectorDefs.M3_GainCaps from .detector_property import DetectorProperty diff --git a/python/slsdet/pattern.py b/python/slsdet/pattern.py index a2d80fdfe..273865c65 100644 --- a/python/slsdet/pattern.py +++ b/python/slsdet/pattern.py @@ -1,8 +1,8 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package -import _slsdet +from . import _slsdet -from _slsdet import Pattern +from ._slsdet import Pattern class patternParameters(_slsdet.patternParameters): diff --git a/python/slsdet/powers.py b/python/slsdet/powers.py index 8de1781c7..a513eedbe 100755 --- a/python/slsdet/powers.py +++ b/python/slsdet/powers.py @@ -3,7 +3,7 @@ from .detector_property import DetectorProperty from functools import partial import numpy as np -import _slsdet +from . import _slsdet from .detector import freeze dacIndex = _slsdet.slsDetectorDefs.dacIndex class Power(DetectorProperty): diff --git a/python/slsdet/proxy.py b/python/slsdet/proxy.py index cd10cb38a..316c1dbe3 100644 --- a/python/slsdet/proxy.py +++ b/python/slsdet/proxy.py @@ -3,7 +3,7 @@ from .utils import element_if_equal from .enums import dacIndex from .defines import M3_MAX_PATTERN_LEVELS, MAX_PATTERN_LEVELS -from _slsdet import slsDetectorDefs +from ._slsdet import slsDetectorDefs detectorType = slsDetectorDefs.detectorType diff --git a/python/slsdet/utils.py b/python/slsdet/utils.py index 89a7651bc..4648abd5a 100755 --- a/python/slsdet/utils.py +++ b/python/slsdet/utils.py @@ -6,7 +6,7 @@ but not directly used in controlling the detector """ from collections import namedtuple -import _slsdet #C++ lib +from . import _slsdet #C++ lib import functools import datetime as dt import pathlib diff --git a/python/src/duration.cpp b/python/src/duration.cpp index db6da3d06..ed8927c90 100644 --- a/python/src/duration.cpp +++ b/python/src/duration.cpp @@ -1,3 +1,4 @@ +#include #include "py_headers.h" #include "DurationWrapper.h" @@ -19,4 +20,25 @@ void init_duration(py::module &m) { << " count: " << self.count() << ")"; return ss.str(); }); + + m.def( + "test_return_DurationWrapper", + []() { + DurationWrapper t(1.3); + return t; + }, + R"( + Test function to return a DurationWrapper object. Ensures that the automatic conversion in typecaster.h works. + )"); + + m.def( + "test_duration_to_ns", + [](const std::chrono::nanoseconds t) { + //Duration wrapper is used to be able to convert from time in python to chrono::nanoseconds + //return count to have something to test + return t.count(); + }, + R"( + Test function convert DurationWrapper or number to chrono::ns. Ensures that the automatic conversion in typecaster.h works. + )"); // default value to test the default constructor } diff --git a/python/src/typecaster.h b/python/src/typecaster.h index 5eba7b436..6412afa72 100644 --- a/python/src/typecaster.h +++ b/python/src/typecaster.h @@ -54,11 +54,16 @@ template <> struct type_caster { value = duration_cast(duration(PyFloat_AsDouble(src.ptr()))); return true; } + // If invoked with an int we assume it is nanoseconds and convert, same as in chrono.h + if (PyLong_Check(src.ptr())) { + value = duration_cast(duration(PyLong_AsLongLong(src.ptr()))); + return true; + } // Lastly if we were actually called with a DurationWrapper object we get // the number of nanoseconds and create a std::chrono::nanoseconds from it - py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper"); + py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper"); if (py::isinstance(src, py_cls)){ sls::DurationWrapper *cls = src.cast(); value = nanoseconds(cls->count()); @@ -77,7 +82,7 @@ template <> struct type_caster { * set the count from chrono::nanoseconds and return */ static handle cast(std::chrono::nanoseconds src, return_value_policy /* policy */, handle /* parent */) { - py::object py_cls = py::module::import("_slsdet").attr("DurationWrapper"); + py::object py_cls = py::module::import("slsdet._slsdet").attr("DurationWrapper"); py::object* obj = new py::object; *obj = py_cls(); sls::DurationWrapper *dur = obj->cast(); diff --git a/python/tests/test_DurationWrapper.py b/python/tests/test_DurationWrapper.py new file mode 100644 index 000000000..f6902da26 --- /dev/null +++ b/python/tests/test_DurationWrapper.py @@ -0,0 +1,58 @@ +import pytest + +from slsdet import DurationWrapper + +#import the compiled extension to use test functions for the automatic conversion +from slsdet import _slsdet + + +def test_default_construction_of_DurationWrapper(): + """Test default construction of DurationWrapper""" + t = DurationWrapper() + assert t.count() == 0 + assert t.total_seconds() == 0 + +def test_construction_of_DurationWrapper(): + """Test construction of DurationWrapper with total_seconds""" + t = DurationWrapper(5) + assert t.count() == 5e9 + assert t.total_seconds() == 5 + +def test_set_count_on_DurationWrapper(): + """Test set_count on DurationWrapper""" + t = DurationWrapper() + t.set_count(10) + assert t.count() == 10 + assert t.total_seconds() == 10e-9 + t.set_count(0) + assert t.count() == 0 + assert t.total_seconds() == 0 + + +def test_return_a_DurationWrapper_from_cpp(): + """Test returning a DurationWrapper from C++""" + t = _slsdet.test_return_DurationWrapper() + assert t.count() == 1.3e9 + assert t.total_seconds() == 1.3 + +def test_call_a_cpp_function_with_a_duration_wrapper(): + """C++ functions can accept a DurationWrapper""" + t = DurationWrapper(5) + assert _slsdet.test_duration_to_ns(t) == 5e9 + +def test_call_a_cpp_function_converting_number_to_DurationWrapper(): + """int and float can be converted to std::chrono::nanoseconds""" + assert _slsdet.test_duration_to_ns(0) == 0 + assert _slsdet.test_duration_to_ns(3) == 3e9 + assert _slsdet.test_duration_to_ns(1.3) == 1.3e9 + assert _slsdet.test_duration_to_ns(10e-9) == 10 + +def test_call_a_cpp_function_with_datetime_timedelta(): + """datetime.timedelta can be converted to std::chrono::nanoseconds""" + import datetime + t = datetime.timedelta(seconds=5) + assert _slsdet.test_duration_to_ns(t) == 5e9 + t = datetime.timedelta(seconds=0) + assert _slsdet.test_duration_to_ns(t) == 0 + t = datetime.timedelta(seconds=1.3) + assert _slsdet.test_duration_to_ns(t) == 1.3e9 \ No newline at end of file diff --git a/slsDetectorServers/compileAllServers.sh b/slsDetectorServers/compileAllServers.sh old mode 100644 new mode 100755 index eec8907bf..005c0d623 --- a/slsDetectorServers/compileAllServers.sh +++ b/slsDetectorServers/compileAllServers.sh @@ -1,17 +1,20 @@ # SPDX-License-Identifier: LGPL-3.0-or-other # Copyright (C) 2021 Contributors to the SLS Detector Package -# empty branch = developer branch in updateAPIVersion.sh -branch="" det_list=("ctbDetectorServer gotthardDetectorServer gotthard2DetectorServer jungfrauDetectorServer mythen3DetectorServer moenchDetectorServer - xilinx_ctbDetectorServer" + xilinx_ctbDetectorServer" ) -usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'" +usage="\nUsage: compileAllServers.sh [server|all(opt)] [update_api(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tupdate_api if true updates the api to version in VERSION file" + +update_api=true +target=version + + # arguments if [ $# -eq 0 ]; then @@ -35,15 +38,12 @@ elif [ $# -eq 1 ] || [ $# -eq 2 ]; then declare -a det=("${1}") #echo "Compiling only $1" fi - # branch + if [ $# -eq 2 ]; then - # arg in list - if [[ $det_list == *$2* ]]; then - echo -e "Invalid argument 2: $2. $usage" - return 1 + update_api=$2 + if not $update_api ; then + target=clean fi - branch+=$2 - #echo "with branch $branch" fi else echo -e "Too many arguments.$usage" @@ -54,6 +54,9 @@ declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK") echo -e "list is ${det[@]}" +if $update_api; then + echo "updating api to $(cat ../VERSION)" +fi # compile each server idet=0 for i in ${det[@]} @@ -63,14 +66,13 @@ do echo -e "Compiling $dir [$file]" cd $dir make clean - if make version API_BRANCH=$branch; then + if make $target; then deterror[$idet]="OK" else deterror[$idet]="FAIL" fi mv bin/$dir bin/$file git add -f bin/$file - cp bin/$file /tftpboot/ cd .. echo -e "\n\n" ((++idet)) diff --git a/slsDetectorServers/compileAllServers_noAPIUpdate.sh b/slsDetectorServers/compileAllServers_noAPIUpdate.sh deleted file mode 100644 index ecfbdf6fb..000000000 --- a/slsDetectorServers/compileAllServers_noAPIUpdate.sh +++ /dev/null @@ -1,87 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package - -# empty branch = developer branch in updateAPIVersion.sh -branch="" -det_list=("ctbDetectorServer" - "gotthardDetectorServer" - "gotthard2DetectorServer" - "jungfrauDetectorServer" - "mythen3DetectorServer" - "moenchDetectorServer" - "xilinx_ctbDetectorServer" - ) -usage="\nUsage: compileAllServers.sh [server|all(opt)] [branch(opt)]. \n\tNo arguments mean all servers with 'developer' branch. \n\tNo 'branch' input means 'developer branch'" - -# arguments -if [ $# -eq 0 ]; then - # no argument, all servers - declare -a det=${det_list[@]} - echo "Compiling all servers" -elif [ $# -eq 1 ] || [ $# -eq 2 ]; then - # 'all' servers - if [[ $1 == "all" ]]; then - declare -a det=${det_list[@]} - echo "Compiling all servers" - else - # only one server - # arg not in list - if [[ $det_list != *$1* ]]; then - echo -e "Invalid argument 1: $1. $usage" - return -1 - fi - declare -a det=("${1}") - #echo "Compiling only $1" - fi - # branch - if [ $# -eq 2 ]; then - # arg in list - if [[ $det_list == *$2* ]]; then - echo -e "Invalid argument 2: $2. $usage" - return -1 - fi - branch+=$2 - #echo "with branch $branch" - fi -else - echo -e "Too many arguments.$usage" - return -1 -fi - -declare -a deterror=("OK" "OK" "OK" "OK" "OK" "OK") - -echo -e "list is ${det[@]}" - -# compile each server -idet=0 -for i in ${det[@]} -do - dir=$i - file="${i}_developer" - echo -e "Compiling $dir [$file]" - cd $dir - make clean - if make API_BRANCH=$branch; then - deterror[$idet]="OK" - else - deterror[$idet]="FAIL" - fi - mv bin/$dir bin/$file - git add -f bin/$file - cp bin/$file /tftpboot/ - cd .. - echo -e "\n\n" - ((++idet)) -done - -echo -e "Results:" -idet=0 -for i in ${det[@]} -do - printf "%s\t\t= %s\n" "$i" "${deterror[$idet]}" - ((++idet)) -done - - - - diff --git a/slsDetectorServers/compileEigerServer.sh b/slsDetectorServers/compileEigerServer.sh old mode 100644 new mode 100755 index 35aff3f80..f5873dff8 --- a/slsDetectorServers/compileEigerServer.sh +++ b/slsDetectorServers/compileEigerServer.sh @@ -3,21 +3,31 @@ deterror="OK" dir="eigerDetectorServer" file="${dir}_developer" -branch="" + +usage="\nUsage: compileAllServers.sh [update_api(opt)]. \n\t update_api if true updates the api to version in VERSION file" + +update_api=true +target=version # arguments if [ $# -eq 1 ]; then - branch+=$1 - #echo "with branch $branch" + update_api=$1 + if not $update_api ; then + target=clean + + fi elif [ ! $# -eq 0 ]; then - echo -e "Only one optional argument allowed for branch." + echo -e "Only one optional argument allowed for update_api." return -1 fi +if $update_api; then + echo "updating api to $(cat ../VERSION)" +fi + echo -e "Compiling $dir [$file]" cd $dir -make clean -if make version API_BRANCH=$branch; then +if make $target; then deterror="OK" else deterror="FAIL" @@ -25,7 +35,6 @@ fi mv bin/$dir bin/$file git add -f bin/$file -cp bin/$file /tftpboot/ cd .. echo -e "\n\n" printf "Result:\t\t= %s\n" "${deterror}" diff --git a/slsDetectorServers/ctbDetectorServer/Makefile b/slsDetectorServers/ctbDetectorServer/Makefile index 5bdb5679d..0b56dd825 100755 --- a/slsDetectorServers/ctbDetectorServer/Makefile +++ b/slsDetectorServers/ctbDetectorServer/Makefile @@ -25,11 +25,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APICTB version_path=slsDetectorServers/ctbDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/eigerDetectorServer/Makefile b/slsDetectorServers/eigerDetectorServer/Makefile index 5d896249f..63910c6f9 100755 --- a/slsDetectorServers/eigerDetectorServer/Makefile +++ b/slsDetectorServers/eigerDetectorServer/Makefile @@ -25,11 +25,10 @@ version: clean versioning $(PROGS) #hv9m_blackfin_server boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIEIGER version_path=slsDetectorServers/eigerDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/gotthard2DetectorServer/Makefile b/slsDetectorServers/gotthard2DetectorServer/Makefile index f5fa63f14..b5670a658 100755 --- a/slsDetectorServers/gotthard2DetectorServer/Makefile +++ b/slsDetectorServers/gotthard2DetectorServer/Makefile @@ -24,11 +24,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIGOTTHARD2 version_path=slsDetectorServers/gotthard2DetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/gotthardDetectorServer/Makefile b/slsDetectorServers/gotthardDetectorServer/Makefile index 57ead7418..a280b6cd7 100755 --- a/slsDetectorServers/gotthardDetectorServer/Makefile +++ b/slsDetectorServers/gotthardDetectorServer/Makefile @@ -27,7 +27,7 @@ version_branch=$(API_BRANCH) version_name=APIGOTTHARD version_path=slsDetectorServers/gotthardDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/jungfrauDetectorServer/Makefile b/slsDetectorServers/jungfrauDetectorServer/Makefile index b54c0c188..881f2e660 100755 --- a/slsDetectorServers/jungfrauDetectorServer/Makefile +++ b/slsDetectorServers/jungfrauDetectorServer/Makefile @@ -24,11 +24,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIJUNGFRAU version_path=slsDetectorServers/jungfrauDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/moenchDetectorServer/Makefile b/slsDetectorServers/moenchDetectorServer/Makefile index 5f7457c19..71ebbf4fd 100755 --- a/slsDetectorServers/moenchDetectorServer/Makefile +++ b/slsDetectorServers/moenchDetectorServer/Makefile @@ -24,11 +24,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIMOENCH version_path=slsDetectorServers/moenchDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/mythen3DetectorServer/Makefile b/slsDetectorServers/mythen3DetectorServer/Makefile index fb03c9d12..b6d68fac0 100755 --- a/slsDetectorServers/mythen3DetectorServer/Makefile +++ b/slsDetectorServers/mythen3DetectorServer/Makefile @@ -25,11 +25,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIMYTHEN3 version_path=slsDetectorServers/mythen3DetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsDetectorServers/xilinx_ctbDetectorServer/Makefile b/slsDetectorServers/xilinx_ctbDetectorServer/Makefile index c271efdfe..075c649a6 100755 --- a/slsDetectorServers/xilinx_ctbDetectorServer/Makefile +++ b/slsDetectorServers/xilinx_ctbDetectorServer/Makefile @@ -36,11 +36,10 @@ version: clean versioning $(PROGS) boot: $(OBJS) -version_branch=$(API_BRANCH) version_name=APIXILINXCTB version_path=slsDetectorServers/xilinx_ctbDetectorServer versioning: - cd ../../ && echo $(PWD) && echo `tput setaf 6; ./updateAPIVersion.sh $(version_name) $(version_path) $(version_branch); tput sgr0;` + cd ../../ && echo $(PWD) && echo `tput setaf 6; python updateAPIVersion.py $(version_name) $(version_path); tput sgr0;` $(PROGS): $(OBJS) diff --git a/slsSupportLib/include/sls/Version.h b/slsSupportLib/include/sls/Version.h index 33d10c27e..6e97873e4 100644 --- a/slsSupportLib/include/sls/Version.h +++ b/slsSupportLib/include/sls/Version.h @@ -11,7 +11,7 @@ class Version { private: std::string version_; std::string date_; - const std::string defaultBranch_ = "developer"; + inline static const std::string defaultVersion_[] = {"developer", "0.0.0"}; public: explicit Version(const std::string &s); diff --git a/slsSupportLib/include/sls/versionAPI.h b/slsSupportLib/include/sls/versionAPI.h index 77eba3c20..0b39ad96f 100644 --- a/slsSupportLib/include/sls/versionAPI.h +++ b/slsSupportLib/include/sls/versionAPI.h @@ -8,6 +8,6 @@ #define APICTB "9.1.0 0x250204" #define APIXILINXCTB "9.1.0 0x250204" #define APIJUNGFRAU "9.1.0 0x250318" -#define APILIB "9.1.0 0x250325" +#define APILIB "9.2.0 0x250527" #define APIMYTHEN3 "9.1.1 0x250409" #define APIRECEIVER "9.1.1 0x250513" diff --git a/slsSupportLib/src/Version.cpp b/slsSupportLib/src/Version.cpp index 2be4e6c3e..03aeb5339 100644 --- a/slsSupportLib/src/Version.cpp +++ b/slsSupportLib/src/Version.cpp @@ -21,7 +21,8 @@ Version::Version(const std::string &s) { } bool Version::hasSemanticVersioning() const { - return version_ != defaultBranch_; + + return (version_ != defaultVersion_[0]) && (version_ != defaultVersion_[1]); } std::string Version::getVersion() const { return version_; } diff --git a/slsSupportLib/tests/CMakeLists.txt b/slsSupportLib/tests/CMakeLists.txt index 4fae7a346..827db97ff 100755 --- a/slsSupportLib/tests/CMakeLists.txt +++ b/slsSupportLib/tests/CMakeLists.txt @@ -14,6 +14,7 @@ target_sources(tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/test-TypeTraits.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-UdpRxSocket.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-logger.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/test-Version.cpp ${CMAKE_CURRENT_SOURCE_DIR}/test-ZmqSocket.cpp ) diff --git a/slsSupportLib/tests/test-Version.cpp b/slsSupportLib/tests/test-Version.cpp new file mode 100644 index 000000000..9c1f1d3f8 --- /dev/null +++ b/slsSupportLib/tests/test-Version.cpp @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: LGPL-3.0-or-other +// Copyright (C) 2021 Contributors to the SLS Detector Package +#include "catch.hpp" +#include "sls/Version.h" + +namespace sls { + +TEST_CASE("check if version is semantic", "[.version]") { + + auto [version_string, has_semantic_version] = + GENERATE(std::make_tuple("developer 0x250512", false), + std::make_tuple("0.0.0 0x250512", false)); + + Version version(version_string); + + CHECK(version.hasSemanticVersioning() == has_semantic_version); +} + +} // namespace sls diff --git a/tests/scripts/test_frame_synchronizer.py b/tests/scripts/test_frame_synchronizer.py index 87c784cf7..8d2915f0a 100644 --- a/tests/scripts/test_frame_synchronizer.py +++ b/tests/scripts/test_frame_synchronizer.py @@ -20,6 +20,7 @@ from utils_for_test import ( cleanSharedmemory, startProcessInBackground, startProcessInBackgroundWithLogFile, + checkLogForErrors, startDetectorVirtualServer, loadConfig, ParseArguments @@ -34,6 +35,9 @@ def startFrameSynchronizerPullSocket(name, fp): fname = PULL_SOCKET_PREFIX_FNAME + name + '.txt' cmd = ['python', '-u', 'frameSynchronizerPullSocket.py'] startProcessInBackgroundWithLogFile(cmd, fp, fname) + time.sleep(1) + checkLogForErrors(fp, fname) + def startFrameSynchronizer(num_mods, fp): @@ -44,16 +48,14 @@ def startFrameSynchronizer(num_mods, fp): time.sleep(1) -def acquire(fp): +def acquire(fp, det): Log(LogLevel.INFO, 'Acquiring') Log(LogLevel.INFO, 'Acquiring', fp) - d = Detector() - d.acquire() + det.acquire() -def testFramesCaught(name, num_frames): - d = Detector() - fnum = d.rx_framescaught[0] +def testFramesCaught(name, det, num_frames): + fnum = det.rx_framescaught[0] if fnum != num_frames: raise RuntimeException(f"{name} caught only {fnum}. Expected {num_frames}") @@ -61,7 +63,7 @@ def testFramesCaught(name, num_frames): Log(LogLevel.INFOGREEN, f'Frames caught test passed for {name}', fp) -def testZmqHeadetTypeCount(name, num_mods, num_frames, fp): +def testZmqHeadetTypeCount(name, det, num_mods, num_frames, fp): Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}") Log(LogLevel.INFO, f"Testing Zmq Header type count for {name}", fp) @@ -88,8 +90,7 @@ def testZmqHeadetTypeCount(name, num_mods, num_frames, fp): continue # test if file contents matches expected counts - d = Detector() - num_ports_per_module = 1 if name == "gotthard2" else d.numinterfaces + num_ports_per_module = 1 if name == "gotthard2" else det.numinterfaces total_num_frame_parts = num_ports_per_module * num_mods * num_frames for htype, expected_count in [("header", num_mods), ("series_end", num_mods), ("module", total_num_frame_parts)]: if htype_counts[htype] != expected_count: @@ -111,10 +112,10 @@ def startTestsForAll(args, fp): startDetectorVirtualServer(server, args.num_mods, fp) startFrameSynchronizerPullSocket(server, fp) startFrameSynchronizer(args.num_mods, fp) - loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames) - acquire(fp) - testFramesCaught(server, args.num_frames) - testZmqHeadetTypeCount(server, args.num_mods, args.num_frames, fp) + d = loadConfig(name=server, rx_hostname=args.rx_hostname, settingsdir=args.settingspath, fp=fp, num_mods=args.num_mods, num_frames=args.num_frames) + acquire(fp, d) + testFramesCaught(server, d, args.num_frames) + testZmqHeadetTypeCount(server, d, args.num_mods, args.num_frames, fp) Log(LogLevel.INFO, '\n') except Exception as e: raise RuntimeException(f'Synchronizer Tests failed') from e diff --git a/tests/scripts/utils_for_test.py b/tests/scripts/utils_for_test.py index 389bfad4a..bc703648a 100644 --- a/tests/scripts/utils_for_test.py +++ b/tests/scripts/utils_for_test.py @@ -104,7 +104,7 @@ def startProcessInBackground(cmd, fp): raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e -def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name): +def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name: str): Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name) Log(LogLevel.INFOBLUE, 'Starting up ' + ' '.join(cmd) + '. Log: ' + log_file_name, fp) try: @@ -114,6 +114,22 @@ def startProcessInBackgroundWithLogFile(cmd, fp, log_file_name): raise RuntimeException(f'Failed to start {cmd}:{str(e)}') from e +def checkLogForErrors(fp, log_file_path: str): + try: + with open(log_file_path, 'r') as log_file: + for line in log_file: + if 'Error' in line: + Log(LogLevel.ERROR, f"Error found in log: {line.strip()}") + Log(LogLevel.ERROR, f"Error found in log: {line.strip()}", fp) + raise RuntimeException("Error found in log file") + except FileNotFoundError: + print(f"Log file not found: {log_file_path}") + raise + except Exception as e: + print(f"Exception while reading log: {e}") + raise + + def runProcessWithLogFile(name, cmd, fp, log_file_name): Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name) Log(LogLevel.INFOBLUE, 'Running ' + name + '. Log: ' + log_file_name, fp) @@ -142,7 +158,7 @@ def startDetectorVirtualServer(name :str, num_mods, fp): cmd = [name + 'DetectorServer_virtual', '-p', str(port_no)] if name == 'gotthard': cmd += ['-m', '1'] - startProcessInBackground(cmd, fp) + startProcessInBackgroundWithLogFile(cmd, fp, "/tmp/virtual_det_" + name + str(i) + ".txt") match name: case 'jungfrau': time.sleep(7) @@ -206,6 +222,8 @@ def loadConfig(name, rx_hostname, settingsdir, fp, num_mods = 1, num_frames = 1) d.frames = num_frames except Exception as e: raise RuntimeException(f'Could not load config for {name}. Error: {str(e)}') from e + + return d def ParseArguments(description, default_num_mods=1): diff --git a/updateAPIVersion.py b/updateAPIVersion.py new file mode 100644 index 000000000..4d0cf7ccf --- /dev/null +++ b/updateAPIVersion.py @@ -0,0 +1,81 @@ +# SPDX-License-Identifier: LGPL-3.0-or-other +# Copyright (C) 2025 Contributors to the SLS Detector Package +""" +Script to update API VERSION file based on the version in VERSION file. +""" + +import argparse +import sys +import os +import re +import time +from datetime import datetime + + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + +API_FILE = SCRIPT_DIR + "/slsSupportLib/include/sls/versionAPI.h" + +VERSION_FILE = SCRIPT_DIR + "/VERSION" + +parser = argparse.ArgumentParser(description = 'updates API version') +parser.add_argument('api_module_name', choices=["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"], help = 'module name to change api version options are: ["APILIB", "APIRECEIVER", "APICTB", "APIGOTTHARD2", "APIMOENCH", "APIEIGER", "APIXILINXCTB", "APIJUNGFRAU", "APIMYTHEN3"]') +parser.add_argument('api_dir', help = 'Relative or absolute path to the module code') + +def update_api_file(new_api : str, api_module_name : str, api_file_name : str): + + regex_pattern = re.compile(rf'#define\s+{api_module_name}\s+') + with open(api_file_name, "r") as api_file: + lines = api_file.readlines() + + with open(api_file_name, "w") as api_file: + for line in lines: + if regex_pattern.match(line): + api_file.write(f'#define {api_module_name} "{new_api}"\n') + else: + api_file.write(line) + +def get_latest_modification_date(directory : str): + latest_time = 0 + latest_date = None + + for root, dirs, files in os.walk(directory): + for file in files: + if file.endswith(".o"): + continue + full_path = os.path.join(root, file) + try: + mtime = os.path.getmtime(full_path) + if mtime > latest_time: + latest_time = mtime + except FileNotFoundError: + continue + + latest_date = datetime.fromtimestamp(latest_time).strftime("%y%m%d") + + return latest_date + + +def update_api_version(api_module_name : str, api_dir : str): + api_date = get_latest_modification_date(api_dir) + api_date = "0x"+str(api_date) + + with open(VERSION_FILE, "r") as version_file: + api_version = version_file.read().strip() + + api_version = api_version + " " + api_date #not sure if we should give an argument option version_branch + + update_api_file(api_version, api_module_name, API_FILE) + + print(f"updated {api_module_name} api version to: {api_version}") + +if __name__ == "__main__": + + args = parser.parse_args() + + api_dir = SCRIPT_DIR + "/" + args.api_dir + + + update_api_version(args.api_module_name, api_dir) + + diff --git a/updateAPIVersion.sh b/updateAPIVersion.sh deleted file mode 100755 index 8c45e0c48..000000000 --- a/updateAPIVersion.sh +++ /dev/null @@ -1,65 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package -usage="\nUsage: updateAPIVersion.sh [API_NAME] [API_DIR] [API_BRANCH(opt)]." - -if [ $# -lt 2 ]; then - echo -e "Requires atleast 2 arguments. $usage" - return [-1] -fi - -API_NAME=$1 -PACKAGE_DIR=$PWD -API_DIR=$PACKAGE_DIR/$2 -API_FILE=$PACKAGE_DIR/slsSupportLib/include/sls/versionAPI.h -CURR_DIR=$PWD - -if [ ! -d "$API_DIR" ]; then - echo "[API_DIR] does not exist. $usage" - return [-1] -fi - -#go to directory -cd $API_DIR - -#deleting line from file -NUM=$(sed -n '/'$API_NAME' /=' $API_FILE) -#echo $NUM - - -if [ "$NUM" -gt 0 ]; then - sed -i ${NUM}d $API_FILE -fi - -#find new API date -API_DATE="find . -printf \"%T@ %CY-%Cm-%Cd\n\"| sort -nr | cut -d' ' -f2- | egrep -v '(\.)o' | head -n 1" - -API_DATE=`eval $API_DATE` - -API_DATE=$(sed "s/-//g" <<< $API_DATE | awk '{print $1;}' ) - -#extracting only date -API_DATE=${API_DATE:2:6} - -#prefix of 0x -API_DATE=${API_DATE/#/0x} -echo "date="$API_DATE - - -# API_VAL concatenates branch and date -API_VAL="" -# API branch is defined (3rd argument) -if [ $# -eq 3 ]; then - API_BRANCH=$3 - echo "branch="$API_BRANCH - API_VAL+="\"$API_BRANCH $API_DATE\"" -else - # API branch not defined (default is developer) - echo "branch=developer" - API_VAL+="\"developer $API_DATE\"" -fi - -#copy it to versionAPI.h -echo "#define "$API_NAME $API_VAL >> $API_FILE - -#go back to original directory -cd $CURR_DIR diff --git a/updateClientAPIVersion.py b/updateClientAPIVersion.py new file mode 100644 index 000000000..d7764cff9 --- /dev/null +++ b/updateClientAPIVersion.py @@ -0,0 +1,34 @@ +# SPDX-License-Identifier: LGPL-3.0-or-other +# Copyright (C) 2025 Contributors to the SLS Detector Package +""" +Script to update API VERSION for slsReceiverSoftware or slsDetectorSoftware +""" + +import argparse +import os + +from updateAPIVersion import update_api_version + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + +parser = argparse.ArgumentParser(description = 'updates API version') +parser.add_argument('module_name', nargs="?", choices=["slsDetectorSoftware", "slsReceiverSoftware", "all"], default="all", help = 'module name to change api version options are: ["slsDetectorSoftware", "slsReceiverSoftware, "all"]') + +if __name__ == "__main__": + args = parser.parse_args() + + if args.module_name == "all": + client_names = ["APILIB", "APIRECEIVER"] + client_directories = [SCRIPT_DIR+"/slsDetectorSoftware", SCRIPT_DIR+"/slsReceiverSoftware"] + elif args.module_name == "slsDetectorSoftware": + client_names = ["APILIB"] + client_directories = [SCRIPT_DIR+"/slsDetectorSoftware"] + else: + client_names = ["APIRECEIVER"] + client_directories = [SCRIPT_DIR+"/slsReceiverSoftware"] + + for client_name, client_directory in zip(client_names, client_directories): + update_api_version(client_name, client_directory) + + + diff --git a/updateClientAPIVersion.sh b/updateClientAPIVersion.sh deleted file mode 100755 index bed281622..000000000 --- a/updateClientAPIVersion.sh +++ /dev/null @@ -1,59 +0,0 @@ -# SPDX-License-Identifier: LGPL-3.0-or-other -# Copyright (C) 2021 Contributors to the SLS Detector Package -branch="" -client_list=("slsDetectorSoftware" "slsReceiverSoftware") -usage="\nUsage: updateClientAPI.sh [all|slsDetectorSoftware|slsReceiverSoftware] [branch]. \n\tNo arguments means all with 'developer' branch. \n\tNo 'branch' input means 'developer branch'" - -# arguments -if [ $# -eq 0 ]; then - declare -a client=${client_list[@]} - echo "API Versioning all" -elif [ $# -eq 1 ] || [ $# -eq 2 ]; then - # 'all' client - if [[ $1 == "all" ]]; then - declare -a client=${client_list[@]} - echo "API Versioning all" - else - # only one server - if [[ $client_list != *$1* ]]; then - echo -e "Invalid argument 1: $1. $usage" - return -1 - fi - declare -a client=("${1}") - #echo "Versioning only $1" - fi - if [ $# -eq 2 ]; then - if [[ $client_list == *$2* ]]; then - echo -e "Invalid argument 2: $2. $usage" - return -1 - fi - branch+=$2 - #echo "with branch $branch" - fi -else - echo -e "Too many arguments.$usage" - return -1 -fi - -#echo "list is: ${client[@]}" - -# versioning each client -for i in ${client[@]} -do - dir=$i - case $dir in - slsDetectorSoftware) - declare -a name=APILIB - ;; - slsReceiverSoftware) - declare -a name=APIRECEIVER - ;; - *) - echo -n "unknown client argument $i" - return -1 - ;; - esac - echo -e "Versioning $dir [$name]" - ./updateAPIVersion.sh $name $dir $branch -done - diff --git a/update_version.py b/update_version.py index c074ae542..6b3e1ebad 100644 --- a/update_version.py +++ b/update_version.py @@ -5,7 +5,12 @@ Script to update VERSION file with semantic versioning if provided as an argumen """ import sys -import re +import os + +from packaging.version import Version, InvalidVersion + + +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) def get_version(): @@ -14,23 +19,24 @@ def get_version(): return "0.0.0" version = sys.argv[1] - - # Validate that the version argument matches semantic versioning format (X.Y.Z) - if not re.match(r'^\d+\.\d+\.\d+$', version): - print("Error: Version argument must be in semantic versioning format (X.Y.Z)") + + try: + v = Version(version) # normalizcheck if version follows PEP 440 specification + #replace - + return version.replace("-", ".") + except InvalidVersion as e: + print(f"Invalid version {version}. Version format must follow semantic versioning format of python PEP 440 version identification specification.") sys.exit(1) - return version - def write_version_to_file(version): - with open("VERSION", "w") as version_file: + version_file_path = os.path.join(SCRIPT_DIR, "VERSION") + with open(version_file_path, "w") as version_file: version_file.write(version) print(f"Version {version} written to VERSION file.") - # Main script if __name__ == "__main__": version = get_version() - write_version_to_file(version) \ No newline at end of file + write_version_to_file(version)