.mypy_cache/ | .mypy_cache/ | ||||
*.dsd/ | *.dsd/ | ||||
_prebuilt/ | _prebuilt/ | ||||
.dds-repo-lock | |||||
.dds-repo-lock | |||||
.pytest_cache |
Type: Index | Type: Index | ||||
Package: taywee-args; external/taywee-args.lmp | |||||
Package: spdlog; external/spdlog.lmp | Package: spdlog; external/spdlog.lmp | ||||
Package: ms-third; external/ms-third.lmp | Package: ms-third; external/ms-third.lmp | ||||
Package: ranges-v3; external/ranges-v3.lmp | Package: ranges-v3; external/ranges-v3.lmp |
steps: | steps: | ||||
- script: | | - script: | | ||||
echo Loading VS environment | echo Loading VS environment | ||||
call "C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Enterprise\\Common7\\Tools\\vsdevcmd" -arch=x64 || exit 1 | |||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\Common7\Tools\vsdevcmd" -arch=x64 || exit 1 | |||||
echo Executing Build and Tests | echo Executing Build and Tests | ||||
python -u tools/ci.py -B download --cxx cl.exe -T tools\\msvc.dds || exit 1 | |||||
reg add HKLM\SYSTEM\CurrentControlSet\Control\FileSystem /v LongPathsEnabled /t REG_DWORD /d 1 /f || exit 1 | |||||
python -m pip install pytest pytest-xdist || exit 1 | |||||
python -u tools/ci.py -B download --cxx cl.exe -T tools\msvc.dds -T2 tools\msvc.p2.dds || exit 1 | |||||
displayName: Full CI | displayName: Full CI | ||||
- publish: _build/dds.exe | - publish: _build/dds.exe | ||||
artifact: DDS Executable - Windows VS2019 | artifact: DDS Executable - Windows VS2019 | ||||
pool: | pool: | ||||
vmImage: ubuntu-18.04 | vmImage: ubuntu-18.04 | ||||
steps: | steps: | ||||
- script: sudo apt update -y && sudo apt install -y python3-minimal g++-8 | |||||
- script: | | |||||
set -eu | |||||
sudo apt update -y | |||||
sudo apt install -y python3-minimal g++-8 | |||||
python3 -m pip install pytest pytest-xdist | |||||
displayName: Prepare System | displayName: Prepare System | ||||
- script: python3 -u tools/ci.py -B download --cxx g++-8 -T tools/gcc-8.dds | |||||
- script: python3 -u tools/ci.py -B download --cxx g++-8 -T tools/gcc-8.dds -T2 tools/gcc-8.p2.dds | |||||
displayName: Full CI | displayName: Full CI | ||||
- publish: _build/dds | - publish: _build/dds | ||||
artifact: DDS Executable - Linux | artifact: DDS Executable - Linux | ||||
steps: | steps: | ||||
- script: brew install gcc@8 | - script: brew install gcc@8 | ||||
displayName: Prepare System | displayName: Prepare System | ||||
- script: python3 -u tools/ci.py -B download --cxx g++-8 -T tools/gcc-8.dds | |||||
- script: | | |||||
set -eu | |||||
python3 -m pip install pytest pytest-xdist | |||||
python3 -u tools/ci.py -B download --cxx g++-8 -T tools/gcc-8.dds -T2 tools/gcc-8.p2.dds | |||||
displayName: Build and Run Unit Tests | displayName: Build and Run Unit Tests | ||||
- publish: _build/dds | - publish: _build/dds | ||||
artifact: DDS Executable - macOS | artifact: DDS Executable - macOS |
Type: Library | |||||
Name: args | |||||
Include-Path: repo/taywee-args/include |
/* | /* | ||||
__ _____ _____ _____ | __ _____ _____ _____ | ||||
__| | __| | | | JSON for Modern C++ | __| | __| | | | JSON for Modern C++ | ||||
| | |__ | | | | | | version 3.7.0 | |||||
| | |__ | | | | | | version 3.7.1 | |||||
|_____|_____|_____|_|___| https://github.com/nlohmann/json | |_____|_____|_____|_|___| https://github.com/nlohmann/json | ||||
Licensed under the MIT License <http://opensource.org/licenses/MIT>. | Licensed under the MIT License <http://opensource.org/licenses/MIT>. | ||||
#define NLOHMANN_JSON_VERSION_MAJOR 3 | #define NLOHMANN_JSON_VERSION_MAJOR 3 | ||||
#define NLOHMANN_JSON_VERSION_MINOR 7 | #define NLOHMANN_JSON_VERSION_MINOR 7 | ||||
#define NLOHMANN_JSON_VERSION_PATCH 0 | |||||
#define NLOHMANN_JSON_VERSION_PATCH 1 | |||||
#include <algorithm> // all_of, find, for_each | #include <algorithm> // all_of, find, for_each | ||||
#include <cassert> // assert | #include <cassert> // assert | ||||
* SPDX-License-Identifier: CC0-1.0 | * SPDX-License-Identifier: CC0-1.0 | ||||
*/ | */ | ||||
#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 9) | |||||
#if !defined(JSON_HEDLEY_VERSION) || (JSON_HEDLEY_VERSION < 11) | |||||
#if defined(JSON_HEDLEY_VERSION) | #if defined(JSON_HEDLEY_VERSION) | ||||
#undef JSON_HEDLEY_VERSION | #undef JSON_HEDLEY_VERSION | ||||
#endif | #endif | ||||
#define JSON_HEDLEY_VERSION 9 | |||||
#define JSON_HEDLEY_VERSION 11 | |||||
#if defined(JSON_HEDLEY_STRINGIFY_EX) | #if defined(JSON_HEDLEY_STRINGIFY_EX) | ||||
#undef JSON_HEDLEY_STRINGIFY_EX | #undef JSON_HEDLEY_STRINGIFY_EX | ||||
#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) | #if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE) | ||||
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | ||||
#endif | #endif | ||||
#if defined(__has_cpp_attribute) && defined(__cplusplus) | |||||
#if \ | |||||
defined(__has_cpp_attribute) && \ | |||||
defined(__cplusplus) && \ | |||||
(!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) | |||||
#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) __has_cpp_attribute(attribute) | ||||
#else | #else | ||||
#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) | #define JSON_HEDLEY_HAS_CPP_ATTRIBUTE(attribute) (0) | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS) | |||||
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS | |||||
#endif | |||||
#if !defined(__cplusplus) || !defined(__has_cpp_attribute) | |||||
#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) | |||||
#elif \ | |||||
!defined(JSON_HEDLEY_PGI_VERSION) && \ | |||||
(!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ | |||||
(!defined(JSON_HEDLEY_MSVC_VERSION) || JSON_HEDLEY_MSVC_VERSION_CHECK(19,20,0)) | |||||
#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) JSON_HEDLEY_HAS_CPP_ATTRIBUTE(ns::attribute) | |||||
#else | |||||
#define JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(ns,attribute) (0) | |||||
#endif | |||||
#if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) | #if defined(JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE) | ||||
#undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE | #undef JSON_HEDLEY_GNUC_HAS_CPP_ATTRIBUTE | ||||
#endif | #endif | ||||
#define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | #define JSON_HEDLEY_GCC_HAS_WARNING(warning,major,minor,patch) JSON_HEDLEY_GCC_VERSION_CHECK(major,minor,patch) | ||||
#endif | #endif | ||||
/* JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ is for | |||||
HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ | |||||
#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_) | |||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ | |||||
#endif | |||||
#if defined(__cplusplus) && JSON_HEDLEY_HAS_WARNING("-Wc++98-compat") | |||||
# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(xpr) \ | |||||
JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |||||
_Pragma("clang diagnostic ignored \"-Wc++98-compat\"") \ | |||||
xpr \ | |||||
JSON_HEDLEY_DIAGNOSTIC_POP | |||||
#else | |||||
# define JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(x) x | |||||
#endif | |||||
#if \ | #if \ | ||||
(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ | (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ | ||||
defined(__clang__) || \ | defined(__clang__) || \ | ||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | #define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES) | |||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |||||
#endif | |||||
#if JSON_HEDLEY_HAS_WARNING("-Wunknown-attributes") | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("clang diagnostic ignored \"-Wunknown-attributes\"") | |||||
#elif JSON_HEDLEY_GCC_VERSION_CHECK(4,6,0) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") | |||||
#elif JSON_HEDLEY_INTEL_VERSION_CHECK(17,0,0) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("warning(disable:1292)") | |||||
#elif JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,0) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES __pragma(warning(disable:5030)) | |||||
#elif JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1097") | |||||
#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,14,0) && defined(__cplusplus) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("error_messages(off,attrskipunsup)") | |||||
#elif JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES _Pragma("diag_suppress 1173") | |||||
#else | |||||
#define JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |||||
#endif | |||||
#if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) | #if defined(JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL) | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | ||||
#endif | #endif | ||||
#undef JSON_HEDLEY_DEPRECATED_FOR | #undef JSON_HEDLEY_DEPRECATED_FOR | ||||
#endif | #endif | ||||
#if defined(__cplusplus) && (__cplusplus >= 201402L) | #if defined(__cplusplus) && (__cplusplus >= 201402L) | ||||
#define JSON_HEDLEY_DEPRECATED(since) [[deprecated("Since " #since)]] | |||||
#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) [[deprecated("Since " #since "; use " #replacement)]] | |||||
#define JSON_HEDLEY_DEPRECATED(since) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since)]]) | |||||
#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[deprecated("Since " #since "; use " #replacement)]]) | |||||
#elif \ | #elif \ | ||||
JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ | JSON_HEDLEY_HAS_EXTENSION(attribute_deprecated_with_message) || \ | ||||
JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ | JSON_HEDLEY_GCC_VERSION_CHECK(4,5,0) || \ | ||||
#elif \ | #elif \ | ||||
JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) || \ | ||||
JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) | JSON_HEDLEY_PELLES_VERSION_CHECK(6,50,0) | ||||
#define JSON_HEDLEY_DEPRECATED(since) _declspec(deprecated) | |||||
#define JSON_HEDLEY_DEPRECATED(since) __declspec(deprecated) | |||||
#define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) | #define JSON_HEDLEY_DEPRECATED_FOR(since, replacement) __declspec(deprecated) | ||||
#elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | #elif JSON_HEDLEY_IAR_VERSION_CHECK(8,0,0) | ||||
#define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") | #define JSON_HEDLEY_DEPRECATED(since) _Pragma("deprecated") | ||||
#undef JSON_HEDLEY_WARN_UNUSED_RESULT | #undef JSON_HEDLEY_WARN_UNUSED_RESULT | ||||
#endif | #endif | ||||
#if defined(__cplusplus) && (__cplusplus >= 201703L) | #if defined(__cplusplus) && (__cplusplus >= 201703L) | ||||
#define JSON_HEDLEY_WARN_UNUSED_RESULT [[nodiscard]] | |||||
#define JSON_HEDLEY_WARN_UNUSED_RESULT JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[nodiscard]]) | |||||
#elif \ | #elif \ | ||||
JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ | JSON_HEDLEY_HAS_ATTRIBUTE(warn_unused_result) || \ | ||||
JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | ||||
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L | #elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L | ||||
#define JSON_HEDLEY_NO_RETURN _Noreturn | #define JSON_HEDLEY_NO_RETURN _Noreturn | ||||
#elif defined(__cplusplus) && (__cplusplus >= 201103L) | #elif defined(__cplusplus) && (__cplusplus >= 201103L) | ||||
#define JSON_HEDLEY_NO_RETURN [[noreturn]] | |||||
#define JSON_HEDLEY_NO_RETURN JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[noreturn]]) | |||||
#elif \ | #elif \ | ||||
JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ | JSON_HEDLEY_HAS_ATTRIBUTE(noreturn) || \ | ||||
JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ | JSON_HEDLEY_GCC_VERSION_CHECK(3,2,0) || \ | ||||
JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ | JSON_HEDLEY_TI_VERSION_CHECK(18,0,0) || \ | ||||
(JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) | (JSON_HEDLEY_TI_VERSION_CHECK(17,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) | ||||
#define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) | #define JSON_HEDLEY_NO_RETURN __attribute__((__noreturn__)) | ||||
#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |||||
#define JSON_HEDLEY_NO_RETURN _Pragma("does_not_return") | |||||
#elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) | #elif JSON_HEDLEY_MSVC_VERSION_CHECK(13,10,0) | ||||
#define JSON_HEDLEY_NO_RETURN __declspec(noreturn) | #define JSON_HEDLEY_NO_RETURN __declspec(noreturn) | ||||
#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) | #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) | ||||
#define JSON_HEDLEY_NO_RETURN | #define JSON_HEDLEY_NO_RETURN | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_NO_ESCAPE) | |||||
#undef JSON_HEDLEY_NO_ESCAPE | |||||
#endif | |||||
#if JSON_HEDLEY_HAS_ATTRIBUTE(noescape) | |||||
#define JSON_HEDLEY_NO_ESCAPE __attribute__((__noescape__)) | |||||
#else | |||||
#define JSON_HEDLEY_NO_ESCAPE | |||||
#endif | |||||
#if defined(JSON_HEDLEY_UNREACHABLE) | #if defined(JSON_HEDLEY_UNREACHABLE) | ||||
#undef JSON_HEDLEY_UNREACHABLE | #undef JSON_HEDLEY_UNREACHABLE | ||||
#endif | #endif | ||||
#define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) | #define JSON_HEDLEY_ASSUME(expr) ((void) (expr)) | ||||
#endif | #endif | ||||
JSON_HEDLEY_DIAGNOSTIC_PUSH | JSON_HEDLEY_DIAGNOSTIC_PUSH | ||||
#if \ | |||||
JSON_HEDLEY_HAS_WARNING("-Wvariadic-macros") || \ | |||||
JSON_HEDLEY_GCC_VERSION_CHECK(4,0,0) | |||||
#if JSON_HEDLEY_HAS_WARNING("-Wpedantic") | |||||
#pragma clang diagnostic ignored "-Wpedantic" | |||||
#endif | |||||
#if JSON_HEDLEY_HAS_WARNING("-Wc++98-compat-pedantic") && defined(__cplusplus) | |||||
#pragma clang diagnostic ignored "-Wc++98-compat-pedantic" | |||||
#endif | |||||
#if JSON_HEDLEY_GCC_HAS_WARNING("-Wvariadic-macros",4,0,0) | |||||
#if defined(__clang__) | #if defined(__clang__) | ||||
#pragma clang diagnostic ignored "-Wvariadic-macros" | #pragma clang diagnostic ignored "-Wvariadic-macros" | ||||
#elif defined(JSON_HEDLEY_GCC_VERSION) | #elif defined(JSON_HEDLEY_GCC_VERSION) | ||||
#endif | #endif | ||||
#if defined(__cplusplus) | #if defined(__cplusplus) | ||||
#if __cplusplus >= 201103L | #if __cplusplus >= 201103L | ||||
#define JSON_HEDLEY_CONSTEXPR constexpr | |||||
#define JSON_HEDLEY_CONSTEXPR JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(constexpr) | |||||
#endif | #endif | ||||
#endif | #endif | ||||
#if !defined(JSON_HEDLEY_CONSTEXPR) | #if !defined(JSON_HEDLEY_CONSTEXPR) | ||||
JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ | JSON_HEDLEY_TI_VERSION_CHECK(8,0,0) || \ | ||||
(JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) | (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) | ||||
#define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) | #define JSON_HEDLEY_MALLOC __attribute__((__malloc__)) | ||||
#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |||||
#define JSON_HEDLEY_MALLOC _Pragma("returns_new_memory") | |||||
#elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) | #elif JSON_HEDLEY_MSVC_VERSION_CHECK(14, 0, 0) | ||||
#define JSON_HEDLEY_MALLOC __declspec(restrict) | #define JSON_HEDLEY_MALLOC __declspec(restrict) | ||||
#else | #else | ||||
(JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | ||||
JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | ||||
#define JSON_HEDLEY_PURE __attribute__((__pure__)) | #define JSON_HEDLEY_PURE __attribute__((__pure__)) | ||||
#elif JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |||||
#define JSON_HEDLEY_PURE _Pragma("does_not_write_global_data") | |||||
#elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) | #elif JSON_HEDLEY_TI_VERSION_CHECK(6,0,0) && defined(__cplusplus) | ||||
#define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") | #define JSON_HEDLEY_PURE _Pragma("FUNC_IS_PURE;") | ||||
#else | #else | ||||
(JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | (JSON_HEDLEY_TI_VERSION_CHECK(7,3,0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) || \ | ||||
JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | JSON_HEDLEY_PGI_VERSION_CHECK(17,10,0) | ||||
#define JSON_HEDLEY_CONST __attribute__((__const__)) | #define JSON_HEDLEY_CONST __attribute__((__const__)) | ||||
#elif \ | |||||
JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) | |||||
#define JSON_HEDLEY_CONST _Pragma("no_side_effect") | |||||
#else | #else | ||||
#define JSON_HEDLEY_CONST JSON_HEDLEY_PURE | #define JSON_HEDLEY_CONST JSON_HEDLEY_PURE | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_FALL_THROUGH) | #if defined(JSON_HEDLEY_FALL_THROUGH) | ||||
#undef JSON_HEDLEY_FALL_THROUGH | #undef JSON_HEDLEY_FALL_THROUGH | ||||
#endif | #endif | ||||
#if \ | |||||
defined(__cplusplus) && \ | |||||
(!defined(JSON_HEDLEY_SUNPRO_VERSION) || JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,15,0)) && \ | |||||
!defined(JSON_HEDLEY_PGI_VERSION) | |||||
#if \ | |||||
(__cplusplus >= 201703L) || \ | |||||
((__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough)) | |||||
#define JSON_HEDLEY_FALL_THROUGH [[fallthrough]] | |||||
#elif (__cplusplus >= 201103L) && JSON_HEDLEY_HAS_CPP_ATTRIBUTE(clang::fallthrough) | |||||
#define JSON_HEDLEY_FALL_THROUGH [[clang::fallthrough]] | |||||
#elif (__cplusplus >= 201103L) && JSON_HEDLEY_GCC_VERSION_CHECK(7,0,0) | |||||
#define JSON_HEDLEY_FALL_THROUGH [[gnu::fallthrough]] | |||||
#endif | |||||
#endif | |||||
#if !defined(JSON_HEDLEY_FALL_THROUGH) | |||||
#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) | |||||
#define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) | |||||
#elif defined(__fallthrough) /* SAL */ | |||||
#define JSON_HEDLEY_FALL_THROUGH __fallthrough | |||||
#else | |||||
#define JSON_HEDLEY_FALL_THROUGH | |||||
#endif | |||||
#if JSON_HEDLEY_GNUC_HAS_ATTRIBUTE(fallthrough,7,0,0) && !defined(JSON_HEDLEY_PGI_VERSION) | |||||
#define JSON_HEDLEY_FALL_THROUGH __attribute__((__fallthrough__)) | |||||
#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS(clang,fallthrough) | |||||
#define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[clang::fallthrough]]) | |||||
#elif JSON_HEDLEY_HAS_CPP_ATTRIBUTE(fallthrough) | |||||
#define JSON_HEDLEY_FALL_THROUGH JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_([[fallthrough]]) | |||||
#elif defined(__fallthrough) /* SAL */ | |||||
#define JSON_HEDLEY_FALL_THROUGH __fallthrough | |||||
#else | |||||
#define JSON_HEDLEY_FALL_THROUGH | |||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_RETURNS_NON_NULL) | #if defined(JSON_HEDLEY_RETURNS_NON_NULL) | ||||
#if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) | #if defined(JSON_HEDLEY_REQUIRE_CONSTEXPR) | ||||
#undef JSON_HEDLEY_REQUIRE_CONSTEXPR | #undef JSON_HEDLEY_REQUIRE_CONSTEXPR | ||||
#endif | #endif | ||||
/* Note the double-underscore. For internal use only; no API | |||||
* guarantees! */ | |||||
#if defined(JSON_HEDLEY__IS_CONSTEXPR) | |||||
#undef JSON_HEDLEY__IS_CONSTEXPR | |||||
/* JSON_HEDLEY_IS_CONSTEXPR_ is for | |||||
HEDLEY INTERNAL USE ONLY. API subject to change without notice. */ | |||||
#if defined(JSON_HEDLEY_IS_CONSTEXPR_) | |||||
#undef JSON_HEDLEY_IS_CONSTEXPR_ | |||||
#endif | #endif | ||||
#if \ | #if \ | ||||
JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ | JSON_HEDLEY_HAS_BUILTIN(__builtin_constant_p) || \ | ||||
JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | JSON_HEDLEY_GCC_VERSION_CHECK(3,4,0) || \ | ||||
JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | JSON_HEDLEY_ARM_VERSION_CHECK(4,1,0) || \ | ||||
JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ | JSON_HEDLEY_IBM_VERSION_CHECK(13,1,0) || \ | ||||
JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ | JSON_HEDLEY_TI_VERSION_CHECK(6,1,0) || \ | ||||
JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) || \ | |||||
(JSON_HEDLEY_SUNPRO_VERSION_CHECK(5,10,0) && !defined(__cplusplus)) || \ | |||||
JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) | JSON_HEDLEY_CRAY_VERSION_CHECK(8,1,0) | ||||
#define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) | #define JSON_HEDLEY_IS_CONSTANT(expr) __builtin_constant_p(expr) | ||||
#endif | #endif | ||||
JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ | JSON_HEDLEY_ARM_VERSION_CHECK(5,4,0) || \ | ||||
JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) | JSON_HEDLEY_TINYC_VERSION_CHECK(0,9,24) | ||||
#if defined(__INTPTR_TYPE__) | #if defined(__INTPTR_TYPE__) | ||||
#define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) | |||||
#define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0)), int*) | |||||
#else | #else | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#define JSON_HEDLEY__IS_CONSTEXPR(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) | |||||
#define JSON_HEDLEY_IS_CONSTEXPR_(expr) __builtin_types_compatible_p(__typeof__((1 ? (void*) ((intptr_t) ((expr) * 0)) : (int*) 0)), int*) | |||||
#endif | #endif | ||||
# elif \ | # elif \ | ||||
(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ | (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L) && !defined(JSON_HEDLEY_SUNPRO_VERSION) && !defined(JSON_HEDLEY_PGI_VERSION)) || \ | ||||
JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ | JSON_HEDLEY_IBM_VERSION_CHECK(12,1,0) || \ | ||||
JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) | JSON_HEDLEY_ARM_VERSION_CHECK(5,3,0) | ||||
#if defined(__INTPTR_TYPE__) | #if defined(__INTPTR_TYPE__) | ||||
#define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) | |||||
#define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((__INTPTR_TYPE__) ((expr) * 0)) : (int*) 0), int*: 1, void*: 0) | |||||
#else | #else | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#define JSON_HEDLEY__IS_CONSTEXPR(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) | |||||
#define JSON_HEDLEY_IS_CONSTEXPR_(expr) _Generic((1 ? (void*) ((intptr_t) * 0) : (int*) 0), int*: 1, void*: 0) | |||||
#endif | #endif | ||||
# elif \ | # elif \ | ||||
defined(JSON_HEDLEY_GCC_VERSION) || \ | defined(JSON_HEDLEY_GCC_VERSION) || \ | ||||
defined(JSON_HEDLEY_TINYC_VERSION) || \ | defined(JSON_HEDLEY_TINYC_VERSION) || \ | ||||
defined(JSON_HEDLEY_TI_VERSION) || \ | defined(JSON_HEDLEY_TI_VERSION) || \ | ||||
defined(__clang__) | defined(__clang__) | ||||
# define JSON_HEDLEY__IS_CONSTEXPR(expr) ( \ | |||||
# define JSON_HEDLEY_IS_CONSTEXPR_(expr) ( \ | |||||
sizeof(void) != \ | sizeof(void) != \ | ||||
sizeof(*( \ | sizeof(*( \ | ||||
1 ? \ | 1 ? \ | ||||
) | ) | ||||
# endif | # endif | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY__IS_CONSTEXPR) | |||||
#if defined(JSON_HEDLEY_IS_CONSTEXPR_) | |||||
#if !defined(JSON_HEDLEY_IS_CONSTANT) | #if !defined(JSON_HEDLEY_IS_CONSTANT) | ||||
#define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY__IS_CONSTEXPR(expr) | |||||
#define JSON_HEDLEY_IS_CONSTANT(expr) JSON_HEDLEY_IS_CONSTEXPR_(expr) | |||||
#endif | #endif | ||||
#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY__IS_CONSTEXPR(expr) ? (expr) : (-1)) | |||||
#define JSON_HEDLEY_REQUIRE_CONSTEXPR(expr) (JSON_HEDLEY_IS_CONSTEXPR_(expr) ? (expr) : (-1)) | |||||
#else | #else | ||||
#if !defined(JSON_HEDLEY_IS_CONSTANT) | #if !defined(JSON_HEDLEY_IS_CONSTANT) | ||||
#define JSON_HEDLEY_IS_CONSTANT(expr) (0) | #define JSON_HEDLEY_IS_CONSTANT(expr) (0) | ||||
) | ) | ||||
# define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) | # define JSON_HEDLEY_STATIC_ASSERT(expr, message) _Static_assert(expr, message) | ||||
#elif \ | #elif \ | ||||
(defined(__cplusplus) && (__cplusplus >= 201703L)) || \ | |||||
(defined(__cplusplus) && (__cplusplus >= 201103L)) || \ | |||||
JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ | JSON_HEDLEY_MSVC_VERSION_CHECK(16,0,0) || \ | ||||
(defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) | (defined(__cplusplus) && JSON_HEDLEY_TI_VERSION_CHECK(8,3,0)) | ||||
# define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr, message) | |||||
#elif defined(__cplusplus) && (__cplusplus >= 201103L) | |||||
# define JSON_HEDLEY_STATIC_ASSERT(expr, message) static_assert(expr) | |||||
# define JSON_HEDLEY_STATIC_ASSERT(expr, message) JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(static_assert(expr, message)) | |||||
#else | #else | ||||
# define JSON_HEDLEY_STATIC_ASSERT(expr, message) | # define JSON_HEDLEY_STATIC_ASSERT(expr, message) | ||||
#endif | #endif | ||||
#define JSON_HEDLEY_CPP_CAST(T, expr) (expr) | #define JSON_HEDLEY_CPP_CAST(T, expr) (expr) | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_NULL) | |||||
#undef JSON_HEDLEY_NULL | |||||
#endif | |||||
#if defined(__cplusplus) | |||||
#if __cplusplus >= 201103L | |||||
#define JSON_HEDLEY_NULL JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_(nullptr) | |||||
#elif defined(NULL) | |||||
#define JSON_HEDLEY_NULL NULL | |||||
#else | |||||
#define JSON_HEDLEY_NULL JSON_HEDLEY_STATIC_CAST(void*, 0) | |||||
#endif | |||||
#elif defined(NULL) | |||||
#define JSON_HEDLEY_NULL NULL | |||||
#else | |||||
#define JSON_HEDLEY_NULL ((void*) 0) | |||||
#endif | |||||
#if defined(JSON_HEDLEY_MESSAGE) | #if defined(JSON_HEDLEY_MESSAGE) | ||||
#undef JSON_HEDLEY_MESSAGE | #undef JSON_HEDLEY_MESSAGE | ||||
#endif | #endif | ||||
# define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) | # define JSON_HEDLEY_WARNING(msg) JSON_HEDLEY_MESSAGE(msg) | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_REQUIRE) | |||||
#undef JSON_HEDLEY_REQUIRE | |||||
#endif | |||||
#if defined(JSON_HEDLEY_REQUIRE_MSG) | #if defined(JSON_HEDLEY_REQUIRE_MSG) | ||||
#undef JSON_HEDLEY_REQUIRE_MSG | #undef JSON_HEDLEY_REQUIRE_MSG | ||||
#endif | #endif | ||||
#if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) | #if JSON_HEDLEY_HAS_ATTRIBUTE(diagnose_if) | ||||
# if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") | # if JSON_HEDLEY_HAS_WARNING("-Wgcc-compat") | ||||
# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) \ | |||||
# define JSON_HEDLEY_REQUIRE(expr) \ | |||||
JSON_HEDLEY_DIAGNOSTIC_PUSH \ | |||||
_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ | |||||
__attribute__((diagnose_if(!(expr), #expr, "error"))) \ | |||||
JSON_HEDLEY_DIAGNOSTIC_POP | |||||
# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) \ | |||||
JSON_HEDLEY_DIAGNOSTIC_PUSH \ | JSON_HEDLEY_DIAGNOSTIC_PUSH \ | ||||
_Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ | _Pragma("clang diagnostic ignored \"-Wgcc-compat\"") \ | ||||
__attribute__((__diagnose_if__(!(expr), msg, "error"))) \ | |||||
__attribute__((diagnose_if(!(expr), msg, "error"))) \ | |||||
JSON_HEDLEY_DIAGNOSTIC_POP | JSON_HEDLEY_DIAGNOSTIC_POP | ||||
# else | # else | ||||
# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) __attribute__((__diagnose_if__(!(expr), msg, "error"))) | |||||
# define JSON_HEDLEY_REQUIRE(expr) __attribute__((diagnose_if(!(expr), #expr, "error"))) | |||||
# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) __attribute__((diagnose_if(!(expr), msg, "error"))) | |||||
# endif | # endif | ||||
#else | #else | ||||
# define JSON_HEDLEY_REQUIRE_MSG(expr, msg) | |||||
# define JSON_HEDLEY_REQUIRE(expr) | |||||
# define JSON_HEDLEY_REQUIRE_MSG(expr,msg) | |||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_REQUIRE) | |||||
#undef JSON_HEDLEY_REQUIRE | |||||
#endif | |||||
#define JSON_HEDLEY_REQUIRE(expr) JSON_HEDLEY_REQUIRE_MSG(expr, #expr) | |||||
#if defined(JSON_HEDLEY_FLAGS) | #if defined(JSON_HEDLEY_FLAGS) | ||||
#undef JSON_HEDLEY_FLAGS | #undef JSON_HEDLEY_FLAGS | ||||
#endif | #endif | ||||
# define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) | # define JSON_HEDLEY_FLAGS_CAST(T, expr) JSON_HEDLEY_STATIC_CAST(T, expr) | ||||
#endif | #endif | ||||
#if defined(JSON_HEDLEY_EMPTY_BASES) | |||||
#undef JSON_HEDLEY_EMPTY_BASES | |||||
#endif | |||||
#if JSON_HEDLEY_MSVC_VERSION_CHECK(19,0,23918) && !JSON_HEDLEY_MSVC_VERSION_CHECK(20,0,0) | |||||
#define JSON_HEDLEY_EMPTY_BASES __declspec(empty_bases) | |||||
#else | |||||
#define JSON_HEDLEY_EMPTY_BASES | |||||
#endif | |||||
/* Remaining macros are deprecated. */ | /* Remaining macros are deprecated. */ | ||||
#if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) | #if defined(JSON_HEDLEY_GCC_NOT_CLANG_VERSION_CHECK) | ||||
@def NLOHMANN_JSON_SERIALIZE_ENUM | @def NLOHMANN_JSON_SERIALIZE_ENUM | ||||
@since version 3.4.0 | @since version 3.4.0 | ||||
*/ | */ | ||||
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ | |||||
template<typename BasicJsonType> \ | |||||
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ | |||||
{ \ | |||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |||||
auto it = std::find_if(std::begin(m), std::end(m), \ | |||||
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |||||
{ \ | |||||
return ej_pair.first == e; \ | |||||
}); \ | |||||
j = ((it != std::end(m)) ? it : std::begin(m))->second; \ | |||||
} \ | |||||
template<typename BasicJsonType> \ | |||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ | |||||
{ \ | |||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |||||
auto it = std::find_if(std::begin(m), std::end(m), \ | |||||
[j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |||||
{ \ | |||||
return ej_pair.second == j; \ | |||||
}); \ | |||||
e = ((it != std::end(m)) ? it : std::begin(m))->first; \ | |||||
#define NLOHMANN_JSON_SERIALIZE_ENUM(ENUM_TYPE, ...) \ | |||||
template<typename BasicJsonType> \ | |||||
inline void to_json(BasicJsonType& j, const ENUM_TYPE& e) \ | |||||
{ \ | |||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |||||
auto it = std::find_if(std::begin(m), std::end(m), \ | |||||
[e](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |||||
{ \ | |||||
return ej_pair.first == e; \ | |||||
}); \ | |||||
j = ((it != std::end(m)) ? it : std::begin(m))->second; \ | |||||
} \ | |||||
template<typename BasicJsonType> \ | |||||
inline void from_json(const BasicJsonType& j, ENUM_TYPE& e) \ | |||||
{ \ | |||||
static_assert(std::is_enum<ENUM_TYPE>::value, #ENUM_TYPE " must be an enum!"); \ | |||||
static const std::pair<ENUM_TYPE, BasicJsonType> m[] = __VA_ARGS__; \ | |||||
auto it = std::find_if(std::begin(m), std::end(m), \ | |||||
[&j](const std::pair<ENUM_TYPE, BasicJsonType>& ej_pair) -> bool \ | |||||
{ \ | |||||
return ej_pair.second == j; \ | |||||
}); \ | |||||
e = ((it != std::end(m)) ? it : std::begin(m))->first; \ | |||||
} | } | ||||
// Ugly macros to avoid uglier copy-paste when specializing basic_json. They | // Ugly macros to avoid uglier copy-paste when specializing basic_json. They | ||||
template <typename BasicJsonType, typename CompatibleType> | template <typename BasicJsonType, typename CompatibleType> | ||||
struct is_compatible_type | struct is_compatible_type | ||||
: is_compatible_type_impl<BasicJsonType, CompatibleType> {}; | : is_compatible_type_impl<BasicJsonType, CompatibleType> {}; | ||||
// https://en.cppreference.com/w/cpp/types/conjunction | |||||
template<class...> struct conjunction : std::true_type { }; | |||||
template<class B1> struct conjunction<B1> : B1 { }; | |||||
template<class B1, class... Bn> | |||||
struct conjunction<B1, Bn...> | |||||
: std::conditional<bool(B1::value), conjunction<Bn...>, B1>::type {}; | |||||
template <typename T1, typename T2> | |||||
struct is_constructible_tuple : std::false_type {}; | |||||
template <typename T1, typename... Args> | |||||
struct is_constructible_tuple<T1, std::tuple<Args...>> : conjunction<std::is_constructible<T1, Args>...> {}; | |||||
} // namespace detail | } // namespace detail | ||||
} // namespace nlohmann | } // namespace nlohmann | ||||
JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); | JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); | ||||
} | } | ||||
l.resize(j.size()); | l.resize(j.size()); | ||||
std::copy(j.m_value.array->begin(), j.m_value.array->end(), std::begin(l)); | |||||
std::copy(j.begin(), j.end(), std::begin(l)); | |||||
} | } | ||||
template <typename BasicJsonType, typename T, std::size_t N> | template <typename BasicJsonType, typename T, std::size_t N> | ||||
{ | { | ||||
namespace detail | namespace detail | ||||
{ | { | ||||
template<typename string_type> | |||||
void int_to_string( string_type& target, std::size_t value ) | |||||
{ | |||||
target = std::to_string(value); | |||||
} | |||||
template <typename IteratorType> class iteration_proxy_value | template <typename IteratorType> class iteration_proxy_value | ||||
{ | { | ||||
public: | public: | ||||
using pointer = value_type * ; | using pointer = value_type * ; | ||||
using reference = value_type & ; | using reference = value_type & ; | ||||
using iterator_category = std::input_iterator_tag; | using iterator_category = std::input_iterator_tag; | ||||
using string_type = typename std::remove_cv< typename std::remove_reference<decltype( std::declval<IteratorType>().key() ) >::type >::type; | |||||
private: | private: | ||||
/// the iterator | /// the iterator | ||||
/// last stringified array index | /// last stringified array index | ||||
mutable std::size_t array_index_last = 0; | mutable std::size_t array_index_last = 0; | ||||
/// a string representation of the array index | /// a string representation of the array index | ||||
mutable std::string array_index_str = "0"; | |||||
mutable string_type array_index_str = "0"; | |||||
/// an empty string (to return a reference for primitive values) | /// an empty string (to return a reference for primitive values) | ||||
const std::string empty_str = ""; | |||||
const string_type empty_str = ""; | |||||
public: | public: | ||||
explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} | explicit iteration_proxy_value(IteratorType it) noexcept : anchor(it) {} | ||||
} | } | ||||
/// return key of the iterator | /// return key of the iterator | ||||
const std::string& key() const | |||||
const string_type& key() const | |||||
{ | { | ||||
assert(anchor.m_object != nullptr); | assert(anchor.m_object != nullptr); | ||||
{ | { | ||||
if (array_index != array_index_last) | if (array_index != array_index_last) | ||||
{ | { | ||||
array_index_str = std::to_string(array_index); | |||||
int_to_string( array_index_str, array_index ); | |||||
array_index_last = array_index; | array_index_last = array_index; | ||||
} | } | ||||
return array_index_str; | return array_index_str; | ||||
j.m_type = value_t::array; | j.m_type = value_t::array; | ||||
j.m_value = value_t::array; | j.m_value = value_t::array; | ||||
j.m_value.array->resize(arr.size()); | j.m_value.array->resize(arr.size()); | ||||
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); | |||||
if (arr.size() > 0) | |||||
{ | |||||
std::copy(std::begin(arr), std::end(arr), j.m_value.array->begin()); | |||||
} | |||||
j.assert_invariant(); | j.assert_invariant(); | ||||
} | } | ||||
}; | }; | ||||
external_constructor<value_t::array>::construct(j, arr); | external_constructor<value_t::array>::construct(j, arr); | ||||
} | } | ||||
template<typename BasicJsonType, typename... Args> | |||||
void to_json(BasicJsonType& j, const std::pair<Args...>& p) | |||||
template < typename BasicJsonType, typename T1, typename T2, enable_if_t < std::is_constructible<BasicJsonType, T1>::value&& std::is_constructible<BasicJsonType, T2>::value, int > = 0 > | |||||
void to_json(BasicJsonType& j, const std::pair<T1, T2>& p) | |||||
{ | { | ||||
j = { p.first, p.second }; | j = { p.first, p.second }; | ||||
} | } | ||||
j = { std::get<Idx>(t)... }; | j = { std::get<Idx>(t)... }; | ||||
} | } | ||||
template<typename BasicJsonType, typename... Args> | |||||
void to_json(BasicJsonType& j, const std::tuple<Args...>& t) | |||||
template<typename BasicJsonType, typename T, enable_if_t<is_constructible_tuple<BasicJsonType, T>::value, int > = 0> | |||||
void to_json(BasicJsonType& j, const T& t) | |||||
{ | { | ||||
to_json_tuple_impl(j, t, index_sequence_for<Args...> {}); | |||||
to_json_tuple_impl(j, t, make_index_sequence<std::tuple_size<T>::value> {}); | |||||
} | } | ||||
struct to_json_fn | struct to_json_fn | ||||
class input_buffer_adapter : public input_adapter_protocol | class input_buffer_adapter : public input_adapter_protocol | ||||
{ | { | ||||
public: | public: | ||||
JSON_HEDLEY_NON_NULL(2) | |||||
input_buffer_adapter(const char* b, const std::size_t l) noexcept | input_buffer_adapter(const char* b, const std::size_t l) noexcept | ||||
: cursor(b), limit(b + l) | |||||
: cursor(b), limit(b == nullptr ? nullptr : (b + l)) | |||||
{} | {} | ||||
// delete because of pointer members | // delete because of pointer members | ||||
{ | { | ||||
if (JSON_HEDLEY_LIKELY(cursor < limit)) | if (JSON_HEDLEY_LIKELY(cursor < limit)) | ||||
{ | { | ||||
assert(cursor != nullptr and limit != nullptr); | |||||
return std::char_traits<char>::to_int_type(*(cursor++)); | return std::char_traits<char>::to_int_type(*(cursor++)); | ||||
} | } | ||||
const int exp = (half >> 10u) & 0x1Fu; | const int exp = (half >> 10u) & 0x1Fu; | ||||
const unsigned int mant = half & 0x3FFu; | const unsigned int mant = half & 0x3FFu; | ||||
assert(0 <= exp and exp <= 32); | assert(0 <= exp and exp <= 32); | ||||
assert(0 <= mant and mant <= 1024); | |||||
assert(mant <= 1024); | |||||
switch (exp) | switch (exp) | ||||
{ | { | ||||
case 0: | case 0: | ||||
/*! | /*! | ||||
@param[in] format the current format | @param[in] format the current format | ||||
@param[in] detail a detailed error message | @param[in] detail a detailed error message | ||||
@param[in] context further contect information | |||||
@param[in] context further context information | |||||
@return a message string to use in the parse_error exceptions | @return a message string to use in the parse_error exceptions | ||||
*/ | */ | ||||
std::string exception_message(const input_format_t format, | std::string exception_message(const input_format_t format, | ||||
/*! | /*! | ||||
@brief const copy constructor | @brief const copy constructor | ||||
@param[in] other const iterator to copy from | @param[in] other const iterator to copy from | ||||
@note This copy constuctor had to be defined explicitely to circumvent a bug | |||||
occuring on msvc v19.0 compiler (VS 2015) debug build. For more | |||||
@note This copy constructor had to be defined explicitly to circumvent a bug | |||||
occurring on msvc v19.0 compiler (VS 2015) debug build. For more | |||||
information refer to: https://github.com/nlohmann/json/issues/1608 | information refer to: https://github.com/nlohmann/json/issues/1608 | ||||
*/ | */ | ||||
iter_impl(const iter_impl<const BasicJsonType>& other) noexcept | iter_impl(const iter_impl<const BasicJsonType>& other) noexcept | ||||
/*! | /*! | ||||
@brief append an array index at the end of this JSON pointer | @brief append an array index at the end of this JSON pointer | ||||
@param[in] array_index array index ot append | |||||
@param[in] array_index array index to append | |||||
@return JSON pointer with @a array_index appended | @return JSON pointer with @a array_index appended | ||||
@liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} | @liveexample{The example shows the usage of `operator/=`.,json_pointer__operator_add} | ||||
@since version 3.6.0 | @since version 3.6.0 | ||||
*/ | */ | ||||
const std::string& back() | |||||
const std::string& back() const | |||||
{ | { | ||||
if (JSON_HEDLEY_UNLIKELY(empty())) | if (JSON_HEDLEY_UNLIKELY(empty())) | ||||
{ | { | ||||
*/ | */ | ||||
static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) | static std::size_t calc_bson_array_size(const typename BasicJsonType::array_t& value) | ||||
{ | { | ||||
std::size_t embedded_document_size = 0ul; | |||||
std::size_t array_index = 0ul; | std::size_t array_index = 0ul; | ||||
for (const auto& el : value) | |||||
const std::size_t embedded_document_size = std::accumulate(std::begin(value), std::end(value), 0ul, [&array_index](std::size_t result, const typename BasicJsonType::array_t::value_type & el) | |||||
{ | { | ||||
embedded_document_size += calc_bson_element_size(std::to_string(array_index++), el); | |||||
} | |||||
return result + calc_bson_element_size(std::to_string(array_index++), el); | |||||
}); | |||||
return sizeof(std::int32_t) + embedded_document_size + 1ul; | return sizeof(std::int32_t) + embedded_document_size + 1ul; | ||||
} | } | ||||
// ==> 2^(q - 1 + alpha) <= c * 2^(e + q) | // ==> 2^(q - 1 + alpha) <= c * 2^(e + q) | ||||
// ==> 2^(alpha - e - 1) <= c | // ==> 2^(alpha - e - 1) <= c | ||||
// | // | ||||
// If c were an exakt power of ten, i.e. c = 10^k, one may determine k as | |||||
// If c were an exact power of ten, i.e. c = 10^k, one may determine k as | |||||
// | // | ||||
// k = ceil( log_10( 2^(alpha - e - 1) ) ) | // k = ceil( log_10( 2^(alpha - e - 1) ) ) | ||||
// = ceil( (alpha - e - 1) * log_10(2) ) | // = ceil( (alpha - e - 1) * log_10(2) ) | ||||
if (is_negative) | if (is_negative) | ||||
{ | { | ||||
*buffer_ptr = '-'; | *buffer_ptr = '-'; | ||||
abs_value = static_cast<number_unsigned_t>(std::abs(static_cast<std::intmax_t>(x))); | |||||
abs_value = remove_sign(x); | |||||
// account one more byte for the minus sign | // account one more byte for the minus sign | ||||
n_chars = 1 + count_digits(abs_value); | n_chars = 1 + count_digits(abs_value); | ||||
return state; | return state; | ||||
} | } | ||||
/* | |||||
* Overload to make the compiler happy while it is instantiating | |||||
* dump_integer for number_unsigned_t. | |||||
* Must never be called. | |||||
*/ | |||||
number_unsigned_t remove_sign(number_unsigned_t x) | |||||
{ | |||||
assert(false); // LCOV_EXCL_LINE | |||||
return x; // LCOV_EXCL_LINE | |||||
} | |||||
/* | |||||
* Helper function for dump_integer | |||||
* | |||||
* This function takes a negative signed integer and returns its absolute | |||||
* value as unsigned integer. The plus/minus shuffling is necessary as we can | |||||
* not directly remove the sign of an arbitrary signed integer as the | |||||
* absolute values of INT_MIN and INT_MAX are usually not the same. See | |||||
* #1708 for details. | |||||
*/ | |||||
inline number_unsigned_t remove_sign(number_integer_t x) noexcept | |||||
{ | |||||
assert(x < 0 and x < (std::numeric_limits<number_integer_t>::max)()); | |||||
return static_cast<number_unsigned_t>(-(x + 1)) + 1; | |||||
} | |||||
private: | private: | ||||
/// the output of the serializer | /// the output of the serializer | ||||
output_adapter_t<char> o = nullptr; | output_adapter_t<char> o = nullptr; | ||||
object = nullptr; // silence warning, see #821 | object = nullptr; // silence warning, see #821 | ||||
if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) | if (JSON_HEDLEY_UNLIKELY(t == value_t::null)) | ||||
{ | { | ||||
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.7.0")); // LCOV_EXCL_LINE | |||||
JSON_THROW(other_error::create(500, "961c151d2e87f2686a955a9be24d316f1362bf21 3.7.1")); // LCOV_EXCL_LINE | |||||
} | } | ||||
break; | break; | ||||
} | } | ||||
detail::has_non_default_from_json<basic_json_t, ValueType>::value, | detail::has_non_default_from_json<basic_json_t, ValueType>::value, | ||||
int> = 0> | int> = 0> | ||||
ValueType get() const noexcept(noexcept( | ValueType get() const noexcept(noexcept( | ||||
JSONSerializer<ValueTypeCV>::from_json(std::declval<const basic_json_t&>()))) | |||||
JSONSerializer<ValueType>::from_json(std::declval<const basic_json_t&>()))) | |||||
{ | { | ||||
static_assert(not std::is_reference<ValueTypeCV>::value, | static_assert(not std::is_reference<ValueTypeCV>::value, | ||||
"get() cannot be used with reference types, you might want to use get_ref()"); | "get() cannot be used with reference types, you might want to use get_ref()"); | ||||
return JSONSerializer<ValueTypeCV>::from_json(*this); | |||||
return JSONSerializer<ValueType>::from_json(*this); | |||||
} | } | ||||
/*! | /*! | ||||
@since version 3.6.0 | @since version 3.6.0 | ||||
*/ | */ | ||||
template<typename KeyT, typename std::enable_if< | template<typename KeyT, typename std::enable_if< | ||||
not std::is_same<KeyT, json_pointer>::value, int>::type = 0> | |||||
not std::is_same<typename std::decay<KeyT>::type, json_pointer>::value, int>::type = 0> | |||||
bool contains(KeyT && key) const | bool contains(KeyT && key) const | ||||
{ | { | ||||
return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); | return is_object() and m_value.object->find(std::forward<KeyT>(key)) != m_value.object->end(); | ||||
/*! | /*! | ||||
@brief check the existence of an element in a JSON object given a JSON pointer | @brief check the existence of an element in a JSON object given a JSON pointer | ||||
Check wehther the given JSON pointer @a ptr can be resolved in the current | |||||
Check whether the given JSON pointer @a ptr can be resolved in the current | |||||
JSON value. | JSON value. | ||||
@note This method can be executed on any JSON value type. | @note This method can be executed on any JSON value type. | ||||
/// @note: do not remove the space after '<', | /// @note: do not remove the space after '<', | ||||
/// see https://github.com/nlohmann/json/pull/679 | /// see https://github.com/nlohmann/json/pull/679 | ||||
template<> | template<> | ||||
struct less< ::nlohmann::detail::value_t> | |||||
struct less<::nlohmann::detail::value_t> | |||||
{ | { | ||||
/*! | /*! | ||||
@brief compare two value_t enum values | @brief compare two value_t enum values | ||||
#undef JSON_HEDLEY_ARRAY_PARAM | #undef JSON_HEDLEY_ARRAY_PARAM | ||||
#undef JSON_HEDLEY_ASSUME | #undef JSON_HEDLEY_ASSUME | ||||
#undef JSON_HEDLEY_BEGIN_C_DECLS | #undef JSON_HEDLEY_BEGIN_C_DECLS | ||||
#undef JSON_HEDLEY_C_DECL | |||||
#undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE | #undef JSON_HEDLEY_CLANG_HAS_ATTRIBUTE | ||||
#undef JSON_HEDLEY_CLANG_HAS_BUILTIN | #undef JSON_HEDLEY_CLANG_HAS_BUILTIN | ||||
#undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE | #undef JSON_HEDLEY_CLANG_HAS_CPP_ATTRIBUTE | ||||
#undef JSON_HEDLEY_CONCAT | #undef JSON_HEDLEY_CONCAT | ||||
#undef JSON_HEDLEY_CONCAT_EX | #undef JSON_HEDLEY_CONCAT_EX | ||||
#undef JSON_HEDLEY_CONST | #undef JSON_HEDLEY_CONST | ||||
#undef JSON_HEDLEY_CONSTEXPR | |||||
#undef JSON_HEDLEY_CONST_CAST | #undef JSON_HEDLEY_CONST_CAST | ||||
#undef JSON_HEDLEY_CONSTEXPR | |||||
#undef JSON_HEDLEY_CPP_CAST | #undef JSON_HEDLEY_CPP_CAST | ||||
#undef JSON_HEDLEY_CRAY_VERSION | #undef JSON_HEDLEY_CRAY_VERSION | ||||
#undef JSON_HEDLEY_CRAY_VERSION_CHECK | #undef JSON_HEDLEY_CRAY_VERSION_CHECK | ||||
#undef JSON_HEDLEY_C_DECL | |||||
#undef JSON_HEDLEY_DEPRECATED | #undef JSON_HEDLEY_DEPRECATED | ||||
#undef JSON_HEDLEY_DEPRECATED_FOR | #undef JSON_HEDLEY_DEPRECATED_FOR | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CAST_QUAL | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_CPP98_COMPAT_WRAP_ | |||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_DEPRECATED | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_CPP_ATTRIBUTES | |||||
#undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | #undef JSON_HEDLEY_DIAGNOSTIC_DISABLE_UNKNOWN_PRAGMAS | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_POP | #undef JSON_HEDLEY_DIAGNOSTIC_POP | ||||
#undef JSON_HEDLEY_DIAGNOSTIC_PUSH | #undef JSON_HEDLEY_DIAGNOSTIC_PUSH | ||||
#undef JSON_HEDLEY_DMC_VERSION | #undef JSON_HEDLEY_DMC_VERSION | ||||
#undef JSON_HEDLEY_DMC_VERSION_CHECK | #undef JSON_HEDLEY_DMC_VERSION_CHECK | ||||
#undef JSON_HEDLEY_EMPTY_BASES | |||||
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION | ||||
#undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK | #undef JSON_HEDLEY_EMSCRIPTEN_VERSION_CHECK | ||||
#undef JSON_HEDLEY_END_C_DECLS | #undef JSON_HEDLEY_END_C_DECLS | ||||
#undef JSON_HEDLEY_HAS_ATTRIBUTE | #undef JSON_HEDLEY_HAS_ATTRIBUTE | ||||
#undef JSON_HEDLEY_HAS_BUILTIN | #undef JSON_HEDLEY_HAS_BUILTIN | ||||
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | #undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE | ||||
#undef JSON_HEDLEY_HAS_CPP_ATTRIBUTE_NS | |||||
#undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE | #undef JSON_HEDLEY_HAS_DECLSPEC_ATTRIBUTE | ||||
#undef JSON_HEDLEY_HAS_EXTENSION | #undef JSON_HEDLEY_HAS_EXTENSION | ||||
#undef JSON_HEDLEY_HAS_FEATURE | #undef JSON_HEDLEY_HAS_FEATURE | ||||
#undef JSON_HEDLEY_INTEL_VERSION | #undef JSON_HEDLEY_INTEL_VERSION | ||||
#undef JSON_HEDLEY_INTEL_VERSION_CHECK | #undef JSON_HEDLEY_INTEL_VERSION_CHECK | ||||
#undef JSON_HEDLEY_IS_CONSTANT | #undef JSON_HEDLEY_IS_CONSTANT | ||||
#undef JSON_HEDLEY_IS_CONSTEXPR_ | |||||
#undef JSON_HEDLEY_LIKELY | #undef JSON_HEDLEY_LIKELY | ||||
#undef JSON_HEDLEY_MALLOC | #undef JSON_HEDLEY_MALLOC | ||||
#undef JSON_HEDLEY_MESSAGE | #undef JSON_HEDLEY_MESSAGE | ||||
#undef JSON_HEDLEY_MSVC_VERSION | #undef JSON_HEDLEY_MSVC_VERSION | ||||
#undef JSON_HEDLEY_MSVC_VERSION_CHECK | #undef JSON_HEDLEY_MSVC_VERSION_CHECK | ||||
#undef JSON_HEDLEY_NEVER_INLINE | #undef JSON_HEDLEY_NEVER_INLINE | ||||
#undef JSON_HEDLEY_NO_ESCAPE | |||||
#undef JSON_HEDLEY_NON_NULL | #undef JSON_HEDLEY_NON_NULL | ||||
#undef JSON_HEDLEY_NO_RETURN | #undef JSON_HEDLEY_NO_RETURN | ||||
#undef JSON_HEDLEY_NO_THROW | #undef JSON_HEDLEY_NO_THROW | ||||
#undef JSON_HEDLEY_NULL | |||||
#undef JSON_HEDLEY_PELLES_VERSION | #undef JSON_HEDLEY_PELLES_VERSION | ||||
#undef JSON_HEDLEY_PELLES_VERSION_CHECK | #undef JSON_HEDLEY_PELLES_VERSION_CHECK | ||||
#undef JSON_HEDLEY_PGI_VERSION | #undef JSON_HEDLEY_PGI_VERSION |
Name: nlohmann-json | Name: nlohmann-json | ||||
Namespace: nlohmann | Namespace: nlohmann | ||||
Version: 3.7.0 | |||||
Version: 3.7.1 |
Name: args |
Name: taywee-args | |||||
Version: 0.0.0 | |||||
Namespace: taywee |
Name: ms-wil | Name: ms-wil | ||||
Version: 0.0.0 | |||||
Version: 2019.11.10 | |||||
Namespace: Microsoft | Namespace: Microsoft |
Type: Package | |||||
Name: taywee-args | |||||
Namespace: taywee | |||||
Library: args.lml |
Type: Library | Type: Library | ||||
Name: WIL | |||||
Name: wil | |||||
Include-Path: repo/wil/include | Include-Path: repo/wil/include |
Name: dds | Name: dds | ||||
Uses: taywee/args | |||||
Uses: spdlog/spdlog | Uses: spdlog/spdlog | ||||
Uses: Microsoft/WIL | |||||
Uses: Microsoft/wil | |||||
Uses: Niebler/range-v3 | Uses: Niebler/range-v3 | ||||
Uses: nlohmann/json | Uses: nlohmann/json |
Version: 0.1.0 | Version: 0.1.0 | ||||
Depends: neo-buffer 0.1.0 | Depends: neo-buffer 0.1.0 | ||||
Depends: taywee-args 0.0.0 | |||||
Depends: spdlog 1.4.2 | Depends: spdlog 1.4.2 | ||||
Depends: ms-wil 0.0.0 | |||||
Depends: ms-wil 2019.11.10 | |||||
Depends: range-v3 0.9.1 | Depends: range-v3 0.9.1 | ||||
Depends: nlohmann-json 3.7.0 | |||||
Depends: nlohmann-json 3.7.0 | |||||
Depends: nlohmann-json 3.7.1 |
imports: | imports: | ||||
spdlog: external/spdlog | |||||
taywee-args: external/taywee-args | |||||
wil: external/wil | |||||
ranges-v3: external/ranges-v3 | |||||
nlohmann-json: external/nlohmann-json/include/nlohmann | |||||
spdlog: external/repo/spdlog | |||||
taywee-args: external/repo/taywee-args | |||||
wil: external/repo/wil | |||||
ranges-v3: external/repo/range-v3 | |||||
nlohmann-json: external/repo/nlohmann-json/include/nlohmann | |||||
git module spdlog: | git module spdlog: | ||||
url: https://github.com/gabime/spdlog.git | url: https://github.com/gabime/spdlog.git | ||||
pick: include/ | pick: include/ | ||||
curl module nlohmann-json: | curl module nlohmann-json: | ||||
url: https://raw.githubusercontent.com/nlohmann/json/v3.7.0/single_include/nlohmann/json.hpp | |||||
url: https://raw.githubusercontent.com/nlohmann/json/v3.7.1/single_include/nlohmann/json.hpp |
Remote-Package: range-v3 0.9.1; git url=https://github.com/ericniebler/range-v3.git ref=0.9.1 auto=Niebler/range-v3 | |||||
Remote-Package: spdlog 1.4.2; git url=https://github.com/gabime/spdlog.git ref=v1.4.2 auto=spdlog/spdlog | |||||
# Even a shallow clone of nlohmann-json is HUGE. This fork has only the minimal | |||||
Remote-Package: nlohmann-json 3.7.1; git url=https://github.com/vector-of-bool/json.git ref=dds/3.7.1 | |||||
# MS never tags anything in this repo, so we'll use a fork that has some tags. | |||||
Remote-Package: ms-wil 2019.11.10; git url=https://github.com/vector-of-bool/wil.git ref=dds/2019.11.10 | |||||
# XXX: Don't depend on a moving revision! | |||||
Remote-Package: neo-buffer 0.1.0; git url=https://github.com/vector-of-bool/neo-buffer.git ref=develop |
return usage_requirement_map::from_lm_index(idx); | return usage_requirement_map::from_lm_index(idx); | ||||
} | } | ||||
void prepare_catch2_driver(library_build_params& lib_params, | |||||
test_lib test_driver, | |||||
const build_params& params, | |||||
const package_manifest& man) { | |||||
void prepare_catch2_driver(library_build_params& lib_params, | |||||
test_lib test_driver, | |||||
const build_params& params, | |||||
const package_manifest&) { | |||||
fs::path test_include_root = params.out_root / "_test_inc"; | fs::path test_include_root = params.out_root / "_test_inc"; | ||||
lib_params.test_include_dirs.emplace_back(test_include_root); | lib_params.test_include_dirs.emplace_back(test_include_root); | ||||
#include <dds/build.hpp> | #include <dds/build.hpp> | ||||
#include <dds/logging.hpp> | #include <dds/logging.hpp> | ||||
#include <dds/repo/remote.hpp> | |||||
#include <dds/repo/repo.hpp> | #include <dds/repo/repo.hpp> | ||||
#include <dds/sdist.hpp> | #include <dds/sdist.hpp> | ||||
#include <dds/toolchain/from_dds.hpp> | #include <dds/toolchain/from_dds.hpp> | ||||
#include <range/v3/view/group_by.hpp> | #include <range/v3/view/group_by.hpp> | ||||
#include <range/v3/view/transform.hpp> | #include <range/v3/view/transform.hpp> | ||||
#include <args.hxx> | |||||
#include <dds/3rd/args.hxx> | |||||
#include <filesystem> | #include <filesystem> | ||||
#include <iostream> | #include <iostream> | ||||
auto same_name | auto same_name | ||||
= [](auto&& a, auto&& b) { return a.manifest.name == b.manifest.name; }; | = [](auto&& a, auto&& b) { return a.manifest.name == b.manifest.name; }; | ||||
auto all_sdists = repo.load_sdists(); | |||||
auto grp_by_name = all_sdists // | |||||
auto all = repo.iter_sdists(); | |||||
auto grp_by_name = all // | |||||
| ranges::views::group_by(same_name) // | | ranges::views::group_by(same_name) // | ||||
| ranges::views::transform(ranges::to_vector) // | | ranges::views::transform(ranges::to_vector) // | ||||
| ranges::views::transform([](auto&& grp) { | | ranges::views::transform([](auto&& grp) { | ||||
for (const auto& [name, grp] : grp_by_name) { | for (const auto& [name, grp] : grp_by_name) { | ||||
spdlog::info("{}:", name); | spdlog::info("{}:", name); | ||||
for (const dds::sdist& sd : grp) { | for (const dds::sdist& sd : grp) { | ||||
spdlog::info(" - {}", | |||||
sd.manifest.version.to_string()); | |||||
spdlog::info(" - {}", sd.manifest.version.to_string()); | |||||
} | } | ||||
} | } | ||||
common_flags _common{cmd}; | common_flags _common{cmd}; | ||||
common_project_flags project{cmd}; | |||||
args::Group sdist_group{cmd, "`sdist` commands"}; | args::Group sdist_group{cmd, "`sdist` commands"}; | ||||
struct { | struct { | ||||
cli_sdist& parent; | cli_sdist& parent; | ||||
args::Command cmd{parent.sdist_group, "create", "Create a source distribution"}; | args::Command cmd{parent.sdist_group, "create", "Create a source distribution"}; | ||||
common_project_flags project{cmd}; | |||||
path_flag out{cmd, | path_flag out{cmd, | ||||
"out", | "out", | ||||
"The destination of the source distribution", | "The destination of the source distribution", | ||||
int run() { | int run() { | ||||
dds::sdist_params params; | dds::sdist_params params; | ||||
params.project_dir = parent.project.root.Get(); | |||||
params.project_dir = project.root.Get(); | |||||
params.dest_path = out.Get(); | params.dest_path = out.Get(); | ||||
params.force = force.Get(); | params.force = force.Get(); | ||||
dds::create_sdist(params); | dds::create_sdist(params); | ||||
"export", | "export", | ||||
"Export a source distribution to a repository"}; | "Export a source distribution to a repository"}; | ||||
common_project_flags project{cmd}; | |||||
repo_where_flag repo_where{cmd}; | repo_where_flag repo_where{cmd}; | ||||
args::Flag force{cmd, | args::Flag force{cmd, | ||||
"replace-if-exists", | "replace-if-exists", | ||||
dds::fs::remove_all(tmp_sdist); | dds::fs::remove_all(tmp_sdist); | ||||
} | } | ||||
dds::sdist_params params; | dds::sdist_params params; | ||||
params.project_dir = parent.project.root.Get(); | |||||
params.project_dir = project.root.Get(); | |||||
params.dest_path = tmp_sdist; | params.dest_path = tmp_sdist; | ||||
params.force = true; | params.force = true; | ||||
auto sdist = dds::create_sdist(params); | auto sdist = dds::create_sdist(params); | ||||
path_flag lm_index{cmd, | path_flag lm_index{cmd, | ||||
"lm_index", | "lm_index", | ||||
"Path to a libman index (usually INDEX.lmi)", | "Path to a libman index (usually INDEX.lmi)", | ||||
{"--lm-index", 'I'}, | |||||
{"lm-index", 'I'}, | |||||
dds::fs::path()}; | dds::fs::path()}; | ||||
args::Flag enable_warnings{cmd, | args::Flag enable_warnings{cmd, | ||||
} | } | ||||
} ls{*this}; | } ls{*this}; | ||||
struct { | |||||
cli_deps& parent; | |||||
args::Command cmd{parent.deps_group, | |||||
"get", | |||||
"Ensure we have local copies of the project dependencies"}; | |||||
common_flags _common{cmd}; | |||||
repo_where_flag repo_where{cmd}; | |||||
path_flag remote_listing_file{ | |||||
cmd, | |||||
"remote-listing", | |||||
"Path to a file containing listing of remote sdists and how to obtain them", | |||||
{'R', "remote-list"}, | |||||
"remote.dds"}; | |||||
int run() { | |||||
auto man = parent.load_package_manifest(); | |||||
auto rd = dds::remote_directory::load_from_file(remote_listing_file.Get()); | |||||
bool failed = false; | |||||
dds::repository::with_repository( // | |||||
repo_where.Get(), | |||||
dds::repo_flags::write_lock | dds::repo_flags::create_if_absent, | |||||
[&](dds::repository repo) { | |||||
for (auto& dep : man.dependencies) { | |||||
auto exists = !!repo.find(dep.name, dep.version); | |||||
if (!exists) { | |||||
spdlog::info("Pull remote: {} {}", dep.name, dep.version.to_string()); | |||||
auto opt_remote = rd.find(dep.name, dep.version); | |||||
if (opt_remote) { | |||||
auto tsd = opt_remote->pull_sdist(); | |||||
repo.add_sdist(tsd.sdist, dds::if_exists::ignore); | |||||
} else { | |||||
spdlog::error("No remote listing for {} {}", | |||||
dep.name, | |||||
dep.version.to_string()); | |||||
failed = true; | |||||
} | |||||
} else { | |||||
spdlog::info("Okay: {} {}", dep.name, dep.version.to_string()); | |||||
} | |||||
} | |||||
}); | |||||
if (failed) { | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} | |||||
} get{*this}; | |||||
struct { | struct { | ||||
cli_deps& parent; | cli_deps& parent; | ||||
args::Command cmd{parent.deps_group, "build", "Build project dependencies"}; | args::Command cmd{parent.deps_group, "build", "Build project dependencies"}; | ||||
return ls.run(); | return ls.run(); | ||||
} else if (build.cmd) { | } else if (build.cmd) { | ||||
return build.run(); | return build.run(); | ||||
} else if (get.cmd) { | |||||
return get.run(); | |||||
} | } | ||||
std::terminate(); | std::terminate(); | ||||
} | } |
} | } | ||||
std::vector<sdist> dds::find_dependencies(const repository& repo, const dependency& dep) { | std::vector<sdist> dds::find_dependencies(const repository& repo, const dependency& dep) { | ||||
auto all_dists = repo.load_sdists(); | |||||
detail::sort_sdists(all_dists); | |||||
std::vector<sdist> acc; | std::vector<sdist> acc; | ||||
detail::do_find_deps(all_dists, dep, acc); | |||||
detail::do_find_deps(repo, dep, acc); | |||||
return acc; | return acc; | ||||
} | } | ||||
auto tie_sdist(const sdist& sd) { | |||||
return std::tuple(sd.manifest.name, sd.manifest.version.to_string()); | |||||
} | |||||
auto sdist_compare | |||||
= [](const sdist& lhs, const sdist& rhs) { return tie_sdist(lhs) < tie_sdist(rhs); }; | |||||
void detail::sort_sdists(std::vector<sdist>& sd) { std::sort(sd.begin(), sd.end(), sdist_compare); } | |||||
namespace { | |||||
const sdist* | |||||
get_sdist(const std::vector<sdist>& sorted_sds, std::string_view name, std::string_view version) { | |||||
auto found | |||||
= std::partition_point(sorted_sds.begin(), sorted_sds.end(), [&](const auto& candidate) { | |||||
return tie_sdist(candidate) < std::tie(name, version); | |||||
}); | |||||
if (found->manifest.name == name && found->manifest.version.to_string() == version) { | |||||
return &*found; | |||||
} | |||||
return nullptr; | |||||
} | |||||
} // namespace | |||||
void detail::do_find_deps(const std::vector<sdist>& sdists, | |||||
const dependency& dep, | |||||
std::vector<sdist>& sd) { | |||||
auto sdist_opt = get_sdist(sdists, dep.name, dep.version.to_string()); | |||||
void detail::do_find_deps(const repository& repo, const dependency& dep, std::vector<sdist>& sd) { | |||||
auto sdist_opt = repo.find(dep.name, dep.version); | |||||
if (!sdist_opt) { | if (!sdist_opt) { | ||||
throw std::runtime_error( | throw std::runtime_error( | ||||
fmt::format("Unable to find dependency to satisfy requirement: {} {}", | fmt::format("Unable to find dependency to satisfy requirement: {} {}", | ||||
} | } | ||||
const sdist& new_sd = *sdist_opt; | const sdist& new_sd = *sdist_opt; | ||||
for (const auto& inner_dep : new_sd.manifest.dependencies) { | for (const auto& inner_dep : new_sd.manifest.dependencies) { | ||||
do_find_deps(sdists, inner_dep, sd); | |||||
do_find_deps(repo, inner_dep, sd); | |||||
} | } | ||||
auto insert_point = std::partition_point(sd.begin(), sd.end(), [&](const sdist& cand) { | auto insert_point = std::partition_point(sd.begin(), sd.end(), [&](const sdist& cand) { | ||||
return cand.path < new_sd.path; | return cand.path < new_sd.path; | ||||
} | } | ||||
auto pub_inc_dir = lib.source_root() / "include"; | auto pub_inc_dir = lib.source_root() / "include"; | ||||
auto src_dir = lib.source_root() / "src"; | auto src_dir = lib.source_root() / "src"; | ||||
if (fs::exists(src_dir)) { | |||||
if (!fs::exists(pub_inc_dir)) { | |||||
pub_inc_dir = src_dir; | pub_inc_dir = src_dir; | ||||
} | } | ||||
kvs.emplace_back("Include-Path", pub_inc_dir.string()); | kvs.emplace_back("Include-Path", pub_inc_dir.string()); |
#pragma once | #pragma once | ||||
#include <dds/build/plan/full.hpp> | #include <dds/build/plan/full.hpp> | ||||
#include <dds/repo/repo.hpp> | |||||
#include <semver/version.hpp> | #include <semver/version.hpp> | ||||
namespace dds { | namespace dds { | ||||
struct sdist; | struct sdist; | ||||
class repository; | |||||
enum class version_strength { | enum class version_strength { | ||||
exact, | exact, | ||||
namespace detail { | namespace detail { | ||||
void do_find_deps(const std::vector<sdist>&, const dependency& dep, std::vector<sdist>& acc); | |||||
void sort_sdists(std::vector<sdist>& sds); | |||||
void do_find_deps(const repository&, const dependency& dep, std::vector<sdist>& acc); | |||||
} // namespace detail | } // namespace detail | ||||
template <typename Iter, typename Snt> | template <typename Iter, typename Snt> | ||||
inline std::vector<sdist> find_dependencies(const repository& repo, Iter it, Snt stop) { | inline std::vector<sdist> find_dependencies(const repository& repo, Iter it, Snt stop) { | ||||
std::vector<sdist> acc; | std::vector<sdist> acc; | ||||
auto all_sds = repo.load_sdists(); | |||||
detail::sort_sdists(all_sds); | |||||
while (it != stop) { | while (it != stop) { | ||||
detail::do_find_deps(all_sds, *it++, acc); | |||||
detail::do_find_deps(repo, *it++, acc); | |||||
} | } | ||||
return acc; | return acc; | ||||
} | } | ||||
void write_libman_index(path_ref where, const build_plan& plan, const build_env& env); | void write_libman_index(path_ref where, const build_plan& plan, const build_env& env); | ||||
} // namespace dds | |||||
} // namespace dds |
#include "./remote.hpp" | |||||
#include <dds/deps.hpp> | |||||
#include <dds/proc.hpp> | |||||
#include <dds/repo/repo.hpp> | |||||
#include <dds/sdist.hpp> | |||||
#include <dds/temp.hpp> | |||||
#include <dds/toolchain/toolchain.hpp> | |||||
#include <spdlog/spdlog.h> | |||||
#include <libman/parse.hpp> | |||||
#include <algorithm> | |||||
using namespace dds; | |||||
namespace { | |||||
struct read_listing_item { | |||||
std::string_view _key; | |||||
std::set<remote_listing, remote_listing_compare_t>& out; | |||||
bool operator()(std::string_view context, std::string_view key, std::string_view value) { | |||||
if (key != _key) { | |||||
return false; | |||||
} | |||||
auto nested = lm::nested_kvlist::parse(value); | |||||
auto name_ver_pair = split_shell_string(nested.primary); | |||||
if (name_ver_pair.size() != 2) { | |||||
throw std::runtime_error( | |||||
fmt::format("{}: Invalid Remote-Package identity: '{}'", context, nested.primary)); | |||||
} | |||||
auto name = name_ver_pair[0]; | |||||
auto version = semver::version::parse(name_ver_pair[1]); | |||||
put_listing(context, name, version, nested.pairs); | |||||
return true; | |||||
} | |||||
void put_listing(std::string_view context, | |||||
std::string name, | |||||
semver::version version, | |||||
const lm::pair_list& pairs) { | |||||
if (pairs.find("git")) { | |||||
std::string url; | |||||
std::string ref; | |||||
std::optional<lm::usage> auto_id; | |||||
lm::read(fmt::format("{}: Parsing Git remote listing", context), | |||||
pairs, | |||||
lm::read_required("url", url), | |||||
lm::read_required("ref", ref), | |||||
lm::read_check_eq("git", ""), | |||||
lm::read_opt("auto", auto_id, &lm::split_usage_string), | |||||
lm::reject_unknown()); | |||||
auto did_insert = out.emplace(remote_listing{std::move(name), | |||||
version, | |||||
git_remote_listing{url, ref, auto_id}}) | |||||
.second; | |||||
if (!did_insert) { | |||||
spdlog::warn("Duplicate remote package defintion for {} {}", | |||||
name, | |||||
version.to_string()); | |||||
} | |||||
} else { | |||||
throw std::runtime_error(fmt::format("Unable to determine remote type of package {} {}", | |||||
name, | |||||
version.to_string())); | |||||
} | |||||
} | |||||
}; | |||||
temporary_sdist do_pull_sdist(const remote_listing& listing, const git_remote_listing& git) { | |||||
auto tmpdir = dds::temporary_dir::create(); | |||||
using namespace std::literals; | |||||
spdlog::info("Cloning repository: {} [{}] ...", git.url, git.ref); | |||||
auto command = {"git"s, | |||||
"clone"s, | |||||
"--depth=1"s, | |||||
"--branch"s, | |||||
git.ref, | |||||
git.url, | |||||
tmpdir.path().generic_string()}; | |||||
auto git_res = run_proc(command); | |||||
if (!git_res.okay()) { | |||||
throw std::runtime_error( | |||||
fmt::format("Git clone operation failed [Git command: {}] [Exitted {}]:\n{}", | |||||
quote_command(command), | |||||
git_res.retc, | |||||
git_res.output)); | |||||
} | |||||
spdlog::info("Create sdist from clone ..."); | |||||
if (git.auto_lib.has_value()) { | |||||
spdlog::info("Generating library data automatically"); | |||||
auto pkg_strm = dds::open(tmpdir.path() / "package.dds", std::ios::binary | std::ios::out); | |||||
pkg_strm << "Name: " << listing.name << '\n' // | |||||
<< "Version: " << listing.version.to_string() << '\n' // | |||||
<< "Namespace: " << git.auto_lib->namespace_; | |||||
auto lib_strm = dds::open(tmpdir.path() / "library.dds", std::ios::binary | std::ios::out); | |||||
lib_strm << "Name: " << git.auto_lib->name; | |||||
} | |||||
sdist_params params; | |||||
params.project_dir = tmpdir.path(); | |||||
auto sd_tmp_dir = dds::temporary_dir::create(); | |||||
params.dest_path = sd_tmp_dir.path(); | |||||
params.force = true; | |||||
auto sd = create_sdist(params); | |||||
return {sd_tmp_dir, sd}; | |||||
} | |||||
} // namespace | |||||
temporary_sdist remote_listing::pull_sdist() const { | |||||
auto tsd = visit([&](auto&& actual) { return do_pull_sdist(*this, actual); }); | |||||
if (tsd.sdist.manifest.name != name) { | |||||
throw std::runtime_error( | |||||
fmt::format("The name in the generated sdist ('{}') does not match the name listed in " | |||||
"the remote listing file (expected '{}')", | |||||
tsd.sdist.manifest.name, | |||||
name)); | |||||
} | |||||
if (tsd.sdist.manifest.version != version) { | |||||
throw std::runtime_error( | |||||
fmt::format("The version of the generated sdist is '{}', which does not match the " | |||||
"expected version '{}'", | |||||
tsd.sdist.manifest.version.to_string(), | |||||
version.to_string())); | |||||
} | |||||
return tsd; | |||||
} | |||||
remote_directory remote_directory::load_from_file(path_ref filepath) { | |||||
auto kvs = lm::parse_file(filepath); | |||||
listing_set listings; | |||||
lm::read(fmt::format("Loading remote package listing from {}", filepath.string()), | |||||
kvs, | |||||
read_listing_item{"Remote-Package", listings}, | |||||
lm::reject_unknown()); | |||||
return {std::move(listings)}; | |||||
} | |||||
const remote_listing* remote_directory::find(std::string_view name, semver::version ver) const | |||||
noexcept { | |||||
auto found = _remotes.find(std::tie(name, ver)); | |||||
if (found == _remotes.end()) { | |||||
return nullptr; | |||||
} | |||||
return &*found; | |||||
} | |||||
void remote_directory::ensure_all_local(const repository&) const { | |||||
spdlog::critical("Dependency download is not fully implemented!"); | |||||
} |
#pragma once | |||||
#include <dds/util/fs.hpp> | |||||
#include <dds/sdist.hpp> | |||||
#include <dds/temp.hpp> | |||||
#include <semver/version.hpp> | |||||
#include <libman/library.hpp> | |||||
#include <set> | |||||
#include <string> | |||||
#include <tuple> | |||||
#include <utility> | |||||
#include <variant> | |||||
namespace dds { | |||||
struct temporary_sdist { | |||||
temporary_dir tmpdir; | |||||
dds::sdist sdist; | |||||
}; | |||||
struct git_remote_listing { | |||||
std::string url; | |||||
std::string ref; | |||||
std::optional<lm::usage> auto_lib; | |||||
void clone(path_ref path) const; | |||||
}; | |||||
struct remote_listing { | |||||
std::string name; | |||||
semver::version version; | |||||
std::variant<git_remote_listing> remote; | |||||
template <typename Func> | |||||
decltype(auto) visit(Func&& fn) const { | |||||
return std::visit(std::forward<Func>(fn), remote); | |||||
} | |||||
temporary_sdist pull_sdist() const; | |||||
}; | |||||
inline constexpr struct remote_listing_compare_t { | |||||
using is_transparent = int; | |||||
auto tie(const remote_listing& rl) const { return std::tie(rl.name, rl.version); } | |||||
bool operator()(const remote_listing& lhs, const remote_listing& rhs) const { | |||||
return tie(lhs) < tie(rhs); | |||||
} | |||||
template <typename Name, typename Version> | |||||
bool operator()(const remote_listing& lhs, const std::tuple<Name, Version>& rhs) const { | |||||
return tie(lhs) < rhs; | |||||
} | |||||
template <typename Name, typename Version> | |||||
bool operator()(const std::tuple<Name, Version>& lhs, const remote_listing& rhs) const { | |||||
return lhs < tie(rhs); | |||||
} | |||||
} remote_listing_compare; | |||||
class remote_directory { | |||||
using listing_set = std::set<remote_listing, remote_listing_compare_t>; | |||||
listing_set _remotes; | |||||
remote_directory(listing_set s) | |||||
: _remotes(std::move(s)) {} | |||||
public: | |||||
static remote_directory load_from_file(path_ref); | |||||
void ensure_all_local(const class repository& repo) const; | |||||
const remote_listing* find(std::string_view name, semver::version ver) const noexcept; | |||||
}; | |||||
} // namespace dds |
#include <spdlog/spdlog.h> | #include <spdlog/spdlog.h> | ||||
#include <range/v3/range/conversion.hpp> | |||||
#include <range/v3/view/filter.hpp> | #include <range/v3/view/filter.hpp> | ||||
#include <range/v3/view/transform.hpp> | #include <range/v3/view/transform.hpp> | ||||
using namespace ranges; | using namespace ranges; | ||||
namespace { | |||||
auto load_sdists(path_ref root) { | |||||
using namespace ranges; | |||||
using namespace ranges::views; | |||||
auto try_read_sdist = [](path_ref p) -> std::optional<sdist> { | |||||
if (starts_with(p.filename().string(), ".")) { | |||||
return std::nullopt; | |||||
} | |||||
try { | |||||
return sdist::from_directory(p); | |||||
} catch (const std::runtime_error& e) { | |||||
spdlog::error("Failed to load source distribution from directory '{}': {}", | |||||
p.string(), | |||||
e.what()); | |||||
return std::nullopt; | |||||
} | |||||
}; | |||||
return | |||||
// Get the top-level `name-version` dirs | |||||
fs::directory_iterator(root) // | |||||
// // Convert each dir into an `sdist` object | |||||
| transform(try_read_sdist) // | |||||
// // Drop items that failed to load | |||||
| filter([](auto&& opt) { return opt.has_value(); }) // | |||||
| transform([](auto&& opt) { return *opt; }) // | |||||
; | |||||
} | |||||
} // namespace | |||||
void repository::_log_blocking(path_ref dirpath) noexcept { | void repository::_log_blocking(path_ref dirpath) noexcept { | ||||
spdlog::warn("Another process has the repository directory locked [{}]", dirpath.string()); | spdlog::warn("Another process has the repository directory locked [{}]", dirpath.string()); | ||||
spdlog::warn("Waiting for repository to be released..."); | spdlog::warn("Waiting for repository to be released..."); | ||||
} | } | ||||
void repository::_init_repo_dir(path_ref dirpath) noexcept { | |||||
fs::create_directories(dirpath); | |||||
} | |||||
void repository::_init_repo_dir(path_ref dirpath) noexcept { fs::create_directories(dirpath); } | |||||
fs::path repository::default_local_path() noexcept { return dds_data_dir() / "repo"; } | fs::path repository::default_local_path() noexcept { return dds_data_dir() / "repo"; } | ||||
repository repository::open_for_directory(path_ref dirpath) { | |||||
auto dist_dir = dirpath; | |||||
auto entries = fs::directory_iterator(dist_dir) | to_vector; | |||||
return {dirpath}; | |||||
repository repository::_open_for_directory(bool writeable, path_ref dirpath) { | |||||
sdist_set entries = load_sdists(dirpath) | to<sdist_set>(); | |||||
return {writeable, dirpath, std::move(entries)}; | |||||
} | } | ||||
void repository::add_sdist(const sdist& sd, if_exists ife_action) { | void repository::add_sdist(const sdist& sd, if_exists ife_action) { | ||||
auto sd_dest | |||||
= _root / fmt::format("{}_{}", sd.manifest.name, sd.manifest.version.to_string()); | |||||
if (!_write_enabled) { | |||||
spdlog::critical( | |||||
"DDS attempted to write into a repository that wasn't opened with a write-lock. This " | |||||
"is a hard bug and should be reported. For the safety and integrity of the local " | |||||
"repository, we'll hard-exit immediately."); | |||||
std::terminate(); | |||||
} | |||||
auto sd_dest = _root / fmt::format("{}_{}", sd.manifest.name, sd.manifest.version.to_string()); | |||||
if (fs::exists(sd_dest)) { | if (fs::exists(sd_dest)) { | ||||
auto msg = fmt::format("Source distribution '{}' is already available in the local repo", | auto msg = fmt::format("Source distribution '{}' is already available in the local repo", | ||||
sd.path.string()); | sd.path.string()); | ||||
spdlog::info("Source distribution '{}' successfully exported", sd.ident()); | spdlog::info("Source distribution '{}' successfully exported", sd.ident()); | ||||
} | } | ||||
std::vector<sdist> repository::load_sdists() const { | |||||
using namespace ranges; | |||||
using namespace ranges::views; | |||||
auto try_read_sdist = [](path_ref p) -> std::optional<sdist> { | |||||
if (starts_with(p.filename().string(), ".")) { | |||||
return std::nullopt; | |||||
} | |||||
try { | |||||
return sdist::from_directory(p); | |||||
} catch (const std::runtime_error& e) { | |||||
spdlog::error("Failed to load source distribution from directory '{}': {}", | |||||
p.string(), | |||||
e.what()); | |||||
return std::nullopt; | |||||
} | |||||
}; | |||||
return | |||||
// Get the top-level `name-version` dirs | |||||
fs::directory_iterator(_root) // | |||||
// // Convert each dir into an `sdist` object | |||||
| transform(try_read_sdist) // | |||||
// // Drop items that failed to load | |||||
| filter([](auto&& opt) { return opt.has_value(); }) // | |||||
| transform([](auto&& opt) { return *opt; }) // | |||||
| to_vector // | |||||
; | |||||
} | |||||
std::optional<sdist> repository::get_sdist(std::string_view name, std::string_view version) const { | |||||
auto expect_path = _root / fmt::format("{}_{}", name, version); | |||||
if (!fs::is_directory(expect_path)) { | |||||
return std::nullopt; | |||||
const sdist* repository::find(std::string_view name, semver::version ver) const noexcept { | |||||
auto found = _sdists.find(std::tie(name, ver)); | |||||
if (found == _sdists.end()) { | |||||
return nullptr; | |||||
} | } | ||||
return sdist::from_directory(expect_path); | |||||
return &*found; | |||||
} | } |
#pragma once | #pragma once | ||||
#include <dds/sdist.hpp> | |||||
#include <dds/util/flock.hpp> | #include <dds/util/flock.hpp> | ||||
#include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
#include <functional> | #include <functional> | ||||
#include <optional> | #include <optional> | ||||
#include <set> | |||||
#include <shared_mutex> | #include <shared_mutex> | ||||
#include <vector> | #include <vector> | ||||
namespace dds { | namespace dds { | ||||
struct sdist; | |||||
enum repo_flags { | enum repo_flags { | ||||
none = 0b00, | none = 0b00, | ||||
read = none, | read = none, | ||||
} | } | ||||
class repository { | class repository { | ||||
fs::path _root; | |||||
using sdist_set = std::set<sdist, sdist_compare_t>; | |||||
bool _write_enabled = false; | |||||
fs::path _root; | |||||
sdist_set _sdists; | |||||
repository(path_ref p) | |||||
: _root(p) {} | |||||
repository(bool writeable, path_ref p, sdist_set sds) | |||||
: _write_enabled(writeable) | |||||
, _root(p) | |||||
, _sdists(std::move(sds)) {} | |||||
static void _log_blocking(path_ref dir) noexcept; | |||||
static void _init_repo_dir(path_ref dir) noexcept; | |||||
static void _log_blocking(path_ref dir) noexcept; | |||||
static void _init_repo_dir(path_ref dir) noexcept; | |||||
static repository _open_for_directory(bool writeable, path_ref); | |||||
public: | public: | ||||
template <typename Func> | template <typename Func> | ||||
std::shared_lock shared_lk{mut, std::defer_lock}; | std::shared_lock shared_lk{mut, std::defer_lock}; | ||||
std::unique_lock excl_lk{mut, std::defer_lock}; | std::unique_lock excl_lk{mut, std::defer_lock}; | ||||
if (flags & repo_flags::write_lock) { | |||||
bool writeable = (flags & repo_flags::write_lock) != repo_flags::none; | |||||
if (writeable) { | |||||
if (!excl_lk.try_lock()) { | if (!excl_lk.try_lock()) { | ||||
_log_blocking(dirpath); | _log_blocking(dirpath); | ||||
excl_lk.lock(); | excl_lk.lock(); | ||||
} | } | ||||
} | } | ||||
return std::invoke((Func &&) fn, open_for_directory(dirpath)); | |||||
auto repo = _open_for_directory(writeable, dirpath); | |||||
return std::invoke((Func &&) fn, std::move(repo)); | |||||
} | } | ||||
static repository open_for_directory(path_ref); | |||||
static fs::path default_local_path() noexcept; | static fs::path default_local_path() noexcept; | ||||
void add_sdist(const sdist&, if_exists = if_exists::throw_exc); | |||||
std::optional<sdist> get_sdist(std::string_view name, std::string_view version) const; | |||||
std::vector<sdist> load_sdists() const; | |||||
void add_sdist(const sdist&, if_exists = if_exists::throw_exc); | |||||
const sdist* find(std::string_view name, semver::version ver) const noexcept; | |||||
auto iter_sdists() const noexcept { | |||||
class ret { | |||||
const sdist_set& s; | |||||
public: | |||||
ret(const sdist_set& s) | |||||
: s(s) {} | |||||
auto begin() const { return s.cbegin(); } | |||||
auto end() const { return s.cend(); } | |||||
} r{_sdists}; | |||||
return r; | |||||
} | |||||
}; | }; | ||||
} // namespace dds | } // namespace dds |
#pragma once | #pragma once | ||||
#include <tuple> | |||||
#include <dds/package_manifest.hpp> | #include <dds/package_manifest.hpp> | ||||
#include <dds/util/fs.hpp> | #include <dds/util/fs.hpp> | ||||
} | } | ||||
}; | }; | ||||
inline constexpr struct sdist_compare_t { | |||||
bool operator()(const sdist& lhs, const sdist& rhs) const { | |||||
return std::tie(lhs.manifest.name, lhs.manifest.version) | |||||
< std::tie(rhs.manifest.name, rhs.manifest.version); | |||||
} | |||||
template <typename Name, typename Version> | |||||
bool operator()(const sdist& lhs, const std::tuple<Name, Version>& rhs) const { | |||||
return std::tie(lhs.manifest.name, lhs.manifest.version) < rhs; | |||||
} | |||||
template <typename Name, typename Version> | |||||
bool operator()(const std::tuple<Name, Version>& lhs, const sdist& rhs) const { | |||||
return lhs < std::tie(rhs.manifest.name, rhs.manifest.version); | |||||
} | |||||
using is_transparent = int; | |||||
} sdist_compare; | |||||
sdist create_sdist(const sdist_params&); | sdist create_sdist(const sdist_params&); | ||||
sdist create_sdist_in_dir(path_ref, const sdist_params&); | sdist create_sdist_in_dir(path_ref, const sdist_params&); | ||||
#include <dds/util/string.hpp> | #include <dds/util/string.hpp> | ||||
#include <algorithm> | #include <algorithm> | ||||
#include <cassert> | |||||
#include <optional> | #include <optional> | ||||
#include <vector> | #include <vector> | ||||
std::optional<source_kind> dds::infer_source_kind(path_ref p) noexcept { | std::optional<source_kind> dds::infer_source_kind(path_ref p) noexcept { | ||||
static std::vector<std::string_view> header_exts = { | static std::vector<std::string_view> header_exts = { | ||||
".h", | |||||
".H", | ".H", | ||||
".H++", | ".H++", | ||||
".h", | |||||
".h++", | ".h++", | ||||
".hh", | ".hh", | ||||
".hpp", | ".hpp", | ||||
".hxx", | ".hxx", | ||||
".inl", | ".inl", | ||||
}; | }; | ||||
assert(std::is_sorted(header_exts.begin(), header_exts.end())); | |||||
static std::vector<std::string_view> source_exts = { | static std::vector<std::string_view> source_exts = { | ||||
".C", | ".C", | ||||
".c", | ".c", | ||||
".cpp", | ".cpp", | ||||
".cxx", | ".cxx", | ||||
}; | }; | ||||
assert(std::is_sorted(source_exts.begin(), source_exts.end())); | |||||
auto leaf = p.filename(); | auto leaf = p.filename(); | ||||
auto ext_found | auto ext_found |
library ret; | library ret; | ||||
std::vector<std::string> uses_strs; | |||||
std::vector<std::string> links_strs; | |||||
std::string _type_; | std::string _type_; | ||||
read(fmt::format("Reading library manifest file '{}'", fpath.string()), | read(fmt::format("Reading library manifest file '{}'", fpath.string()), | ||||
pairs, | pairs, | ||||
read_opt("Path", ret.linkable_path), | read_opt("Path", ret.linkable_path), | ||||
read_accumulate("Include-Path", ret.include_paths), | read_accumulate("Include-Path", ret.include_paths), | ||||
read_accumulate("Preprocessor-Define", ret.preproc_defs), | read_accumulate("Preprocessor-Define", ret.preproc_defs), | ||||
read_accumulate("Uses", uses_strs), | |||||
read_accumulate("Links", links_strs), | |||||
read_accumulate("Uses", ret.uses, &split_usage_string), | |||||
read_accumulate("Links", ret.links, &split_usage_string), | |||||
read_accumulate("Special-Uses", ret.special_uses)); | read_accumulate("Special-Uses", ret.special_uses)); | ||||
for (auto&& uses_str : uses_strs) { | |||||
ret.uses.push_back(split_usage_string(uses_str)); | |||||
} | |||||
for (auto&& links_str : links_strs) { | |||||
ret.links.push_back(split_usage_string(links_str)); | |||||
} | |||||
auto make_absolute = [&](path_ref p) { return fpath.parent_path() / p; }; | auto make_absolute = [&](path_ref p) { return fpath.parent_path() / p; }; | ||||
std::transform(ret.include_paths.begin(), | std::transform(ret.include_paths.begin(), | ||||
ret.include_paths.end(), | ret.include_paths.end(), |
for (auto& pair : pairs) { | for (auto& pair : pairs) { | ||||
fstream << pair.key << ": " << pair.value << '\n'; | fstream << pair.key << ": " << pair.value << '\n'; | ||||
} | } | ||||
} | |||||
nested_kvlist nested_kvlist::parse(const std::string_view line_) { | |||||
const auto line = trim_view(line_); | |||||
const auto semi_pos = line.find(';'); | |||||
const auto primary = trim_view(line.substr(0, semi_pos)); | |||||
auto tail = semi_pos == line.npos ? ""sv : trim_view(line.substr(semi_pos + 1)); | |||||
std::vector<pair> pairs; | |||||
while (!tail.empty()) { | |||||
const auto space_pos = tail.find(' '); | |||||
const auto item = tail.substr(0, space_pos); | |||||
const auto eq_pos = item.find('='); | |||||
if (eq_pos == item.npos) { | |||||
pairs.emplace_back(item, ""sv); | |||||
} else { | |||||
const auto key = item.substr(0, eq_pos); | |||||
const auto value = item.substr(eq_pos + 1); | |||||
pairs.emplace_back(key, value); | |||||
} | |||||
if (space_pos == tail.npos) { | |||||
break; | |||||
} | |||||
tail = trim_view(tail.substr(space_pos + 1)); | |||||
} | |||||
return nested_kvlist{std::string(primary), pair_list{std::move(pairs)}}; | |||||
} | } |
write_pairs(fpath, pairs.items()); | write_pairs(fpath, pairs.items()); | ||||
} | } | ||||
struct nested_kvlist { | |||||
std::string primary; | |||||
pair_list pairs; | |||||
static nested_kvlist parse(std::string_view s); | |||||
}; | |||||
struct unchanged { | |||||
template <typename Item> | |||||
auto operator()(Item&& item) const { | |||||
return item; | |||||
} | |||||
}; | |||||
template <typename What> | template <typename What> | ||||
class read_required { | class read_required { | ||||
std::string_view _key; | std::string_view _key; | ||||
} | } | ||||
}; | }; | ||||
template <typename T> | |||||
template <typename T, typename Transform = unchanged> | |||||
class read_opt { | class read_opt { | ||||
std::string_view _key; | std::string_view _key; | ||||
T& _ref; | T& _ref; | ||||
bool _did_read = false; | bool _did_read = false; | ||||
Transform _tr; | |||||
public: | public: | ||||
read_opt(std::string_view key, T& ref) | |||||
read_opt(std::string_view key, T& ref, Transform tr = unchanged()) | |||||
: _key(key) | : _key(key) | ||||
, _ref(ref) {} | |||||
, _ref(ref) | |||||
, _tr(std::move(tr)) {} | |||||
int operator()(std::string_view context, std::string_view key, std::string_view value) { | int operator()(std::string_view context, std::string_view key, std::string_view value) { | ||||
if (key != _key) { | if (key != _key) { | ||||
throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key) | throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key) | ||||
+ "' is not allowed."); | + "' is not allowed."); | ||||
} | } | ||||
_ref = T(value); | |||||
_ref = T(_tr(value)); | |||||
return 1; | return 1; | ||||
} | } | ||||
}; | }; | ||||
} | } | ||||
}; | }; | ||||
struct read_empty_set_true { | |||||
std::string_view _key; | |||||
bool& _bool; | |||||
bool _seen = false; | |||||
bool operator()(std::string_view context, std::string_view key, std::string_view value) { | |||||
if (key != _key) { | |||||
return false; | |||||
} | |||||
if (value != "") { | |||||
throw std::runtime_error(std::string(context) + ": Key '" + std::string(key) | |||||
+ "' does not expected a value (Got '" + std::string(value) | |||||
+ "')."); | |||||
} | |||||
if (_seen) { | |||||
throw std::runtime_error(std::string(context) + ": Duplicated key '" + std::string(key) | |||||
+ "'"); | |||||
} | |||||
_bool = true; | |||||
_seen = true; | |||||
return true; | |||||
} | |||||
}; | |||||
class read_check_eq { | class read_check_eq { | ||||
std::string_view _key; | std::string_view _key; | ||||
std::string_view _expect; | std::string_view _expect; | ||||
} | } | ||||
}; | }; | ||||
template <typename Container> | |||||
template <typename Container, typename Transform = unchanged> | |||||
class read_accumulate { | class read_accumulate { | ||||
std::string_view _key; | std::string_view _key; | ||||
Container& _items; | Container& _items; | ||||
Transform _tr; | |||||
public: | public: | ||||
read_accumulate(std::string_view key, Container& c, Transform tr) | |||||
: _key(key) | |||||
, _items(c) | |||||
, _tr(std::move(tr)) {} | |||||
read_accumulate(std::string_view key, Container& c) | read_accumulate(std::string_view key, Container& c) | ||||
: _key(key) | : _key(key) | ||||
, _items(c) {} | |||||
, _items(c) | |||||
, _tr(unchanged()) {} | |||||
int operator()(std::string_view, std::string_view key, std::string_view value) const { | int operator()(std::string_view, std::string_view key, std::string_view value) const { | ||||
if (key == _key) { | if (key == _key) { | ||||
_items.emplace_back(value); | |||||
_items.emplace_back(_tr(value)); | |||||
return 1; | return 1; | ||||
} | } | ||||
return 0; | return 0; |
CHECK(!iter); | CHECK(!iter); | ||||
} | } | ||||
void test_nested_kvlist() { | |||||
auto check_1 = [](auto str) { | |||||
auto result = nested_kvlist::parse(str); | |||||
CHECK(result.primary == "Foo"); | |||||
CHECK(result.pairs.size() == 1); | |||||
REQUIRE(result.pairs.find("bar")); | |||||
CHECK(result.pairs.find("bar")->value == "baz"); | |||||
}; | |||||
check_1("Foo; bar=baz"); | |||||
check_1("Foo ; bar=baz"); | |||||
check_1("Foo ; bar=baz"); | |||||
check_1("Foo ; bar=baz "); | |||||
check_1("Foo;bar=baz "); | |||||
check_1("Foo;bar=baz"); | |||||
auto check_2 = [](auto str) { | |||||
auto result = nested_kvlist::parse(str); | |||||
CHECK(result.primary == "Foo"); | |||||
CHECK(result.pairs.size() == 0); | |||||
}; | |||||
check_2("Foo"); | |||||
check_2("Foo;"); | |||||
check_2("Foo ;"); | |||||
check_2("Foo ; "); | |||||
check_2("Foo; "); | |||||
auto check_3 = [](auto str) { | |||||
auto result = nested_kvlist::parse(str); | |||||
CHECK(result.primary == "Foo bar"); | |||||
CHECK(result.pairs.size() == 2); | |||||
REQUIRE(result.pairs.find("baz")); | |||||
CHECK(result.pairs.find("baz")->value == "meow"); | |||||
REQUIRE(result.pairs.find("quux")); | |||||
CHECK(result.pairs.find("quux")->value == ""); | |||||
}; | |||||
check_3("Foo bar; baz=meow quux"); | |||||
check_3("Foo bar ; baz=meow quux="); | |||||
check_3("Foo bar ; quux= baz=meow"); | |||||
check_3("Foo bar ;quux= baz=meow"); | |||||
} | |||||
void run_tests() { | void run_tests() { | ||||
test_simple(); | test_simple(); | ||||
test_multi(); | test_multi(); | ||||
test_nested_kvlist(); | |||||
} | } | ||||
DDS_TEST_MAIN; | DDS_TEST_MAIN; |
import sys | |||||
from pathlib import Path | |||||
sys.path.append(str(Path(__file__).absolute().parent.parent / 'tools')) | |||||
from .dds import DDS, DDSFixtureParams, scoped_dds, dds_fixture_conf, dds_fixture_conf_1 |
Name: app_only |
Name: dds-app_only-test | |||||
Version: 0.0.0 |
int main() { return 0; } |
from contextlib import ExitStack | |||||
from tests import DDS | |||||
from tests.fileutil import set_contents | |||||
def test_lib_with_just_app(dds: DDS, scope: ExitStack): | |||||
scope.enter_context( | |||||
set_contents( | |||||
dds.source_root / 'src/foo.main.cpp', | |||||
b'int main() {}', | |||||
)) | |||||
dds.build() | |||||
assert (dds.build_dir / f'foo{dds.exe_suffix}').is_file() |
from contextlib import contextmanager | |||||
from tests import DDS | |||||
from tests.fileutil import ensure_dir, set_contents | |||||
def test_build_empty(dds: DDS): | |||||
assert not dds.source_root.exists() | |||||
dds.scope.enter_context(ensure_dir(dds.source_root)) | |||||
dds.build() | |||||
def test_build_simple(dds: DDS): | |||||
dds.scope.enter_context( | |||||
set_contents(dds.source_root / 'src/f.cpp', b'void foo() {}')) | |||||
dds.build() | |||||
def basic_pkg_dds(dds: DDS): | |||||
return set_contents( | |||||
dds.source_root / 'package.dds', b''' | |||||
Name: test-pkg | |||||
Version: 0.2.2 | |||||
''') | |||||
def test_empty_with_pkg_dds(dds: DDS): | |||||
dds.scope.enter_context(basic_pkg_dds(dds)) | |||||
dds.build() | |||||
def test_empty_with_lib_dds(dds: DDS): | |||||
dds.scope.enter_context(basic_pkg_dds(dds)) | |||||
dds.build() | |||||
def test_empty_sdist_create(dds: DDS): | |||||
dds.scope.enter_context(basic_pkg_dds(dds)) | |||||
dds.sdist_create() | |||||
def test_empty_sdist_export(dds: DDS): | |||||
dds.scope.enter_context(basic_pkg_dds(dds)) | |||||
dds.sdist_export() |
from contextlib import ExitStack | |||||
from tests import DDS | |||||
from tests.fileutil import set_contents | |||||
def test_simple_lib(dds: DDS, scope: ExitStack): | |||||
scope.enter_context( | |||||
dds.set_contents( | |||||
'src/foo.cpp', | |||||
b'int the_answer() { return 42; }', | |||||
)) | |||||
scope.enter_context( | |||||
dds.set_contents( | |||||
'library.dds', | |||||
b'Name: TestLibrary', | |||||
)) | |||||
scope.enter_context( | |||||
dds.set_contents( | |||||
'package.dds', | |||||
b''' | |||||
Name: TestProject | |||||
Version: 0.0.0 | |||||
''', | |||||
)) | |||||
dds.build(tests=True, apps=False, warnings=False, export=True) | |||||
assert (dds.build_dir / 'compile_commands.json').is_file() | |||||
assert list(dds.build_dir.glob('libTestLibrary*')) != [] |
from contextlib import ExitStack | |||||
from tests import DDS | |||||
from tests.fileutil import set_contents | |||||
def test_lib_with_just_test(dds: DDS, scope: ExitStack): | |||||
scope.enter_context( | |||||
set_contents( | |||||
dds.source_root / 'src/foo.test.cpp', | |||||
b'int main() {}', | |||||
)) | |||||
dds.build(tests=True, apps=False, warnings=False, export=False) | |||||
assert (dds.build_dir / f'test/foo{dds.exe_suffix}').is_file() |
from contextlib import ExitStack | |||||
from typing import Optional | |||||
from pathlib import Path | |||||
import shutil | |||||
import pytest | |||||
from tests import scoped_dds, DDSFixtureParams | |||||
@pytest.yield_fixture | |||||
def dds(request, tmp_path: Path, worker_id: str, scope: ExitStack): | |||||
test_source_dir = Path(request.fspath).absolute().parent | |||||
test_root = test_source_dir | |||||
# If we are running in parallel, use a unique directory as scratch | |||||
# space so that we aren't stomping on anyone else | |||||
if worker_id != 'master': | |||||
test_root = tmp_path / request.function.__name__ | |||||
shutil.copytree(test_source_dir, test_root) | |||||
project_dir = test_root / 'project' | |||||
# Check if we have a special configuration | |||||
if hasattr(request, 'param'): | |||||
assert isinstance(request.param, DDSFixtureParams), \ | |||||
('Using the `dds` fixture requires passing in indirect ' | |||||
'params. Use @dds_fixture_conf to configure the fixture') | |||||
params: DDSFixtureParams = request.param | |||||
project_dir = test_root / params.subdir | |||||
# Create the instance. Auto-clean when we're done | |||||
yield scope.enter_context(scoped_dds(test_root, project_dir, request.function.__name__)) | |||||
@pytest.fixture | |||||
def scope(): | |||||
with ExitStack() as scope: | |||||
yield scope |
import os | |||||
import itertools | |||||
from contextlib import contextmanager, ExitStack | |||||
from pathlib import Path | |||||
from typing import Iterable, Union, Any, Dict, NamedTuple, ContextManager | |||||
import subprocess | |||||
import shutil | |||||
import pytest | |||||
from dds_ci import proc | |||||
from . import fileutil | |||||
class DDS: | |||||
def __init__(self, dds_exe: Path, test_dir: Path, project_dir: Path, | |||||
scope: ExitStack) -> None: | |||||
self.dds_exe = dds_exe | |||||
self.test_dir = test_dir | |||||
self.source_root = project_dir | |||||
self.scratch_dir = project_dir / '_test_scratch' | |||||
self.scope = scope | |||||
self.scope.callback(self.cleanup) | |||||
@property | |||||
def repo_dir(self) -> Path: | |||||
return self.scratch_dir / 'repo' | |||||
@property | |||||
def deps_build_dir(self) -> Path: | |||||
return self.scratch_dir / 'deps-build' | |||||
@property | |||||
def build_dir(self) -> Path: | |||||
return self.scratch_dir / 'build' | |||||
@property | |||||
def lmi_path(self) -> Path: | |||||
return self.scratch_dir / 'INDEX.lmi' | |||||
def cleanup(self): | |||||
if self.scratch_dir.exists(): | |||||
shutil.rmtree(self.scratch_dir) | |||||
def run_unchecked(self, cmd: proc.CommandLine, *, | |||||
cwd: Path = None) -> subprocess.CompletedProcess: | |||||
full_cmd = itertools.chain([self.dds_exe], cmd) | |||||
return proc.run(full_cmd, cwd=cwd or self.source_root) | |||||
def run(self, cmd: proc.CommandLine, *, | |||||
cwd: Path = None) -> subprocess.CompletedProcess: | |||||
cmdline = list(proc.flatten_cmd(cmd)) | |||||
res = self.run_unchecked(cmd) | |||||
if res.returncode != 0: | |||||
raise subprocess.CalledProcessError( | |||||
res.returncode, [self.dds_exe] + cmdline, res.stdout) | |||||
return res | |||||
@property | |||||
def repo_dir_arg(self) -> str: | |||||
return f'--repo-dir={self.repo_dir}' | |||||
@property | |||||
def project_dir_arg(self) -> str: | |||||
return f'--project-dir={self.source_root}' | |||||
def deps_ls(self) -> subprocess.CompletedProcess: | |||||
return self.run(['deps', 'ls']) | |||||
def deps_get(self) -> subprocess.CompletedProcess: | |||||
return self.run([ | |||||
'deps', | |||||
'get', | |||||
self.repo_dir_arg, | |||||
]) | |||||
def deps_build(self, *, | |||||
toolchain: str = None) -> subprocess.CompletedProcess: | |||||
return self.run([ | |||||
'deps', | |||||
'build', | |||||
f'--toolchain={toolchain or self.default_builtin_toolchain}', | |||||
self.repo_dir_arg, | |||||
f'--deps-build-dir={self.deps_build_dir}', | |||||
f'--lmi-path={self.lmi_path}', | |||||
]) | |||||
def build(self, | |||||
*, | |||||
toolchain: str = None, | |||||
apps: bool = True, | |||||
warnings: bool = True, | |||||
tests: bool = True, | |||||
export: bool = False) -> subprocess.CompletedProcess: | |||||
return self.run([ | |||||
'build', | |||||
f'--out={self.build_dir}', | |||||
['--tests'] if tests else [], | |||||
['--apps'] if apps else [], | |||||
['--warnings'] if warnings else [], | |||||
['--export'] if export else [], | |||||
f'--toolchain={toolchain or self.default_builtin_toolchain}', | |||||
f'--lm-index={self.lmi_path}', | |||||
self.project_dir_arg, | |||||
]) | |||||
def sdist_create(self) -> subprocess.CompletedProcess: | |||||
return self.run([ | |||||
'sdist', | |||||
'create', | |||||
self.project_dir_arg, | |||||
f'--out={self.build_dir / "created-sdist.sds"}', | |||||
]) | |||||
def sdist_export(self) -> subprocess.CompletedProcess: | |||||
return self.run([ | |||||
'sdist', | |||||
'export', | |||||
self.project_dir_arg, | |||||
self.repo_dir_arg, | |||||
]) | |||||
@property | |||||
def default_builtin_toolchain(self) -> str: | |||||
if os.name == 'posix': | |||||
return ':gcc-8' | |||||
elif os.name == 'nt': | |||||
return ':msvc' | |||||
else: | |||||
raise RuntimeError( | |||||
f'No default builtin toolchain defined for tests on platform "{os.name}"' | |||||
) | |||||
@property | |||||
def exe_suffix(self) -> str: | |||||
if os.name == 'posix': | |||||
return '' | |||||
elif os.name == 'nt': | |||||
return '.exe' | |||||
else: | |||||
raise RuntimeError( | |||||
f'We don\'t know the executable suffix for the platform "{os.name}"' | |||||
) | |||||
def set_contents(self, path: Union[str, Path], | |||||
content: bytes) -> ContextManager[Path]: | |||||
return fileutil.set_contents(self.source_root / path, content) | |||||
@contextmanager | |||||
def scoped_dds(test_dir: Path, project_dir: Path, name: str): | |||||
dds_exe = Path(__file__).absolute().parent.parent / '_build/dds' | |||||
if os.name == 'nt': | |||||
dds_exe = dds_exe.with_suffix('.exe') | |||||
with ExitStack() as scope: | |||||
yield DDS(dds_exe, test_dir, project_dir, scope) | |||||
class DDSFixtureParams(NamedTuple): | |||||
ident: str | |||||
subdir: Union[Path, str] | |||||
def dds_fixture_conf(*argsets: DDSFixtureParams): | |||||
args = list(argsets) | |||||
return pytest.mark.parametrize( | |||||
'dds', args, indirect=True, ids=[p.ident for p in args]) | |||||
def dds_fixture_conf_1(subdir: Union[Path, str]): | |||||
params = DDSFixtureParams(ident='only', subdir=subdir) | |||||
return pytest.mark.parametrize('dds', [params], indirect=True, ids=['.']) |
import pytest | |||||
import subprocess | |||||
from tests import DDS, DDSFixtureParams, dds_fixture_conf, dds_fixture_conf_1 | |||||
dds_conf = dds_fixture_conf( | |||||
DDSFixtureParams(ident='git-remote', subdir='git-remote'), | |||||
DDSFixtureParams(ident='no-deps', subdir='no-deps'), | |||||
) | |||||
@dds_conf | |||||
def test_ls(dds: DDS): | |||||
dds.run(['deps', 'ls']) | |||||
@dds_conf | |||||
def test_deps_build(dds: DDS): | |||||
assert not dds.repo_dir.exists() | |||||
dds.deps_get() | |||||
assert dds.repo_dir.exists(), '`deps get` did not generate a repo directory' | |||||
assert not dds.lmi_path.exists() | |||||
dds.deps_build() | |||||
assert dds.lmi_path.exists(), '`deps build` did not generate the build dir' | |||||
@dds_fixture_conf_1('use-remote') | |||||
def test_use_nlohmann_json_remote(dds: DDS): | |||||
dds.deps_get() | |||||
dds.deps_build() | |||||
dds.build(apps=True) | |||||
app_exe = dds.build_dir / f'app{dds.exe_suffix}' | |||||
assert app_exe.is_file() | |||||
subprocess.check_call([str(app_exe)]) |
Name: deps-test | |||||
Version: 0.0.0 | |||||
Depends: neo-buffer 0.1.0 | |||||
Depends: range-v3 0.9.1 |
Remote-Package: neo-buffer 0.1.0; git url=https://github.com/vector-of-bool/neo-buffer.git ref=develop | |||||
Remote-Package: range-v3 0.9.1; git url=https://github.com/ericniebler/range-v3.git ref=0.9.1 auto=Niebler/range-v3 |
Name: deps-test | |||||
Version: 0.0.0 |
Name: dummy | |||||
Uses: nlohmann/json |
Name: json-test | |||||
Version: 0.0.0 | |||||
Depends: nlohmann-json 3.7.1 |
Remote-Package: nlohmann-json 3.7.1; git url=https://github.com/vector-of-bool/json.git ref=dds/3.7.1 |
#include <nlohmann/json.hpp> | |||||
int main() { | |||||
nlohmann::json j = { | |||||
{"foo", "bar"}, | |||||
}; | |||||
return j.size() == 1 ? 0 : 12; | |||||
} |
Compiler-ID: GNU | |||||
C++-Version: C++17 | |||||
C++-Compiler: g++-8 | |||||
Flags: -D SPDLOG_COMPILED_LIB |
Compiler-ID: MSVC | |||||
Flags: -D SPDLOG_COMPILED_LIB |
Name: spdlog-user | |||||
Uses: spdlog/spdlog |
Name: test | |||||
Version: 0.0.0 | |||||
Depends: spdlog 1.4.2 |
Remote-Package: spdlog 1.4.2; git url=https://github.com/gabime/spdlog.git ref=v1.4.2 auto=spdlog/spdlog |
#include <spdlog/spdlog.h> | |||||
int write_message() { | |||||
spdlog::warn("This is a message generated by spdlog in the spdlog-user test library"); | |||||
return 42; | |||||
} |
#pragma once | |||||
extern int write_message(); |
#include "./spdlog_user.hpp" | |||||
#include <spdlog/spdlog.h> | |||||
int main() { | |||||
auto result = ::write_message(); | |||||
if (result != 42) { | |||||
spdlog::critical( | |||||
"The test library returned the wrong value (This is a REAL dds test failure, and is " | |||||
"very unexpected)"); | |||||
return 1; | |||||
} | |||||
return 0; | |||||
} |
from tests import DDS | |||||
from dds_ci import proc | |||||
def test_get_build_use_spdlog(dds: DDS): | |||||
dds.deps_get() | |||||
tc_fname = 'gcc.tc.dds' if 'gcc' in dds.default_builtin_toolchain else 'msvc.tc.dds' | |||||
tc = str(dds.test_dir / tc_fname) | |||||
dds.deps_build(toolchain=tc) | |||||
dds.build(toolchain=tc, apps=True) | |||||
proc.check_run((dds.build_dir / 'use-spdlog').with_suffix(dds.exe_suffix)) |
from tests import DDS | |||||
from tests.fileutil import ensure_dir | |||||
def test_empty_dir(dds: DDS): | |||||
with ensure_dir(dds.source_root): | |||||
dds.build() |
from contextlib import contextmanager, ExitStack | |||||
from pathlib import Path | |||||
from typing import Iterator, Union, Optional | |||||
import shutil | |||||
@contextmanager | |||||
def ensure_dir(dirpath: Path) -> Iterator[Path]: | |||||
""" | |||||
Ensure that the given directory (and any parents) exist. When the context | |||||
exists, removes any directories that were created. | |||||
""" | |||||
dirpath = dirpath.absolute() | |||||
if dirpath.exists(): | |||||
assert dirpath.is_dir(), f'Directory {dirpath} is a non-directory file' | |||||
yield dirpath | |||||
return | |||||
# Create the directory and clean it up when we are done | |||||
with ensure_dir(dirpath.parent): | |||||
dirpath.mkdir() | |||||
try: | |||||
yield dirpath | |||||
finally: | |||||
shutil.rmtree(dirpath) | |||||
@contextmanager | |||||
def auto_delete(fpath: Path) -> Iterator[Path]: | |||||
try: | |||||
yield fpath | |||||
finally: | |||||
if fpath.exists(): | |||||
fpath.unlink() | |||||
@contextmanager | |||||
def set_contents(fpath: Path, content: bytes) -> Iterator[Path]: | |||||
prev_content: Optional[bytes] = None | |||||
if fpath.exists(): | |||||
assert fpath.is_file(), 'File {fpath} exists and is not a regular file' | |||||
prev_content = fpath.read_bytes() | |||||
with ensure_dir(fpath.parent): | |||||
fpath.write_bytes(content) | |||||
try: | |||||
yield fpath | |||||
finally: | |||||
if prev_content is None: | |||||
fpath.unlink() | |||||
else: | |||||
fpath.write_bytes(prev_content) |
Name: foo |
Name: foo | |||||
Version: 1.2.3 |
from tests.dds import DDS, dds_fixture_conf_1 | |||||
@dds_fixture_conf_1('create') | |||||
def test_create_sdist(dds: DDS): | |||||
dds.sdist_create() | |||||
sd_dir = dds.build_dir / 'created-sdist.sds' | |||||
assert sd_dir.is_dir() | |||||
foo_cpp = sd_dir / 'src/foo.cpp' | |||||
assert foo_cpp.is_file() | |||||
header_hpp = sd_dir / 'include/header.hpp' | |||||
assert header_hpp.is_file() | |||||
header_h = sd_dir / 'include/header.h' | |||||
assert header_h.is_file() |
Name: simple |
Name: dds-simple-test | |||||
Version: 0.0.0 |
int foo() { return 42; } |
Name: test_only |
Name: dds-test_only-test | |||||
Version: 0.0.0 |
int main() { return 0; } |
import argparse | import argparse | ||||
import os | import os | ||||
import sys | import sys | ||||
import pytest | |||||
from pathlib import Path | from pathlib import Path | ||||
from typing import Sequence, NamedTuple | from typing import Sequence, NamedTuple | ||||
import subprocess | import subprocess | ||||
import urllib.request | import urllib.request | ||||
import shutil | |||||
HERE = Path(__file__).parent.absolute() | |||||
TOOLS_DIR = HERE | |||||
PROJECT_ROOT = HERE.parent | |||||
PREBUILT_DDS = PROJECT_ROOT / '_prebuilt/dds' | |||||
from self_build import self_build | |||||
from self_deps_get import self_deps_get | |||||
from self_deps_build import self_deps_build | |||||
from dds_ci import paths, proc | |||||
class CIOptions(NamedTuple): | class CIOptions(NamedTuple): | ||||
cxx: Path | cxx: Path | ||||
toolchain: str | toolchain: str | ||||
toolchain_2: str | |||||
def _do_bootstrap_build(opts: CIOptions) -> None: | def _do_bootstrap_build(opts: CIOptions) -> None: | ||||
subprocess.check_call([ | subprocess.check_call([ | ||||
sys.executable, | sys.executable, | ||||
'-u', | '-u', | ||||
str(TOOLS_DIR / 'bootstrap.py'), | |||||
str(paths.TOOLS_DIR / 'bootstrap.py'), | |||||
f'--cxx={opts.cxx}', | f'--cxx={opts.cxx}', | ||||
]) | ]) | ||||
'darwin': 'dds-macos-x64', | 'darwin': 'dds-macos-x64', | ||||
}.get(sys.platform) | }.get(sys.platform) | ||||
if filename is None: | if filename is None: | ||||
raise RuntimeError(f'We do not have a prebuilt DDS binary for the "{sys.platform}" platform') | |||||
raise RuntimeError(f'We do not have a prebuilt DDS binary for ' | |||||
f'the "{sys.platform}" platform') | |||||
url = f'https://github.com/vector-of-bool/dds/releases/download/bootstrap-p2/{filename}' | url = f'https://github.com/vector-of-bool/dds/releases/download/bootstrap-p2/{filename}' | ||||
print(f'Downloading prebuilt DDS executable: {url}') | print(f'Downloading prebuilt DDS executable: {url}') | ||||
stream = urllib.request.urlopen(url) | stream = urllib.request.urlopen(url) | ||||
PREBUILT_DDS.parent.mkdir(exist_ok=True, parents=True) | |||||
with PREBUILT_DDS.open('wb') as fd: | |||||
paths.PREBUILT_DDS.parent.mkdir(exist_ok=True, parents=True) | |||||
with paths.PREBUILT_DDS.open('wb') as fd: | |||||
while True: | while True: | ||||
buf = stream.read(1024 * 4) | buf = stream.read(1024 * 4) | ||||
if not buf: | if not buf: | ||||
if os.name != 'nt': | if os.name != 'nt': | ||||
# Mark the binary executable. By default it won't be | # Mark the binary executable. By default it won't be | ||||
mode = PREBUILT_DDS.stat().st_mode | |||||
mode = paths.PREBUILT_DDS.stat().st_mode | |||||
mode |= 0b001_001_001 | mode |= 0b001_001_001 | ||||
PREBUILT_DDS.chmod(mode) | |||||
paths.PREBUILT_DDS.chmod(mode) | |||||
def main(argv: Sequence[str]) -> int: | def main(argv: Sequence[str]) -> int: | ||||
parser.add_argument( | parser.add_argument( | ||||
'-B', | '-B', | ||||
'--bootstrap-with', | '--bootstrap-with', | ||||
help= | |||||
'Skip the prebuild-bootstrap step. This requires a _prebuilt/dds to exist!', | |||||
choices=('download', 'build'), | |||||
help='How are we to obtain a bootstrapped DDS executable?', | |||||
choices=('download', 'build', 'skip'), | |||||
required=True, | required=True, | ||||
) | ) | ||||
parser.add_argument( | parser.add_argument( | ||||
'-T', | '-T', | ||||
help='The toolchain to use for the CI process', | help='The toolchain to use for the CI process', | ||||
required=True) | required=True) | ||||
parser.add_argument( | |||||
'--toolchain-2', | |||||
'-T2', | |||||
help='Toolchain for the second-phase self-test', | |||||
required=True) | |||||
args = parser.parse_args(argv) | args = parser.parse_args(argv) | ||||
opts = CIOptions(cxx=Path(args.cxx), toolchain=args.toolchain) | |||||
opts = CIOptions( | |||||
cxx=Path(args.cxx), | |||||
toolchain=args.toolchain, | |||||
toolchain_2=args.toolchain_2) | |||||
if args.bootstrap_with == 'build': | if args.bootstrap_with == 'build': | ||||
_do_bootstrap_build(opts) | _do_bootstrap_build(opts) | ||||
elif args.bootstrap_with == 'download': | elif args.bootstrap_with == 'download': | ||||
_do_bootstrap_download() | _do_bootstrap_download() | ||||
elif args.bootstrap_with == 'skip': | |||||
pass | |||||
else: | else: | ||||
assert False, 'impossible' | assert False, 'impossible' | ||||
subprocess.check_call([ | |||||
str(PREBUILT_DDS), | |||||
'deps', | |||||
'build', | |||||
f'-T{opts.toolchain}', | |||||
f'--repo-dir={PROJECT_ROOT / "external/repo"}', | |||||
]) | |||||
subprocess.check_call([ | |||||
str(PREBUILT_DDS), | |||||
proc.check_run( | |||||
paths.PREBUILT_DDS, | |||||
'build', | 'build', | ||||
'--full', | '--full', | ||||
f'-T{opts.toolchain}', | |||||
]) | |||||
('-T', opts.toolchain), | |||||
) | |||||
exe_suffix = '.exe' if os.name == 'nt' else '' | |||||
subprocess.check_call([ | |||||
sys.executable, | |||||
'-u', | |||||
str(TOOLS_DIR / 'test.py'), | |||||
f'--exe={PROJECT_ROOT / f"_build/dds{exe_suffix}"}', | |||||
f'-T{opts.toolchain}', | |||||
self_build(paths.CUR_BUILT_DDS, toolchain=opts.toolchain) | |||||
print('Bootstrap test PASSED!') | |||||
if paths.SELF_TEST_REPO_DIR.exists(): | |||||
shutil.rmtree(paths.SELF_TEST_REPO_DIR) | |||||
self_deps_get(paths.CUR_BUILT_DDS, paths.SELF_TEST_REPO_DIR) | |||||
self_deps_build(paths.CUR_BUILT_DDS, opts.toolchain_2, | |||||
paths.SELF_TEST_REPO_DIR, | |||||
paths.PROJECT_ROOT / 'remote.dds') | |||||
self_build( | |||||
paths.CUR_BUILT_DDS, | |||||
toolchain=opts.toolchain, | |||||
lmi_path=paths.BUILD_DIR / 'INDEX.lmi') | |||||
return pytest.main([ | |||||
'-v', | |||||
'--durations=10', | |||||
f'--basetemp={paths.BUILD_DIR / "_tmp"}', | |||||
'-n4', | |||||
]) | ]) | ||||
return 0 | |||||
if __name__ == "__main__": | if __name__ == "__main__": | ||||
sys.exit(main(sys.argv[1:])) | sys.exit(main(sys.argv[1:])) |
from argparse import ArgumentParser | |||||
from dds_ci import paths | |||||
def add_tc_arg(parser: ArgumentParser, *, required=True) -> None: | |||||
parser.add_argument( | |||||
'--toolchain', | |||||
'-T', | |||||
help='The DDS toolchain to use', | |||||
required=required) | |||||
def add_dds_exe_arg(parser: ArgumentParser, *, required=True) -> None: | |||||
parser.add_argument( | |||||
'--exe', | |||||
'-e', | |||||
help='Path to a DDS executable to use', | |||||
required=required) |
import os | |||||
from pathlib import Path | |||||
TOOLS_DIR = Path(__file__).absolute().parent.parent | |||||
PROJECT_ROOT = TOOLS_DIR.parent | |||||
BUILD_DIR = PROJECT_ROOT / '_build' | |||||
PREBUILT_DIR = PROJECT_ROOT / '_prebuilt' | |||||
EXE_SUFFIX = '.exe' if os.name == 'nt' else '' | |||||
PREBUILT_DDS = (PREBUILT_DIR / 'dds').with_suffix(EXE_SUFFIX) | |||||
CUR_BUILT_DDS = (BUILD_DIR / 'dds').with_suffix(EXE_SUFFIX) | |||||
EMBEDDED_REPO_DIR = PROJECT_ROOT / 'external/repo' | |||||
SELF_TEST_REPO_DIR = BUILD_DIR / '_self-repo' |
from pathlib import PurePath, Path | |||||
from typing import Iterable, Union | |||||
import subprocess | |||||
CommandLineArg = Union[str, PurePath, int, float] | |||||
CommandLineArg1 = Union[CommandLineArg, Iterable[CommandLineArg]] | |||||
CommandLineArg2 = Union[CommandLineArg1, Iterable[CommandLineArg1]] | |||||
CommandLineArg3 = Union[CommandLineArg2, Iterable[CommandLineArg2]] | |||||
CommandLineArg4 = Union[CommandLineArg3, Iterable[CommandLineArg3]] | |||||
CommandLine = Union[CommandLineArg4, Iterable[CommandLineArg4]] | |||||
def flatten_cmd(cmd: CommandLine) -> Iterable[str]: | |||||
if isinstance(cmd, (str, PurePath)): | |||||
yield str(cmd) | |||||
elif isinstance(cmd, (int, float)): | |||||
yield str(cmd) | |||||
elif hasattr(cmd, '__iter__'): | |||||
each = (flatten_cmd(arg) for arg in cmd) # type: ignore | |||||
for item in each: | |||||
yield from item | |||||
else: | |||||
assert False, f'Invalid command line element: {repr(cmd)}' | |||||
def run(*cmd: CommandLine, cwd: Path = None) -> subprocess.CompletedProcess: | |||||
return subprocess.run( | |||||
list(flatten_cmd(cmd)), # type: ignore | |||||
cwd=cwd, | |||||
) | |||||
def check_run(*cmd: CommandLine, | |||||
cwd: Path = None) -> subprocess.CompletedProcess: | |||||
flat_cmd = list(flatten_cmd(cmd)) # type: ignore | |||||
res = run(flat_cmd, cwd=cwd) | |||||
if res.returncode != 0: | |||||
raise subprocess.CalledProcessError(res.returncode, flat_cmd) | |||||
return res |
Compiler-ID: GNU | |||||
C++-Version: C++17 | |||||
C++-Compiler: g++-8 | |||||
Flags: -fconcepts -Werror=return-type | |||||
Flags: -D SPDLOG_COMPILED_LIB | |||||
Optimize: True |
Compiler-ID: MSVC | |||||
Flags: /experimental:preprocessor /D SPDLOG_COMPILED_LIB /wd5105 /std:c++latest | |||||
Link-Flags: rpcrt4.lib | |||||
Optimize: True |
#!/usr/bin/env python3 | |||||
import argparse | |||||
from pathlib import Path | |||||
from typing import List, NamedTuple | |||||
import shutil | |||||
import subprocess | |||||
import sys | |||||
from dds_ci import cli, proc | |||||
ROOT = Path(__file__).parent.parent.absolute() | |||||
def self_build(exe: Path, *, toolchain: str, lmi_path: Path = None): | |||||
# Copy the exe to another location, as windows refuses to let a binary be | |||||
# replaced while it is executing | |||||
new_exe = ROOT / '_dds.bootstrap-test.exe' | |||||
shutil.copy2(exe, new_exe) | |||||
try: | |||||
proc.check_run( | |||||
new_exe, | |||||
'build', | |||||
'--full', | |||||
('--toolchain', toolchain), | |||||
('-I', lmi_path) if lmi_path else (), | |||||
) | |||||
finally: | |||||
new_exe.unlink() | |||||
def main(argv: List[str]) -> int: | |||||
parser = argparse.ArgumentParser() | |||||
cli.add_tc_arg(parser) | |||||
cli.add_dds_exe_arg(parser) | |||||
args = parser.parse_args(argv) | |||||
self_build(Path(args.exe), args.toolchain) | |||||
return 0 | |||||
if __name__ == "__main__": | |||||
sys.exit(main(sys.argv[1:])) |
import argparse | |||||
from pathlib import Path | |||||
from dds_ci import cli, proc, paths | |||||
def self_deps_build(exe: Path, toolchain: str, repo_dir: Path, | |||||
remote_list: Path) -> None: | |||||
proc.check_run( | |||||
exe, | |||||
'deps', | |||||
'build', | |||||
('--repo-dir', repo_dir), | |||||
('-T', toolchain), | |||||
) | |||||
def main(): | |||||
parser = argparse.ArgumentParser() | |||||
cli.add_dds_exe_arg(parser) | |||||
cli.add_tc_arg(parser) | |||||
parser.add_argument('--repo-dir', default=paths.SELF_TEST_REPO_DIR) | |||||
args = parser.parse_args() | |||||
self_deps_build( | |||||
Path(args.exe), args.toolchain, args.repo_dir, | |||||
paths.PROJECT_ROOT / 'remote.dds') | |||||
if __name__ == "__main__": | |||||
main() |
from pathlib import Path | |||||
from dds_ci import proc, paths | |||||
PROJECT_ROOT = Path(__file__).absolute().parent.parent | |||||
def self_deps_get(dds_exe: Path, repo_dir: Path) -> None: | |||||
proc.check_run( | |||||
dds_exe, | |||||
'deps', | |||||
'get', | |||||
('--repo-dir', repo_dir), | |||||
('--remote-list', PROJECT_ROOT / 'remote.dds'), | |||||
) | |||||
if __name__ == "__main__": | |||||
self_deps_get(paths.CUR_BUILT_DDS, paths.SELF_TEST_REPO_DIR) |
#!/usr/bin/env python3 | |||||
import argparse | |||||
from pathlib import Path | |||||
from typing import List, NamedTuple | |||||
import shutil | |||||
import subprocess | |||||
import sys | |||||
ROOT = Path(__file__).parent.parent.absolute() | |||||
class TestOptions(NamedTuple): | |||||
exe: Path | |||||
toolchain: str | |||||
def run_test_dir(dir: Path, opts: TestOptions) -> bool: | |||||
fails = 0 | |||||
fails += _run_subproc_test( | |||||
dir, | |||||
opts, | |||||
'Full Build', | |||||
'build', | |||||
'--full', | |||||
f'--toolchain={opts.toolchain}', | |||||
) | |||||
fails += _run_subproc_test( | |||||
dir, | |||||
opts, | |||||
'Source Distribution', | |||||
'sdist', | |||||
'create', | |||||
f'--out=_build/{dir.stem}/test.dsd', | |||||
'--replace', | |||||
) | |||||
return fails == 0 | |||||
def _run_subproc_test(dir: Path, opts: TestOptions, name: str, | |||||
*args: str) -> int: | |||||
print(f'Running test: {dir.stem} - {name} ', end='') | |||||
out_dir = dir / '_build' | |||||
if out_dir.exists(): | |||||
shutil.rmtree(out_dir) | |||||
res = subprocess.run( | |||||
[ | |||||
str(opts.exe), | |||||
] + list(str(s) for s in args), | |||||
cwd=dir, | |||||
stdout=subprocess.PIPE, | |||||
stderr=subprocess.STDOUT, | |||||
) | |||||
if res.returncode != 0: | |||||
print('- FAILED') | |||||
print(f'Test failed with exit code ' | |||||
f'[{res.returncode}]:\n{res.stdout.decode()}') | |||||
return 1 | |||||
print('- PASSED') | |||||
return 0 | |||||
def _run_build_test(dir: Path, opts: TestOptions) -> int: | |||||
print(f'Running test: {dir.stem} - build', end='') | |||||
out_dir = dir / '_build' | |||||
if out_dir.exists(): | |||||
shutil.rmtree(out_dir) | |||||
res = subprocess.run( | |||||
[ | |||||
str(opts.exe), | |||||
'build', | |||||
'--export', | |||||
'--warnings', | |||||
'--tests', | |||||
'--full', | |||||
f'--toolchain={opts.toolchain}', | |||||
f'--out={out_dir}', | |||||
f'--export-name={dir.stem}', | |||||
], | |||||
cwd=dir, | |||||
stdout=subprocess.PIPE, | |||||
stderr=subprocess.STDOUT, | |||||
) | |||||
if res.returncode != 0: | |||||
print('- FAILED') | |||||
print(f'Test failed with exit code ' | |||||
f'[{res.returncode}]:\n{res.stdout.decode()}') | |||||
return 1 | |||||
print('- PASSED') | |||||
return 0 | |||||
def run_tests(opts: TestOptions) -> int: | |||||
print('Sanity check...') | |||||
subprocess.check_output([str(opts.exe), '--help']) | |||||
tests_subdir = ROOT / 'tests' | |||||
test_dirs = tests_subdir.glob('*.test') | |||||
ret = 0 | |||||
for td in test_dirs: | |||||
if not run_test_dir(td, opts): | |||||
ret = 1 | |||||
return ret | |||||
def bootstrap_self(opts: TestOptions): | |||||
# Copy the exe to another location, as windows refuses to let a binary be | |||||
# replaced while it is executing | |||||
new_exe = ROOT / '_dds.bootstrap-test.exe' | |||||
shutil.copy2(opts.exe, new_exe) | |||||
res = subprocess.run([ | |||||
str(new_exe), | |||||
'build', | |||||
f'-FT{opts.toolchain}', | |||||
]) | |||||
new_exe.unlink() | |||||
if res.returncode != 0: | |||||
print('The bootstrap test failed!', file=sys.stderr) | |||||
return False | |||||
print('Bootstrap test PASSED!') | |||||
return True | |||||
def main(argv: List[str]) -> int: | |||||
parser = argparse.ArgumentParser() | |||||
parser.add_argument( | |||||
'--exe', | |||||
'-e', | |||||
help='Path to the dds executable to test', | |||||
required=True) | |||||
parser.add_argument( | |||||
'--toolchain', | |||||
'-T', | |||||
help='The dds toolchain to use while testing', | |||||
required=True, | |||||
) | |||||
parser.add_argument( | |||||
'--skip-bootstrap-test', | |||||
action='store_true', | |||||
help='Skip the self-bootstrap test', | |||||
) | |||||
args = parser.parse_args(argv) | |||||
tc = args.toolchain | |||||
if not tc.startswith(':'): | |||||
tc = Path(tc).absolute() | |||||
opts = TestOptions(exe=Path(args.exe).absolute(), toolchain=tc) | |||||
if not args.skip_bootstrap_test and not bootstrap_self(opts): | |||||
return 2 | |||||
return run_tests(opts) | |||||
if __name__ == "__main__": | |||||
sys.exit(main(sys.argv[1:])) |