Parcourir la source

Merge branch 'feature/get-deps' into develop

default_compile_flags
vector-of-bool il y a 5 ans
Parent
révision
ac0da1f0c4
83 fichiers modifiés avec 1569 ajouts et 494 suppressions
  1. +2
    -1
      .gitignore
  2. +0
    -1
      INDEX.lmi
  3. +14
    -5
      azure-pipelines.yml
  4. +0
    -5
      external/args.lml
  5. +265
    -121
      external/repo/nlohmann-json/include/nlohmann/json.hpp
  6. +1
    -1
      external/repo/nlohmann-json/package.dds
  7. +0
    -1
      external/repo/taywee-args/library.dds
  8. +0
    -3
      external/repo/taywee-args/package.dds
  9. +1
    -1
      external/repo/wil/package.dds
  10. +0
    -6
      external/taywee-args.lmp
  11. +1
    -1
      external/wil.lml
  12. +1
    -2
      library.dds
  13. +2
    -4
      package.dds
  14. +6
    -6
      peru.yaml
  15. +11
    -0
      remote.dds
  16. +0
    -0
      src/dds/3rd/args.hxx
  17. +4
    -4
      src/dds/build.cpp
  18. +63
    -10
      src/dds/dds.main.cpp
  19. +5
    -33
      src/dds/deps.cpp
  20. +4
    -7
      src/dds/deps.hpp
  21. +154
    -0
      src/dds/repo/remote.cpp
  22. +75
    -0
      src/dds/repo/remote.hpp
  23. +51
    -45
      src/dds/repo/repo.cpp
  24. +36
    -14
      src/dds/repo/repo.hpp
  25. +18
    -0
      src/dds/sdist.hpp
  26. +4
    -1
      src/dds/source.cpp
  27. +2
    -13
      src/libman/library.cpp
  28. +29
    -0
      src/libman/parse.cpp
  29. +54
    -7
      src/libman/parse.hpp
  30. +43
    -0
      src/libman/parse.test.cpp
  31. +5
    -0
      tests/__init__.py
  32. +0
    -1
      tests/app_only.test/library.dds
  33. +0
    -2
      tests/app_only.test/package.dds
  34. +0
    -1
      tests/app_only.test/src/something.main.cpp
  35. +14
    -0
      tests/basics/test_app_only.py
  36. +43
    -0
      tests/basics/test_basics.py
  37. +30
    -0
      tests/basics/test_simple.py
  38. +14
    -0
      tests/basics/test_test_only.py
  39. +38
    -0
      tests/conftest.py
  40. +173
    -0
      tests/dds.py
  41. +36
    -0
      tests/deps/do_test.py
  42. +5
    -0
      tests/deps/git-remote/package.dds
  43. +2
    -0
      tests/deps/git-remote/remote.dds
  44. +2
    -0
      tests/deps/no-deps/package.dds
  45. +0
    -0
      tests/deps/no-deps/remote.dds
  46. +3
    -0
      tests/deps/use-remote/library.dds
  47. +4
    -0
      tests/deps/use-remote/package.dds
  48. +1
    -0
      tests/deps/use-remote/remote.dds
  49. +8
    -0
      tests/deps/use-remote/src/app.main.cpp
  50. +4
    -0
      tests/deps/use-spdlog/gcc.tc.dds
  51. +2
    -0
      tests/deps/use-spdlog/msvc.tc.dds
  52. +3
    -0
      tests/deps/use-spdlog/project/library.dds
  53. +4
    -0
      tests/deps/use-spdlog/project/package.dds
  54. +1
    -0
      tests/deps/use-spdlog/project/remote.dds
  55. +6
    -0
      tests/deps/use-spdlog/project/src/spdlog_user.cpp
  56. +3
    -0
      tests/deps/use-spdlog/project/src/spdlog_user.hpp
  57. +14
    -0
      tests/deps/use-spdlog/project/src/use-spdlog.main.cpp
  58. +12
    -0
      tests/deps/use-spdlog/use_spdlog_test.py
  59. +7
    -0
      tests/errors/errors_test.py
  60. +52
    -0
      tests/fileutil.py
  61. +0
    -0
      tests/sdist/create/include/header.h
  62. +0
    -0
      tests/sdist/create/include/header.hpp
  63. +1
    -0
      tests/sdist/create/library.dds
  64. +2
    -0
      tests/sdist/create/package.dds
  65. +0
    -0
      tests/sdist/create/src/foo.cpp
  66. +13
    -0
      tests/sdist/sdist_test.py
  67. +0
    -1
      tests/simple.test/library.dds
  68. +0
    -2
      tests/simple.test/package.dds
  69. +0
    -1
      tests/simple.test/src/foo.cpp
  70. +0
    -1
      tests/test_only.test/library.dds
  71. +0
    -2
      tests/test_only.test/package.dds
  72. +0
    -1
      tests/test_only.test/src/foo.test.cpp
  73. +51
    -35
      tools/ci.py
  74. +0
    -0
      tools/dds_ci/__init__.py
  75. +19
    -0
      tools/dds_ci/cli.py
  76. +12
    -0
      tools/dds_ci/paths.py
  77. +39
    -0
      tools/dds_ci/proc.py
  78. +6
    -0
      tools/gcc-8.p2.dds
  79. +4
    -0
      tools/msvc.p2.dds
  80. +41
    -0
      tools/self_build.py
  81. +30
    -0
      tools/self_deps_build.py
  82. +19
    -0
      tools/self_deps_get.py
  83. +0
    -155
      tools/test.py

+ 2
- 1
.gitignore Voir le fichier

.mypy_cache/ .mypy_cache/
*.dsd/ *.dsd/
_prebuilt/ _prebuilt/
.dds-repo-lock
.dds-repo-lock
.pytest_cache

+ 0
- 1
INDEX.lmi Voir le fichier

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

+ 14
- 5
azure-pipelines.yml Voir le fichier

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

+ 0
- 5
external/args.lml Voir le fichier

Type: Library

Name: args

Include-Path: repo/taywee-args/include

+ 265
- 121
external/repo/nlohmann-json/include/nlohmann/json.hpp Voir le fichier

/* /*
__ _____ _____ _____ __ _____ _____ _____
__| | __| | | | 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

+ 1
- 1
external/repo/nlohmann-json/package.dds Voir le fichier

Name: nlohmann-json Name: nlohmann-json
Namespace: nlohmann Namespace: nlohmann
Version: 3.7.0
Version: 3.7.1

+ 0
- 1
external/repo/taywee-args/library.dds Voir le fichier

Name: args

+ 0
- 3
external/repo/taywee-args/package.dds Voir le fichier

Name: taywee-args
Version: 0.0.0
Namespace: taywee

+ 1
- 1
external/repo/wil/package.dds Voir le fichier

Name: ms-wil Name: ms-wil
Version: 0.0.0
Version: 2019.11.10
Namespace: Microsoft Namespace: Microsoft

+ 0
- 6
external/taywee-args.lmp Voir le fichier

Type: Package

Name: taywee-args
Namespace: taywee

Library: args.lml

+ 1
- 1
external/wil.lml Voir le fichier

Type: Library Type: Library


Name: WIL
Name: wil


Include-Path: repo/wil/include Include-Path: repo/wil/include

+ 1
- 2
library.dds Voir le fichier

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

+ 2
- 4
package.dds Voir le fichier

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

+ 6
- 6
peru.yaml Voir le fichier

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

+ 11
- 0
remote.dds Voir le fichier

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

external/repo/taywee-args/include/args.hxx → src/dds/3rd/args.hxx Voir le fichier


+ 4
- 4
src/dds/build.cpp Voir le fichier

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);



+ 63
- 10
src/dds/dds.main.cpp Voir le fichier

#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();
} }

+ 5
- 33
src/dds/deps.cpp Voir le fichier

} }


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());

+ 4
- 7
src/dds/deps.hpp Voir le fichier

#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

+ 154
- 0
src/dds/repo/remote.cpp Voir le fichier

#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!");
}

+ 75
- 0
src/dds/repo/remote.hpp Voir le fichier

#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

+ 51
- 45
src/dds/repo/repo.cpp Voir le fichier



#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;
} }

+ 36
- 14
src/dds/repo/repo.hpp Voir le fichier

#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

+ 18
- 0
src/dds/sdist.hpp Voir le fichier

#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&);



+ 4
- 1
src/dds/source.cpp Voir le fichier

#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

+ 2
- 13
src/libman/library.cpp Voir le fichier



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(),

+ 29
- 0
src/libman/parse.cpp Voir le fichier

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)}};
} }

+ 54
- 7
src/libman/parse.hpp Voir le fichier

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;

+ 43
- 0
src/libman/parse.test.cpp Voir le fichier

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;

+ 5
- 0
tests/__init__.py Voir le fichier

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

+ 0
- 1
tests/app_only.test/library.dds Voir le fichier

Name: app_only

+ 0
- 2
tests/app_only.test/package.dds Voir le fichier

Name: dds-app_only-test
Version: 0.0.0

+ 0
- 1
tests/app_only.test/src/something.main.cpp Voir le fichier

int main() { return 0; }

+ 14
- 0
tests/basics/test_app_only.py Voir le fichier

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()

+ 43
- 0
tests/basics/test_basics.py Voir le fichier

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()

+ 30
- 0
tests/basics/test_simple.py Voir le fichier

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*')) != []

+ 14
- 0
tests/basics/test_test_only.py Voir le fichier

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()

+ 38
- 0
tests/conftest.py Voir le fichier

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

+ 173
- 0
tests/dds.py Voir le fichier

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=['.'])

+ 36
- 0
tests/deps/do_test.py Voir le fichier

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)])

+ 5
- 0
tests/deps/git-remote/package.dds Voir le fichier

Name: deps-test
Version: 0.0.0

Depends: neo-buffer 0.1.0
Depends: range-v3 0.9.1

+ 2
- 0
tests/deps/git-remote/remote.dds Voir le fichier

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

+ 2
- 0
tests/deps/no-deps/package.dds Voir le fichier

Name: deps-test
Version: 0.0.0

+ 0
- 0
tests/deps/no-deps/remote.dds Voir le fichier


+ 3
- 0
tests/deps/use-remote/library.dds Voir le fichier

Name: dummy

Uses: nlohmann/json

+ 4
- 0
tests/deps/use-remote/package.dds Voir le fichier

Name: json-test
Version: 0.0.0

Depends: nlohmann-json 3.7.1

+ 1
- 0
tests/deps/use-remote/remote.dds Voir le fichier

Remote-Package: nlohmann-json 3.7.1; git url=https://github.com/vector-of-bool/json.git ref=dds/3.7.1

+ 8
- 0
tests/deps/use-remote/src/app.main.cpp Voir le fichier

#include <nlohmann/json.hpp>

int main() {
nlohmann::json j = {
{"foo", "bar"},
};
return j.size() == 1 ? 0 : 12;
}

+ 4
- 0
tests/deps/use-spdlog/gcc.tc.dds Voir le fichier

Compiler-ID: GNU
C++-Version: C++17
C++-Compiler: g++-8
Flags: -D SPDLOG_COMPILED_LIB

+ 2
- 0
tests/deps/use-spdlog/msvc.tc.dds Voir le fichier

Compiler-ID: MSVC
Flags: -D SPDLOG_COMPILED_LIB

+ 3
- 0
tests/deps/use-spdlog/project/library.dds Voir le fichier

Name: spdlog-user

Uses: spdlog/spdlog

+ 4
- 0
tests/deps/use-spdlog/project/package.dds Voir le fichier

Name: test
Version: 0.0.0

Depends: spdlog 1.4.2

+ 1
- 0
tests/deps/use-spdlog/project/remote.dds Voir le fichier

Remote-Package: spdlog 1.4.2; git url=https://github.com/gabime/spdlog.git ref=v1.4.2 auto=spdlog/spdlog

+ 6
- 0
tests/deps/use-spdlog/project/src/spdlog_user.cpp Voir le fichier

#include <spdlog/spdlog.h>

int write_message() {
spdlog::warn("This is a message generated by spdlog in the spdlog-user test library");
return 42;
}

+ 3
- 0
tests/deps/use-spdlog/project/src/spdlog_user.hpp Voir le fichier

#pragma once

extern int write_message();

+ 14
- 0
tests/deps/use-spdlog/project/src/use-spdlog.main.cpp Voir le fichier

#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;
}

+ 12
- 0
tests/deps/use-spdlog/use_spdlog_test.py Voir le fichier

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))

+ 7
- 0
tests/errors/errors_test.py Voir le fichier

from tests import DDS
from tests.fileutil import ensure_dir


def test_empty_dir(dds: DDS):
with ensure_dir(dds.source_root):
dds.build()

+ 52
- 0
tests/fileutil.py Voir le fichier

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)

+ 0
- 0
tests/sdist/create/include/header.h Voir le fichier


+ 0
- 0
tests/sdist/create/include/header.hpp Voir le fichier


+ 1
- 0
tests/sdist/create/library.dds Voir le fichier

Name: foo

+ 2
- 0
tests/sdist/create/package.dds Voir le fichier

Name: foo
Version: 1.2.3

+ 0
- 0
tests/sdist/create/src/foo.cpp Voir le fichier


+ 13
- 0
tests/sdist/sdist_test.py Voir le fichier

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()

+ 0
- 1
tests/simple.test/library.dds Voir le fichier

Name: simple

+ 0
- 2
tests/simple.test/package.dds Voir le fichier

Name: dds-simple-test
Version: 0.0.0

+ 0
- 1
tests/simple.test/src/foo.cpp Voir le fichier

int foo() { return 42; }

+ 0
- 1
tests/test_only.test/library.dds Voir le fichier

Name: test_only

+ 0
- 2
tests/test_only.test/package.dds Voir le fichier

Name: dds-test_only-test
Version: 0.0.0

+ 0
- 1
tests/test_only.test/src/foo.test.cpp Voir le fichier

int main() { return 0; }

+ 51
- 35
tools/ci.py Voir le fichier

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:]))

+ 0
- 0
tools/dds_ci/__init__.py Voir le fichier


+ 19
- 0
tools/dds_ci/cli.py Voir le fichier

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)

+ 12
- 0
tools/dds_ci/paths.py Voir le fichier

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'

+ 39
- 0
tools/dds_ci/proc.py Voir le fichier

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

+ 6
- 0
tools/gcc-8.p2.dds Voir le fichier

Compiler-ID: GNU
C++-Version: C++17
C++-Compiler: g++-8
Flags: -fconcepts -Werror=return-type
Flags: -D SPDLOG_COMPILED_LIB
Optimize: True

+ 4
- 0
tools/msvc.p2.dds Voir le fichier

Compiler-ID: MSVC
Flags: /experimental:preprocessor /D SPDLOG_COMPILED_LIB /wd5105 /std:c++latest
Link-Flags: rpcrt4.lib
Optimize: True

+ 41
- 0
tools/self_build.py Voir le fichier

#!/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:]))

+ 30
- 0
tools/self_deps_build.py Voir le fichier

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()

+ 19
- 0
tools/self_deps_get.py Voir le fichier

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)

+ 0
- 155
tools/test.py Voir le fichier

#!/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:]))

Chargement…
Annuler
Enregistrer