Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package redis++ for openSUSE:Factory checked in at 2026-03-30 18:34:04 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/redis++ (Old) and /work/SRC/openSUSE:Factory/.redis++.new.1999 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "redis++" Mon Mar 30 18:34:04 2026 rev:13 rq:1343672 version:1.3.15 Changes: -------- --- /work/SRC/openSUSE:Factory/redis++/redis++.changes 2025-05-20 09:40:15.039139185 +0200 +++ /work/SRC/openSUSE:Factory/.redis++.new.1999/redis++.changes 2026-03-30 18:38:21.128747114 +0200 @@ -1,0 +2,9 @@ +Sun Mar 29 22:06:09 UTC 2026 - Dirk Müller <[email protected]> + +- update to 1.3.15: + * Support cmake FetchContent feature + * Support more hash commands + * Make variant parser more efficient + * Fix event loop crash: avoid closing handle opened by hiredis + +------------------------------------------------------------------- Old: ---- redis++-1.3.14.tar.gz New: ---- redis++-1.3.15.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ redis++.spec ++++++ --- /var/tmp/diff_new_pack.fMk2Zh/_old 2026-03-30 18:38:21.624767827 +0200 +++ /var/tmp/diff_new_pack.fMk2Zh/_new 2026-03-30 18:38:21.624767827 +0200 @@ -1,7 +1,7 @@ # # spec file for package redis++ # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2026 SUSE LLC and contributors # Copyright (c) 2025 Andreas Stieger <[email protected]> # # All modifications and additions to the file contributed by third parties @@ -19,7 +19,7 @@ %define sover 1 Name: redis++ -Version: 1.3.14 +Version: 1.3.15 Release: 0 Summary: C++ client for Redis License: Apache-2.0 ++++++ redis++-1.3.14.tar.gz -> redis++-1.3.15.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/.github/workflows/build-and-test.yml new/redis-plus-plus-1.3.15/.github/workflows/build-and-test.yml --- old/redis-plus-plus-1.3.14/.github/workflows/build-and-test.yml 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/.github/workflows/build-and-test.yml 2025-07-22 16:58:50.000000000 +0200 @@ -26,6 +26,7 @@ matrix: os: [ubuntu-latest] build_type: [Release] + redis_version: [7.2.8] c_compiler: [gcc, clang] include: - os: ubuntu-latest @@ -39,12 +40,21 @@ - uses: actions/checkout@v4 - name: libuv-dep - run: sudo apt-get update && sudo apt-get install -y libuv1-dev wget unzip + run: | + sudo apt-get update + sudo apt-get install -yq libuv1-dev wget unzip - name: redis-dep run: | - wget -L https://github.com/redis/redis/archive/refs/tags/7.2.3.zip -O redis-7.2.3.zip && unzip redis-7.2.3.zip - cd redis-7.2.3 && make -j2 && ./src/redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --daemonize yes && ./src/redis-server --port 7001 --cluster-enabled yes --cluster-config-file nodes-7001.conf --daemonize yes && ./src/redis-server --port 7002 --cluster-enabled yes --cluster-config-file nodes-7002.conf --daemonize yes && ./src/redis-cli --cluster-yes --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 && ./src/redis-server --daemonize yes + wget -L https://github.com/redis/redis/archive/refs/tags/${{matrix.redis_version}}.zip -O redis-${{matrix.redis_version}}.zip + unzip redis-${{matrix.redis_version}}.zip + cd redis-${{matrix.redis_version}} + make -j2 + ./src/redis-server --port 7000 --cluster-enabled yes --cluster-config-file nodes-7000.conf --daemonize yes + ./src/redis-server --port 7001 --cluster-enabled yes --cluster-config-file nodes-7001.conf --daemonize yes + ./src/redis-server --port 7002 --cluster-enabled yes --cluster-config-file nodes-7002.conf --daemonize yes + sleep 2 + ./src/redis-cli --cluster-yes --cluster create 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 && ./src/redis-server --daemonize yes - name: hiredis-dep run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/CMakeLists.txt new/redis-plus-plus-1.3.15/CMakeLists.txt --- old/redis-plus-plus-1.3.14/CMakeLists.txt 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/CMakeLists.txt 2025-07-22 16:58:50.000000000 +0200 @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) function(GET_VERSION VERSION_PART VERSION_NUM) set(VERSION_REGEX "^const int VERSION_${VERSION_PART} = (.+);$") @@ -139,52 +139,27 @@ endif() # hiredis dependency -find_package(hiredis QUIET) -if(hiredis_FOUND) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS hiredis::hiredis) - - if(REDIS_PLUS_PLUS_USE_TLS) - find_package(hiredis_ssl REQUIRED) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS hiredis::hiredis_ssl) - find_package(OpenSSL REQUIRED) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${OPENSSL_LIBRARIES}) - endif() -else() - find_path(HIREDIS_HEADER hiredis) - find_library(HIREDIS_LIB hiredis) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${HIREDIS_LIB}) - - if(REDIS_PLUS_PLUS_USE_TLS) - find_library(HIREDIS_TLS_LIB hiredis_ssl) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${HIREDIS_TLS_LIB}) - find_package(OpenSSL REQUIRED) - list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${OPENSSL_LIBRARIES}) - endif() -endif() +include(${CMAKE_CURRENT_LIST_DIR}/cmake/FindHiredis.cmake) # Check hiredis features message(STATUS "redis-plus-plus check hiredis features") if(hiredis_FOUND) set(HIREDIS_FEATURE_TEST_INCLUDE ${hiredis_INCLUDE_DIRS}) - set(HIREDIS_FEATURE_TEST_LIB ${REDIS_PLUS_PLUS_HIREDIS_LIBS}) else() set(HIREDIS_FEATURE_TEST_INCLUDE ${HIREDIS_HEADER}) - set(HIREDIS_FEATURE_TEST_LIB ${HIREDIS_LIB}) endif() set(HIREDIS_FEATURE_TEST_HEADER "${HIREDIS_FEATURE_TEST_INCLUDE}/hiredis/hiredis.h") -include(CheckSymbolExists) -set(CMAKE_REQUIRED_LIBRARIES_BACK ${CMAKE_REQUIRED_LIBRARIES}) -set(CMAKE_REQUIRED_LIBRARIES ${HIREDIS_FEATURE_TEST_LIB}) +file(READ "${HIREDIS_FEATURE_TEST_HEADER}" HIREDIS_HEADER_CONTENT) -CHECK_SYMBOL_EXISTS(redisEnableKeepAliveWithInterval ${HIREDIS_FEATURE_TEST_HEADER} REDIS_PLUS_PLUS_HAS_redisEnableKeepAliveWithInterval) +string(FIND "${HIREDIS_HEADER_CONTENT}" redisEnableKeepAliveWithInterval redisEnableKeepAliveWithInterval_POS) +if(${redisEnableKeepAliveWithInterval_POS} GREATER -1) + set(REDIS_PLUS_PLUS_HAS_redisEnableKeepAliveWithInterval ON) +endif() set(REDIS_PLUS_PLUS_GENERATED_HEADER_DIR ${CMAKE_CURRENT_BINARY_DIR}/${REDIS_PLUS_PLUS_HEADER_DIR}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/hiredis_features.h.in ${CMAKE_CURRENT_BINARY_DIR}/${REDIS_PLUS_PLUS_SOURCE_DIR}/hiredis_features.h) -# Restore CMAKE_REQUIRED_LIBRARIES -set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES_BACK}) - # Build static library option(REDIS_PLUS_PLUS_BUILD_STATIC "Build static library" ON) message(STATUS "redis-plus-plus build static library: ${REDIS_PLUS_PLUS_BUILD_STATIC}") @@ -273,11 +248,10 @@ if(hiredis_FOUND) target_include_directories(${SHARED_LIB} PUBLIC $<BUILD_INTERFACE:${hiredis_INCLUDE_DIRS}>) - target_link_libraries(${SHARED_LIB} PUBLIC ${REDIS_PLUS_PLUS_HIREDIS_LIBS}) else() target_include_directories(${SHARED_LIB} PUBLIC $<BUILD_INTERFACE:${HIREDIS_HEADER}>) - target_link_libraries(${SHARED_LIB} PUBLIC ${REDIS_PLUS_PLUS_HIREDIS_LIBS}) endif() + target_link_libraries(${SHARED_LIB} PUBLIC ${REDIS_PLUS_PLUS_HIREDIS_LIBS}) if(REDIS_PLUS_PLUS_BUILD_ASYNC) target_include_directories(${SHARED_LIB} PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/${REDIS_PLUS_PLUS_ASYNC_FUTURE_HEADER}>) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/README.md new/redis-plus-plus-1.3.15/README.md --- old/redis-plus-plus-1.3.14/README.md 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/README.md 2025-07-22 16:58:50.000000000 +0200 @@ -8,7 +8,6 @@ - [Overview](#overview) - [Features](#features) - - [Branches](#branches) - [Installation](#installation) - [Install hiredis](#install-hiredis) - [Install redis-plus-plus](#install-redis-plus-plus) @@ -59,17 +58,13 @@ - Sync and Async interface. - Coroutine support. -### Branches - -The master branch is the stable branch, which passes all tests. The dev branch is unstable. If you want to contribute, please create pull request on dev branch. - ## Installation ### Install hiredis Since *redis-plus-plus* is based on *hiredis*, you should install *hiredis* first. The minimum version requirement for *hiredis* is **v0.12.1**. However, [the latest stable release](https://github.com/redis/hiredis/releases) of *hiredis* is always recommended. -**NOTE**: You must ensure that there's only 1 version of hiredis is installed. Otherwise, you might get some wired problems. Check the following issues for example: [issue 135](https://github.com/sewenew/redis-plus-plus/issues/135), [issue 140](https://github.com/sewenew/redis-plus-plus/issues/140) and [issue 158](https://github.com/sewenew/redis-plus-plus/issues/158). +**NOTE**: You must ensure that there's only 1 version of *hiredis* installed. Otherwise, you might get some weird problems. Check the following issues for example: [issue 135](https://github.com/sewenew/redis-plus-plus/issues/135), [issue 140](https://github.com/sewenew/redis-plus-plus/issues/140) and [issue 158](https://github.com/sewenew/redis-plus-plus/issues/158). Normally, you can install *hiredis* with a C++ package manager, and that's the easiest way to do it, e.g. `sudo apt-get install libhiredis-dev`. However, if you want to install the latest code of hiredis, or a specified version (e.g. async support needs hiredis v1.0.0 or later), you can install it from source. @@ -82,7 +77,7 @@ make -make install +sudo make install ``` By default, *hiredis* is installed at */usr/local*. If you want to install *hiredis* at non-default location, use the following commands to specify the installation path. @@ -110,7 +105,7 @@ make -make install +sudo make install cd .. ``` @@ -139,6 +134,10 @@ *redis-plus-plus* builds static library with `-fPIC` option, i.e. Position Independent Code, by default. However, you can disable it with `-DREDIS_PLUS_PLUS_BUILD_STATIC_WITH_PIC=OFF`. +#### FetchContent + +You can also use cmake's [FetchContent](https://cmake.org/cmake/help/latest/module/FetchContent.html) feature to install redis-plus-plus. Check [this](https://github.com/sewenew/redis-plus-plus/pull/639) for an example. + #### Windows Support Now *hiredis* has Windows support, and since Visual Studio 2017, Visual Studio has built-in support for CMake. So *redis-plus-plus* also supports Windows platform now. It has been fully tested with Visual Studio 2017 and later on Win 10. I'm not familiar with Visual Studio environment, and the following doc might not be accurate. If you're familiar with the Windows platform, feel free to update this doc on how to install *redis-plus-plus* on Windows. @@ -206,7 +205,7 @@ **NOTE**: -- Since 1.3.0, *redis-puls-plus* is built with C++17 by default, and you should also set your application code to be built with C++17. If you still want to build the *redis-plus-plus* with C++11, you can set the `REDIS_PLUS_PLUS_CXX_STANDARD` cmake option to 11. +- Since 1.3.0, *redis-plus-plus* is built with C++17 by default, and you should also set your application code to be built with C++17. If you still want to build the *redis-plus-plus* with C++11, you can set the `REDIS_PLUS_PLUS_CXX_STANDARD` cmake option to 11. - TLS/SSL support has not been tested on Windows yet. ##### Build with Visual Studio diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/cmake/FindHiredis.cmake new/redis-plus-plus-1.3.15/cmake/FindHiredis.cmake --- old/redis-plus-plus-1.3.14/cmake/FindHiredis.cmake 1970-01-01 01:00:00.000000000 +0100 +++ new/redis-plus-plus-1.3.15/cmake/FindHiredis.cmake 2025-07-22 16:58:50.000000000 +0200 @@ -0,0 +1,38 @@ +find_package(hiredis QUIET) +if(hiredis_FOUND) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS hiredis::hiredis) + + if(NOT hiredis_INCLUDE_DIRS) + # This can happen when hiredis is included with FetchContent with OVERRIDE_FIND_PACKAGE + find_path( + hiredis_INCLUDE_DIRS + hiredis.h + PATHS + ${CMAKE_BINARY_DIR}/_deps/hiredis + ${CMAKE_CURRENT_BINARY_DIR}/_deps/hiredis + NO_CACHE + REQUIRED + ) + + # Remove the trailing /hiredis from the include path so that we can include hiredis with hiredis/hiredis.h + get_filename_component(hiredis_INCLUDE_DIRS "${hiredis_INCLUDE_DIRS}" DIRECTORY) + endif() + + if(REDIS_PLUS_PLUS_USE_TLS) + find_package(hiredis_ssl REQUIRED) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS hiredis::hiredis_ssl) + find_package(OpenSSL REQUIRED) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${OPENSSL_LIBRARIES}) + endif() +else() + find_path(HIREDIS_HEADER hiredis) + find_library(HIREDIS_LIB hiredis) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${HIREDIS_LIB}) + + if(REDIS_PLUS_PLUS_USE_TLS) + find_library(HIREDIS_TLS_LIB hiredis_ssl) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${HIREDIS_TLS_LIB}) + find_package(OpenSSL REQUIRED) + list(APPEND REDIS_PLUS_PLUS_HIREDIS_LIBS ${OPENSSL_LIBRARIES}) + endif() +endif() \ No newline at end of file diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/command.h new/redis-plus-plus-1.3.15/src/sw/redis++/command.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/command.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/command.h 2025-07-22 16:58:50.000000000 +0200 @@ -792,6 +792,208 @@ connection.send(args); } +template <typename Input> +void hsetex_keep_ttl_range(Connection &connection, + const StringView &key, + Input first, + Input last, + bool keep_ttl, + HSetExOption opt) { + assert(first != last); + + CmdArgs args; + args << "HSETEX" << key; + + switch (opt) { + case HSetExOption::FNX: + args << "FNX"; + break; + case HSetExOption::FXX: + args << "FXX"; + break; + case HSetExOption::ALWAYS: + break; + default: + throw Error("unknown HSetExOption"); + } + + if (keep_ttl) { + args << "KEEPTTL"; + } + + auto keys_num = std::distance(first, last); + args << "FIELDS" << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hsetex_ttl_range(Connection &connection, + const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HSetExOption opt) { + assert(first != last); + + CmdArgs args; + args << "HSETEX" << key; + + switch (opt) { + case HSetExOption::FNX: + args << "FNX"; + break; + case HSetExOption::FXX: + args << "FXX"; + break; + case HSetExOption::ALWAYS: + break; + default: + throw Error("unknown HSetExOption"); + } + + args << "PX" << ttl.count(); + + auto keys_num = std::distance(first, last); + args << "FIELDS" << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hsetex_time_point_range(Connection &connection, + const StringView &key, + Input first, + Input last, + const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> &tp, + HSetExOption opt) { + assert(first != last); + + CmdArgs args; + args << "HSETEX" << key; + + switch (opt) { + case HSetExOption::FNX: + args << "FNX"; + break; + case HSetExOption::FXX: + args << "FXX"; + break; + case HSetExOption::ALWAYS: + break; + default: + throw Error("unknown HSetExOption"); + } + + args << "PXAT" << tp.time_since_epoch().count(); + + auto keys_num = std::distance(first, last); + args << "FIELDS" << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void httl_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HTTL" << key << "FIELDS"; + + auto keys_num = std::distance(first, last); + args << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hpttl_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HPTTL" << key << "FIELDS"; + + auto keys_num = std::distance(first, last); + args << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hexpiretime_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HEXPIRETIME" << key << "FIELDS"; + + auto keys_num = std::distance(first, last); + args << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hpexpiretime_range(Connection &connection, + const StringView &key, + Input first, + Input last) { + assert(first != last); + + CmdArgs args; + args << "HPEXPIRETIME" << key << "FIELDS"; + + auto keys_num = std::distance(first, last); + args << keys_num << std::make_pair(first, last); + + connection.send(args); +} + +template <typename Input> +void hpexpire_range(Connection &connection, + const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HPExpireOption opt) { + assert(first != last); + + CmdArgs args; + args << "HPEXPIRE" << key << ttl.count(); + + switch (opt) { + case HPExpireOption::NX: + args << "NX"; + break; + case HPExpireOption::XX: + args << "XX"; + break; + case HPExpireOption::GT: + args << "GT"; + break; + case HPExpireOption::LT: + args << "LT"; + break; + case HPExpireOption::ALWAYS: + break; + default: + throw Error("unknown hpexpire option"); + } + + auto keys_num = std::distance(first, last); + args << "FIELDS" << keys_num << std::make_pair(first, last); + + connection.send(args); +} + inline void hsetnx(Connection &connection, const StringView &key, const StringView &field, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/command_options.h new/redis-plus-plus-1.3.15/src/sw/redis++/command_options.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/command_options.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/command_options.h 2025-07-22 16:58:50.000000000 +0200 @@ -216,6 +216,20 @@ std::string to_string(ListWhence whence); +enum class HSetExOption { + FNX = 0, + FXX, + ALWAYS +}; + +enum class HPExpireOption { + NX = 0, + XX, + GT, + LT, + ALWAYS +}; + } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/event_loop.cpp new/redis-plus-plus-1.3.15/src/sw/redis++/event_loop.cpp --- old/redis-plus-plus-1.3.14/src/sw/redis++/event_loop.cpp 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/event_loop.cpp 2025-07-22 16:58:50.000000000 +0200 @@ -16,6 +16,8 @@ #include "sw/redis++/event_loop.h" #include <cassert> +#include <chrono> +#include <thread> #include <hiredis/adapters/libuv.h> #include "sw/redis++/async_connection.h" @@ -208,26 +210,42 @@ // How to correctly close an event loop: // https://stackoverflow.com/questions/25615340/closing-libuv-handles-correctly // TODO: do we need to call this? Since we always has 2 async_t handles. - if (uv_loop_close(loop) == 0) { - delete loop; + //if (uv_loop_close(loop) == 0) { + // delete loop; + // + // return; + //} - return; - } + assert(loop->data != nullptr); uv_walk(loop, - [](uv_handle_t *handle, void *) { + [](uv_handle_t *handle, void *arg) { if (handle != nullptr) { - // We don't need to release handle's memory in close callback, - // since we'll release the memory in EventLoop's destructor. - uv_close(handle, nullptr); + auto *event_loop = static_cast<EventLoop *>(arg); + + assert(event_loop != nullptr); + + if (handle == reinterpret_cast<uv_handle_t *>(event_loop->_event_async.get()) || + handle == reinterpret_cast<uv_handle_t *>(event_loop->_stop_async.get())) { + // We don't need to release handle's memory in close callback, + // since we'll release the memory in EventLoop's destructor. + uv_close(handle, nullptr); + } } }, - nullptr); + loop->data); // Ensure uv_walk's callback to be called. uv_run(loop, UV_RUN_DEFAULT); - uv_loop_close(loop); + for (auto idx = 0; idx < 10; ++idx) { + if (uv_loop_close(loop) == 0) { + break; + } + + // maybe hiredis does not close the handle yet? wait a while. + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } delete loop; } @@ -271,7 +289,7 @@ return uv_async; } -EventLoop::LoopUPtr EventLoop::_create_event_loop() const { +EventLoop::LoopUPtr EventLoop::_create_event_loop() { auto *loop = new uv_loop_t; auto err = uv_loop_init(loop); if (err != 0) { @@ -279,6 +297,8 @@ throw Error("failed to initialize event loop: " + _err_msg(err)); } + loop->data = this; + return LoopUPtr(loop); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/event_loop.h new/redis-plus-plus-1.3.15/src/sw/redis++/event_loop.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/event_loop.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/event_loop.h 2025-07-22 16:58:50.000000000 +0200 @@ -73,7 +73,7 @@ return uv_strerror(err); } - LoopUPtr _create_event_loop() const; + LoopUPtr _create_event_loop(); using UvAsyncUPtr = std::unique_ptr<uv_async_t>; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/redis.h new/redis-plus-plus-1.3.15/src/sw/redis++/redis.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/redis.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/redis.h 2025-07-22 16:58:50.000000000 +0200 @@ -1675,6 +1675,57 @@ return hset(key, il.begin(), il.end()); } + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + bool keep_ttl = false, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> &tp, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input, typename Output> + void httl(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpttl(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hexpiretime(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpexpiretime(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + Output output); + + template <typename Input, typename Output> + void hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HPExpireOption opt, + Output output); + /// @brief Set hash field to value, only if the given field does not exist. /// @param key Key where the hash is stored. /// @param field Field. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/redis.hpp new/redis-plus-plus-1.3.15/src/sw/redis++/redis.hpp --- old/redis-plus-plus-1.3.14/src/sw/redis++/redis.hpp 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/redis.hpp 2025-07-22 16:58:50.000000000 +0200 @@ -437,6 +437,114 @@ return reply::parse<long long>(*reply); } +template <typename Input> +auto Redis::hsetex(const StringView &key, + Input first, + Input last, + bool keep_ttl, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_keep_ttl_range<Input>, key, first, last, keep_ttl, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input> +auto Redis::hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_ttl_range<Input>, key, first, last, ttl, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input> +auto Redis::hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> &tp, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_time_point_range<Input>, key, first, last, tp, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input, typename Output> +void Redis::httl(const StringView &key, Input first, Input last, Output output) { + range_check("HTTL", first, last); + + auto reply = command(cmd::httl_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void Redis::hpttl(const StringView &key, Input first, Input last, Output output) { + range_check("HPTTL", first, last); + + auto reply = command(cmd::hpttl_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void Redis::hexpiretime(const StringView &key, Input first, Input last, Output output) { + range_check("HEXPIRETIME", first, last); + + auto reply = command(cmd::hexpiretime_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void Redis::hpexpiretime(const StringView &key, Input first, Input last, Output output) { + range_check("HPEXPIRETIME", first, last); + + auto reply = command(cmd::hpexpiretime_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void Redis::hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + Output output) { + range_check("HPEXPIRE", first, last); + + auto reply = command(cmd::hpexpire_range<Input>, key, first, last, ttl, HPExpireOption::ALWAYS); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void Redis::hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HPExpireOption opt, + Output output) { + range_check("HPEXPIRE", first, last); + + auto reply = command(cmd::hpexpire_range<Input>, key, first, last, ttl, opt); + + reply::to_array(*reply, output); +} + template <typename Output> inline void Redis::hvals(const StringView &key, Output output) { auto reply = command(cmd::hvals, key); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/redis_cluster.h new/redis-plus-plus-1.3.15/src/sw/redis++/redis_cluster.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/redis_cluster.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/redis_cluster.h 2025-07-22 16:58:50.000000000 +0200 @@ -499,6 +499,57 @@ return hset(key, il.begin(), il.end()); } + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + bool keep_ttl = false, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input> + auto hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> &tp, + HSetExOption opt = HSetExOption::ALWAYS) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, long long>::type; + + template <typename Input, typename Output> + void httl(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpttl(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hexpiretime(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpexpiretime(const StringView &key, Input first, Input last, Output output); + + template <typename Input, typename Output> + void hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + Output output); + + template <typename Input, typename Output> + void hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HPExpireOption opt, + Output output); + bool hsetnx(const StringView &key, const StringView &field, const StringView &val); bool hsetnx(const StringView &key, const std::pair<StringView, StringView> &item); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/redis_cluster.hpp new/redis-plus-plus-1.3.15/src/sw/redis++/redis_cluster.hpp --- old/redis-plus-plus-1.3.14/src/sw/redis++/redis_cluster.hpp 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/redis_cluster.hpp 2025-07-22 16:58:50.000000000 +0200 @@ -407,6 +407,114 @@ return reply::parse<long long>(*reply); } +template <typename Input> +auto RedisCluster::hsetex(const StringView &key, + Input first, + Input last, + bool keep_ttl, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_keep_ttl_range<Input>, key, first, last, keep_ttl, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input> +auto RedisCluster::hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_ttl_range<Input>, key, first, last, ttl, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input> +auto RedisCluster::hsetex(const StringView &key, + Input first, + Input last, + const std::chrono::time_point<std::chrono::system_clock, std::chrono::milliseconds> &tp, + HSetExOption opt) + -> typename std::enable_if<!std::is_convertible<Input, StringView>::value, + long long>::type { + range_check("HSETEX", first, last); + + auto reply = command(cmd::hsetex_time_point_range<Input>, key, first, last, tp, opt); + + return reply::parse<long long>(*reply); +} + +template <typename Input, typename Output> +void RedisCluster::httl(const StringView &key, Input first, Input last, Output output) { + range_check("HTTL", first, last); + + auto reply = command(cmd::httl_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void RedisCluster::hpttl(const StringView &key, Input first, Input last, Output output) { + range_check("HPTTL", first, last); + + auto reply = command(cmd::hpttl_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void RedisCluster::hexpiretime(const StringView &key, Input first, Input last, Output output) { + range_check("HEXPIRETIME", first, last); + + auto reply = command(cmd::hexpiretime_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void RedisCluster::hpexpiretime(const StringView &key, Input first, Input last, Output output) { + range_check("HPEXPIRETIME", first, last); + + auto reply = command(cmd::hpexpiretime_range<Input>, key, first, last); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void RedisCluster::hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + Output output) { + range_check("HPEXPIRE", first, last); + + auto reply = command(cmd::hpexpire_range<Input>, key, first, last, ttl, HPExpireOption::ALWAYS); + + reply::to_array(*reply, output); +} + +template <typename Input, typename Output> +void RedisCluster::hpexpire(const StringView &key, + Input first, + Input last, + const std::chrono::milliseconds &ttl, + HPExpireOption opt, + Output output) { + range_check("HPEXPIRE", first, last); + + auto reply = command(cmd::hpexpire_range<Input>, key, first, last, ttl, opt); + + reply::to_array(*reply, output); +} + template <typename Output> inline void RedisCluster::hvals(const StringView &key, Output output) { auto reply = command(cmd::hvals, key); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/reply.h new/redis-plus-plus-1.3.15/src/sw/redis++/reply.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/reply.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/reply.h 2025-07-22 16:58:50.000000000 +0200 @@ -18,6 +18,7 @@ #define SEWENEW_REDISPLUSPLUS_REPLY_H #include <cassert> +#include <cstdlib> #include <string> #include <iterator> #include <memory> @@ -301,25 +302,305 @@ parse_tuple<Args...>(reply, idx + 1)); } +template <typename T> +bool is_parsable(redisReply &reply); + +bool is_parsable(ParseTag<std::string>, redisReply &reply); + +bool is_parsable(ParseTag<long long>, redisReply &reply); + +bool is_parsable(ParseTag<double>, redisReply &reply); + +bool is_parsable(ParseTag<bool>, redisReply &reply); + +bool is_parsable(ParseTag<void>, redisReply &reply); + +template <typename T> +bool is_parsable(ParseTag<Optional<T>>, redisReply &reply); + +template <typename T, typename U> +bool is_parsable(ParseTag<std::pair<T, U>>, redisReply &reply); + +template <typename ...Args> +bool is_parsable(ParseTag<std::tuple<Args...>>, redisReply &reply); + +template <typename T, typename std::enable_if<IsSequenceContainer<T>::value, int>::type = 0> +bool is_parsable(ParseTag<T>, redisReply &reply); + +template <typename T, typename std::enable_if<IsAssociativeContainer<T>::value, int>::type = 0> +bool is_parsable(ParseTag<T>, redisReply &reply); + #ifdef REDIS_PLUS_PLUS_HAS_VARIANT +bool is_parsable(ParseTag<Monostate>, redisReply &reply); + template <typename T> -Variant<T> parse_variant(redisReply &reply) { - return parse<T>(reply); +bool is_parsable(ParseTag<Variant<T>>, redisReply &reply); + +template <typename T, typename ...Args> +auto is_parsable(ParseTag<Variant<T, Args...>>, redisReply &reply) + -> typename std::enable_if<sizeof...(Args) != 0, bool>::type; + +#endif + +template <typename T> +inline bool is_parsable(redisReply &reply) { + return is_parsable(ParseTag<T>{}, reply); +} + +inline bool is_parsable(ParseTag<std::string>, redisReply &reply) { +#ifdef REDIS_PLUS_PLUS_RESP_VERSION_3 + return is_string(reply) || is_status(reply) + || is_verb(reply) || is_bignum(reply); +#else + return is_string(reply) || is_status(reply); +#endif +} + +inline bool is_parsable(ParseTag<long long>, redisReply &reply) { + return is_integer(reply); +} + +inline bool is_parsable(ParseTag<double>, redisReply &reply) { +#ifdef REDIS_PLUS_PLUS_RESP_VERSION_3 + if (is_double(reply)) { + return true; + } +#endif + + if (!is_string(reply) || reply.str == nullptr) { + return false; + } + + char *end = nullptr; + std::strtod(reply.str, &end); + return end != reply.str; +} + +inline bool is_parsable(ParseTag<bool>, redisReply &reply) { +#ifdef REDIS_PLUS_PLUS_RESP_VERSION_3 + if (!is_bool(reply) && !is_integer(reply)) { + return false; + } +#else + if (!is_integer(reply)) { + return false; + } +#endif + + return reply.integer == 0 || reply.integer == 1; +} + +inline bool is_parsable(ParseTag<void>, redisReply &reply) { + return is_status(reply); +} + +template <typename T> +inline bool is_parsable(ParseTag<Optional<T>>, redisReply &reply) { + if (is_nil(reply)) { + return true; + } + + return is_parsable<T>(reply); +} + +template <typename T, typename U> +inline bool is_parsable(ParseTag<std::pair<T, U>>, redisReply &reply) { + if (!is_array(reply)) { + return false; + } + + if (reply.element == nullptr) { + return false; + } + + if (reply.elements == 1) { + // Nested array reply. Check the first element of the nested array. + auto *nested_element = reply.element[0]; + if (nested_element == nullptr) { + return false; + } + + return is_parsable(ParseTag<std::pair<T, U>>{}, *nested_element); + } + + if (reply.elements != 2) { + return false; + } + + auto *first = reply.element[0]; + auto *second = reply.element[1]; + if (first == nullptr || second == nullptr) { + return false; + } + + return is_parsable(ParseTag<typename std::decay<T>::type>{}, *first) && + is_parsable(ParseTag<typename std::decay<U>::type>{}, *second); +} + +template <typename T> +bool is_tuple_parsable(redisReply **reply, std::size_t idx) { + assert(reply != nullptr); + + auto *sub_reply = reply[idx]; + if (sub_reply == nullptr) { + return false; + } + + return is_parsable<T>(*sub_reply); } template <typename T, typename ...Args> -auto parse_variant(redisReply &reply) -> - typename std::enable_if<sizeof...(Args) != 0, Variant<T, Args...>>::type { +auto is_tuple_parsable(redisReply **reply, std::size_t idx) -> + typename std::enable_if<sizeof...(Args) != 0, bool>::type { + assert(reply != nullptr); + + return is_tuple_parsable<T>(reply, idx) && + is_tuple_parsable<Args...>(reply, idx + 1); +} + +template <typename ...Args> +bool is_parsable(ParseTag<std::tuple<Args...>>, redisReply &reply) { + constexpr auto size = sizeof...(Args); + + static_assert(size > 0, "DO NOT support parsing tuple with 0 element"); + + if (!is_array(reply)) { + return false; + } + + if (reply.elements != size) { + return false; + } + + if (reply.element == nullptr) { + return false; + } + + return is_tuple_parsable<Args...>(reply.element, 0); +} + +template <typename T> +bool is_flat_kv_parsable(redisReply &reply) { + if (reply.element == nullptr || reply.elements == 0) { + // Empty array. + return true; + } + + if (reply.elements % 2 != 0) { + return false; + } + + auto *key_reply = reply.element[0]; + auto *val_reply = reply.element[1]; + if (key_reply == nullptr || val_reply == nullptr) { + return false; + } + + using Pair = typename T::value_type; + using FirstType = typename std::decay<typename Pair::first_type>::type; + using SecondType = typename std::decay<typename Pair::second_type>::type; + return is_parsable<FirstType>(*key_reply) && + is_parsable<SecondType>(*val_reply); +} + +template <typename T> +bool is_container_parsable(std::false_type, redisReply &reply) { + if (reply.element == nullptr || reply.elements == 0) { + // Empty array. + return true; + } + + auto *sub_reply = reply.element[0]; + if (sub_reply == nullptr) { + return false; + } + + return is_parsable<typename T::value_type>(*sub_reply); +} + +template <typename T> +bool is_container_parsable(std::true_type, redisReply &reply) { + if (is_flat_array(reply)) { + return is_flat_kv_parsable<T>(reply); + } else { + return is_container_parsable<T>(std::false_type{}, reply); + } +} + +template <typename T, typename std::enable_if<IsSequenceContainer<T>::value, int>::type> +bool is_parsable(ParseTag<T>, redisReply &reply) { +#ifdef REDIS_PLUS_PLUS_RESP_VERSION_3 + if (!is_array(reply) && !is_set(reply)) { + return false; +#else + if (!is_array(reply)) { + return false; +#endif + } + + return is_container_parsable<T>(typename IsKvPair<typename T::value_type>::type(), reply); +} + +template <typename T, typename std::enable_if<IsAssociativeContainer<T>::value, int>::type> +bool is_parsable(ParseTag<T>, redisReply &reply) { +#ifdef REDIS_PLUS_PLUS_RESP_VERSION_3 + if (!is_array(reply) && !is_map(reply) && !is_set(reply)) { +#else + if (!is_array(reply)) { +#endif + return false; + } + + return is_container_parsable<T>(std::true_type{}, reply); +} + +#ifdef REDIS_PLUS_PLUS_HAS_VARIANT + +template <typename Result, typename T> +Result parse_variant(redisReply &reply) { + if (!is_parsable<T>(reply)) { + throw Error("no variant type matches"); + } + auto return_var = [](auto &&arg) { - return Variant<T, Args...>(std::forward<decltype(arg)>(arg)); + return Result(std::forward<decltype(arg)>(arg)); }; - try { - return std::visit(return_var, parse_variant<T>(reply)); - } catch (const ProtoError &) { - return std::visit(return_var, parse_variant<Args...>(reply)); + return std::visit(return_var, Variant<T>(parse<T>(reply))); +} + +template <typename Result, typename T, typename ...Args> +auto parse_variant(redisReply &reply) -> + typename std::enable_if<sizeof...(Args) != 0, Result>::type { + if (is_parsable<T>(reply)) { + auto return_var = [](auto &&arg) { + return Result(std::forward<decltype(arg)>(arg)); + }; + + return std::visit(return_var, Variant<T>(parse<T>(reply))); } + + return parse_variant<Result, Args...>(reply); +} + +inline bool is_parsable(ParseTag<Monostate>, redisReply &) { + return true; +} + +template <typename T> +bool is_parsable(ParseTag<Variant<T>>, redisReply &reply) { + return is_parsable(ParseTag<T>{}, reply); +} + +template <typename T, typename ...Args> +auto is_parsable(ParseTag<Variant<T, Args...>>, redisReply &reply) -> + typename std::enable_if<sizeof...(Args) != 0, bool>::type { + if (is_parsable(ParseTag<T>{}, reply)) { + return true; + } + + return is_parsable(ParseTag<Variant<Args...>>{}, reply); } #endif @@ -417,7 +698,7 @@ template <typename ...Args> Variant<Args...> parse(ParseTag<Variant<Args...>>, redisReply &reply) { - return detail::parse_variant<Args...>(reply); + return detail::parse_variant<Variant<Args...>, Args...>(reply); } #endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/src/sw/redis++/version.h new/redis-plus-plus-1.3.15/src/sw/redis++/version.h --- old/redis-plus-plus-1.3.14/src/sw/redis++/version.h 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/src/sw/redis++/version.h 2025-07-22 16:58:50.000000000 +0200 @@ -23,7 +23,7 @@ const int VERSION_MAJOR = 1; const int VERSION_MINOR = 3; -const int VERSION_PATCH = 14; +const int VERSION_PATCH = 15; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/redis-plus-plus-1.3.14/test/CMakeLists.txt new/redis-plus-plus-1.3.15/test/CMakeLists.txt --- old/redis-plus-plus-1.3.14/test/CMakeLists.txt 2025-03-30 01:54:24.000000000 +0100 +++ new/redis-plus-plus-1.3.15/test/CMakeLists.txt 2025-07-22 16:58:50.000000000 +0200 @@ -1,23 +1,15 @@ project(test_redis++) -cmake_minimum_required(VERSION 3.1) +cmake_minimum_required(VERSION 3.5) set(REDIS_PLUS_PLUS_TEST_SOURCES src/sw/redis++/test_main.cpp) add_executable(${PROJECT_NAME} ${REDIS_PLUS_PLUS_TEST_SOURCES}) # hiredis dependency -find_path(HIREDIS_HEADER hiredis REQUIRED) -target_include_directories(${PROJECT_NAME} PRIVATE $<BUILD_INTERFACE:${HIREDIS_HEADER}>) +include(${CMAKE_CURRENT_LIST_DIR}/../cmake/FindHiredis.cmake) -find_library(TEST_HIREDIS_LIB NAMES libhiredis.a libhiredisd.a) -if(NOT TEST_HIREDIS_LIB) - find_library(TEST_HIREDIS_LIB NAMES libhiredis_static.a libhiredis_staticd.a) - if(NOT TEST_HIREDIS_LIB) - find_library(TEST_HIREDIS_LIB NAMES hiredis hiredisd) - endif() -endif() -target_link_libraries(${PROJECT_NAME} ${TEST_HIREDIS_LIB}) +target_link_libraries(${PROJECT_NAME} ${REDIS_PLUS_PLUS_HIREDIS_LIBS}) if(REDIS_PLUS_PLUS_USE_TLS) find_package(OpenSSL REQUIRED)
