Merge pull request #6971 from libgit2/ethomson/features

Allow consumers to query the "backends" that libgit2 was built with
This commit is contained in:
Edward Thomson
2024-12-23 09:14:35 +00:00
committed by GitHub
6 changed files with 452 additions and 49 deletions

View File

@@ -4,6 +4,7 @@ include(SanitizeBool)
SanitizeBool(USE_BUNDLED_ZLIB)
if(USE_BUNDLED_ZLIB STREQUAL ON)
set(USE_BUNDLED_ZLIB "Bundled")
set(GIT_COMPRESSION_BUILTIN)
endif()
if(USE_BUNDLED_ZLIB STREQUAL "OFF")
@@ -17,6 +18,7 @@ if(USE_BUNDLED_ZLIB STREQUAL "OFF")
list(APPEND LIBGIT2_PC_REQUIRES "zlib")
endif()
add_feature_info(zlib ON "using system zlib")
set(GIT_COMPRESSION_ZLIB 1)
else()
message(STATUS "zlib was not found; using bundled 3rd-party sources." )
endif()
@@ -26,9 +28,11 @@ if(USE_BUNDLED_ZLIB STREQUAL "Chromium")
list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/chromium-zlib")
list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $<TARGET_OBJECTS:chromium_zlib>)
add_feature_info(zlib ON "using (Chromium) bundled zlib")
set(GIT_COMPRESSION_BUILTIN 1)
elseif(USE_BUNDLED_ZLIB OR NOT ZLIB_FOUND)
add_subdirectory("${PROJECT_SOURCE_DIR}/deps/zlib" "${PROJECT_BINARY_DIR}/deps/zlib")
list(APPEND LIBGIT2_DEPENDENCY_INCLUDES "${PROJECT_SOURCE_DIR}/deps/zlib")
list(APPEND LIBGIT2_DEPENDENCY_OBJECTS $<TARGET_OBJECTS:zlib>)
add_feature_info(zlib ON "using bundled zlib")
set(GIT_COMPRESSION_BUILTIN 1)
endif()

View File

@@ -130,57 +130,81 @@ GIT_EXTERN(int) git_libgit2_version(int *major, int *minor, int *rev);
GIT_EXTERN(const char *) git_libgit2_prerelease(void);
/**
* Combinations of these values describe the features with which libgit2
* was compiled
* Configurable features of libgit2; either optional settings (like
* threading), or features that can be enabled by one of a number of
* different backend "providers" (like HTTPS, which can be provided by
* OpenSSL, mbedTLS, or system libraries).
*/
typedef enum {
/**
* If set, libgit2 was built thread-aware and can be safely used from multiple
* threads.
*/
GIT_FEATURE_THREADS = (1 << 0),
/**
* If set, libgit2 was built with and linked against a TLS implementation.
* Custom TLS streams may still be added by the user to support HTTPS
* regardless of this.
*/
GIT_FEATURE_HTTPS = (1 << 1),
/**
* If set, libgit2 was built with and linked against libssh2. A custom
* transport may still be added by the user to support libssh2 regardless of
* this.
*/
GIT_FEATURE_SSH = (1 << 2),
/**
* If set, libgit2 was built with support for sub-second resolution in file
* modification times.
*/
GIT_FEATURE_NSEC = (1 << 3)
/**
* libgit2 is thread-aware and can be used from multiple threads
* (as described in the documentation).
*/
GIT_FEATURE_THREADS = (1 << 0),
/** HTTPS remotes */
GIT_FEATURE_HTTPS = (1 << 1),
/** SSH remotes */
GIT_FEATURE_SSH = (1 << 2),
/** Sub-second resolution in index timestamps */
GIT_FEATURE_NSEC = (1 << 3),
/** HTTP parsing; always available */
GIT_FEATURE_HTTP_PARSER = (1 << 4),
/** Regular expression support; always available */
GIT_FEATURE_REGEX = (1 << 5),
/** Internationalization support for filename translation */
GIT_FEATURE_I18N = (1 << 6),
/** NTLM support over HTTPS */
GIT_FEATURE_AUTH_NTLM = (1 << 7),
/** Kerberos (SPNEGO) authentication support over HTTPS */
GIT_FEATURE_AUTH_NEGOTIATE = (1 << 8),
/** zlib support; always available */
GIT_FEATURE_COMPRESSION = (1 << 9),
/** SHA1 object support; always available */
GIT_FEATURE_SHA1 = (1 << 10),
/** SHA256 object support */
GIT_FEATURE_SHA256 = (1 << 11)
} git_feature_t;
/**
* Query compile time options for libgit2.
*
* @return A combination of GIT_FEATURE_* values.
*
* - GIT_FEATURE_THREADS
* Libgit2 was compiled with thread support. Note that thread support is
* still to be seen as a 'work in progress' - basic object lookups are
* believed to be threadsafe, but other operations may not be.
*
* - GIT_FEATURE_HTTPS
* Libgit2 supports the https:// protocol. This requires the openssl
* library to be found when compiling libgit2.
*
* - GIT_FEATURE_SSH
* Libgit2 supports the SSH protocol for network operations. This requires
* the libssh2 library to be found when compiling libgit2
*
* - GIT_FEATURE_NSEC
* Libgit2 supports the sub-second resolution in file modification times.
*/
GIT_EXTERN(int) git_libgit2_features(void);
/**
* Query the backend details for the compile-time feature in libgit2.
*
* This will return the "backend" for the feature, which is useful for
* things like HTTPS or SSH support, that can have multiple backends
* that could be compiled in.
*
* For example, when libgit2 is compiled with dynamic OpenSSL support,
* the feature backend will be `openssl-dynamic`. The feature backend
* names reflect the compilation options specified to the build system
* (though in all lower case). The backend _may_ be "builtin" for
* features that are provided by libgit2 itself.
*
* If the feature is not supported by the library, this API returns
* `NULL`.
*
* @param feature the feature to query details for
* @return the provider details, or NULL if the feature is not supported
*/
GIT_EXTERN(const char *) git_libgit2_feature_backend(
git_feature_t feature);
/**
* Global library options
*

View File

@@ -92,6 +92,177 @@ int git_libgit2_features(void)
#endif
#ifdef GIT_USE_NSEC
| GIT_FEATURE_NSEC
#endif
| GIT_FEATURE_HTTP_PARSER
| GIT_FEATURE_REGEX
#ifdef GIT_USE_ICONV
| GIT_FEATURE_I18N
#endif
#if defined(GIT_NTLM) || defined(GIT_WIN32)
| GIT_FEATURE_AUTH_NTLM
#endif
#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32)
| GIT_FEATURE_AUTH_NEGOTIATE
#endif
| GIT_FEATURE_COMPRESSION
| GIT_FEATURE_SHA1
#ifdef GIT_EXPERIMENTAL_SHA256
| GIT_FEATURE_SHA256
#endif
;
}
const char *git_libgit2_feature_backend(git_feature_t feature)
{
switch (feature) {
case GIT_FEATURE_THREADS:
#if defined(GIT_THREADS) && defined(GIT_WIN32)
return "win32";
#elif defined(GIT_THREADS)
return "pthread";
#endif
break;
case GIT_FEATURE_HTTPS:
#if defined(GIT_HTTPS) && defined(GIT_OPENSSL)
return "openssl";
#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC)
return "openssl-dynamic";
#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS)
return "mbedtls";
#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT)
return "securetransport";
#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL)
return "schannel";
#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP)
return "winhttp";
#elif defined(GIT_HTTPS)
GIT_ASSERT_WITH_RETVAL(!"Unknown HTTPS backend", NULL);
#endif
break;
case GIT_FEATURE_SSH:
#if defined(GIT_SSH_EXEC)
return "exec";
#elif defined(GIT_SSH_LIBSSH2)
return "libssh2";
#elif defined(GIT_SSH)
GIT_ASSERT_WITH_RETVAL(!"Unknown SSH backend", NULL);
#endif
break;
case GIT_FEATURE_NSEC:
#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC)
return "mtimespec";
#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM)
return "mtim";
#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC)
return "mtime";
#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32)
return "win32";
#elif defined(GIT_USE_NSEC)
GIT_ASSERT_WITH_RETVAL(!"Unknown high-resolution time backend", NULL);
#endif
break;
case GIT_FEATURE_HTTP_PARSER:
#if defined(GIT_HTTPPARSER_HTTPPARSER)
return "httpparser";
#elif defined(GIT_HTTPPARSER_LLHTTP)
return "llhttp";
#elif defined(GIT_HTTPPARSER_BUILTIN)
return "builtin";
#endif
GIT_ASSERT_WITH_RETVAL(!"Unknown HTTP parser backend", NULL);
break;
case GIT_FEATURE_REGEX:
#if defined(GIT_REGEX_REGCOMP_L)
return "regcomp_l";
#elif defined(GIT_REGEX_REGCOMP)
return "regcomp";
#elif defined(GIT_REGEX_PCRE)
return "pcre";
#elif defined(GIT_REGEX_PCRE2)
return "pcre2";
#elif defined(GIT_REGEX_BUILTIN)
return "builtin";
#endif
GIT_ASSERT_WITH_RETVAL(!"Unknown regular expression backend", NULL);
break;
case GIT_FEATURE_I18N:
#if defined(GIT_USE_ICONV)
return "iconv";
#endif
break;
case GIT_FEATURE_AUTH_NTLM:
#if defined(GIT_NTLM)
return "ntlmclient";
#elif defined(GIT_WIN32)
return "sspi";
#endif
break;
case GIT_FEATURE_AUTH_NEGOTIATE:
#if defined(GIT_GSSAPI)
return "gssapi";
#elif defined(GIT_WIN32)
return "sspi";
#endif
break;
case GIT_FEATURE_COMPRESSION:
#if defined(GIT_COMPRESSION_ZLIB)
return "zlib";
#elif defined(GIT_COMPRESSION_BUILTIN)
return "builtin";
#else
GIT_ASSERT_WITH_RETVAL(!"Unknown compression backend", NULL);
#endif
break;
case GIT_FEATURE_SHA1:
#if defined(GIT_SHA1_COLLISIONDETECT)
return "builtin";
#elif defined(GIT_SHA1_OPENSSL)
return "openssl";
#elif defined(GIT_SHA1_OPENSSL_FIPS)
return "openssl-fips";
#elif defined(GIT_SHA1_OPENSSL_DYNAMIC)
return "openssl-dynamic";
#elif defined(GIT_SHA1_MBEDTLS)
return "mbedtls";
#elif defined(GIT_SHA1_COMMON_CRYPTO)
return "commoncrypto";
#elif defined(GIT_SHA1_WIN32)
return "win32";
#else
GIT_ASSERT_WITH_RETVAL(!"Unknown SHA1 backend", NULL);
#endif
break;
case GIT_FEATURE_SHA256:
#if defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_BUILTIN)
return "builtin";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL)
return "openssl";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_FIPS)
return "openssl-fips";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_DYNAMIC)
return "openssl-dynamic";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_MBEDTLS)
return "mbedtls";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_COMMON_CRYPTO)
return "commoncrypto";
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_WIN32)
return "win32";
#elif defined(GIT_EXPERIMENTAL_SHA256)
GIT_ASSERT_WITH_RETVAL(!"Unknown SHA256 backend", NULL);
#endif
break;
}
return NULL;
}

View File

@@ -66,6 +66,9 @@
#cmakedefine GIT_SHA256_OPENSSL_DYNAMIC 1
#cmakedefine GIT_SHA256_MBEDTLS 1
#cmakedefine GIT_COMPRESSION_BUILTIN 1
#cmakedefine GIT_COMPRESSION_ZLIB 1
#cmakedefine GIT_RAND_GETENTROPY 1
#cmakedefine GIT_RAND_GETLOADAVG 1

View File

@@ -1,15 +1,8 @@
#include "clar_libgit2.h"
void test_core_features__0(void)
void test_core_features__basic(void)
{
int major, minor, rev, caps;
git_libgit2_version(&major, &minor, &rev);
cl_assert_equal_i(LIBGIT2_VERSION_MAJOR, major);
cl_assert_equal_i(LIBGIT2_VERSION_MINOR, minor);
cl_assert_equal_i(LIBGIT2_VERSION_REVISION, rev);
caps = git_libgit2_features();
int caps = git_libgit2_features();
#ifdef GIT_THREADS
cl_assert((caps & GIT_FEATURE_THREADS) != 0);
@@ -32,4 +25,202 @@ void test_core_features__0(void)
#else
cl_assert((caps & GIT_FEATURE_NSEC) == 0);
#endif
cl_assert((caps & GIT_FEATURE_HTTP_PARSER) != 0);
cl_assert((caps & GIT_FEATURE_REGEX) != 0);
#if defined(GIT_USE_ICONV)
cl_assert((caps & GIT_FEATURE_I18N) != 0);
#endif
#if defined(GIT_NTLM) || defined(GIT_WIN32)
cl_assert((caps & GIT_FEATURE_AUTH_NTLM) != 0);
#endif
#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) || defined(GIT_WIN32)
cl_assert((caps & GIT_FEATURE_AUTH_NEGOTIATE) != 0);
#endif
cl_assert((caps & GIT_FEATURE_COMPRESSION) != 0);
cl_assert((caps & GIT_FEATURE_SHA1) != 0);
#if defined(GIT_EXPERIMENTAL_SHA256)
cl_assert((caps & GIT_FEATURE_SHA256) != 0);
#endif
/*
* Ensure that our tests understand all the features;
* this test tries to ensure that if there's a new feature
* added that the backends test (below) is updated as well.
*/
cl_assert((caps & ~(GIT_FEATURE_THREADS |
GIT_FEATURE_HTTPS |
GIT_FEATURE_SSH |
GIT_FEATURE_NSEC |
GIT_FEATURE_HTTP_PARSER |
GIT_FEATURE_REGEX |
GIT_FEATURE_I18N |
GIT_FEATURE_AUTH_NTLM |
GIT_FEATURE_AUTH_NEGOTIATE |
GIT_FEATURE_COMPRESSION |
GIT_FEATURE_SHA1 |
GIT_FEATURE_SHA256
)) == 0);
}
void test_core_features__backends(void)
{
const char *threads = git_libgit2_feature_backend(GIT_FEATURE_THREADS);
const char *https = git_libgit2_feature_backend(GIT_FEATURE_HTTPS);
const char *ssh = git_libgit2_feature_backend(GIT_FEATURE_SSH);
const char *nsec = git_libgit2_feature_backend(GIT_FEATURE_NSEC);
const char *http_parser = git_libgit2_feature_backend(GIT_FEATURE_HTTP_PARSER);
const char *regex = git_libgit2_feature_backend(GIT_FEATURE_REGEX);
const char *i18n = git_libgit2_feature_backend(GIT_FEATURE_I18N);
const char *ntlm = git_libgit2_feature_backend(GIT_FEATURE_AUTH_NTLM);
const char *negotiate = git_libgit2_feature_backend(GIT_FEATURE_AUTH_NEGOTIATE);
const char *compression = git_libgit2_feature_backend(GIT_FEATURE_COMPRESSION);
const char *sha1 = git_libgit2_feature_backend(GIT_FEATURE_SHA1);
const char *sha256 = git_libgit2_feature_backend(GIT_FEATURE_SHA256);
#if defined(GIT_THREADS) && defined(GIT_WIN32)
cl_assert_equal_s("win32", threads);
#elif defined(GIT_THREADS)
cl_assert_equal_s("pthread", threads);
#else
cl_assert(threads == NULL);
#endif
#if defined(GIT_HTTPS) && defined(GIT_OPENSSL)
cl_assert_equal_s("openssl", https);
#elif defined(GIT_HTTPS) && defined(GIT_OPENSSL_DYNAMIC)
cl_assert_equal_s("openssl-dynamic", https);
#elif defined(GIT_HTTPS) && defined(GIT_MBEDTLS)
cl_assert_equal_s("mbedtls", https);
#elif defined(GIT_HTTPS) && defined(GIT_SECURE_TRANSPORT)
cl_assert_equal_s("securetransport", https);
#elif defined(GIT_HTTPS) && defined(GIT_SCHANNEL)
cl_assert_equal_s("schannel", https);
#elif defined(GIT_HTTPS) && defined(GIT_WINHTTP)
cl_assert_equal_s("winhttp", https);
#elif defined(GIT_HTTPS)
cl_assert(0);
#else
cl_assert(https == NULL);
#endif
#if defined(GIT_SSH) && defined(GIT_SSH_EXEC)
cl_assert_equal_s("exec", ssh);
#elif defined(GIT_SSH) && defined(GIT_SSH_LIBSSH2)
cl_assert_equal_s("libssh2", ssh);
#elif defined(GIT_SSH)
cl_assert(0);
#else
cl_assert(ssh == NULL);
#endif
#if defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIMESPEC)
cl_assert_equal_s("mtimespec", nsec);
#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIM)
cl_assert_equal_s("mtim", nsec);
#elif defined(GIT_USE_NSEC) && defined(GIT_USE_STAT_MTIME_NSEC)
cl_assert_equal_s("mtime", nsec);
#elif defined(GIT_USE_NSEC) && defined(GIT_WIN32)
cl_assert_equal_s("win32", nsec);
#elif defined(GIT_USE_NSEC)
cl_assert(0);
#else
cl_assert(nsec == NULL);
#endif
#if defined(GIT_HTTPPARSER_HTTPPARSER)
cl_assert_equal_s("httpparser", http_parser);
#elif defined(GIT_HTTPPARSER_LLHTTP)
cl_assert_equal_s("llhttp", http_parser);
#elif defined(GIT_HTTPPARSER_BUILTIN)
cl_assert_equal_s("builtin", http_parser);
#else
cl_assert(0);
#endif
#if defined(GIT_REGEX_REGCOMP_L)
cl_assert_equal_s("regcomp_l", regex);
#elif defined(GIT_REGEX_REGCOMP)
cl_assert_equal_s("regcomp", regex);
#elif defined(GIT_REGEX_PCRE)
cl_assert_equal_s("pcre", regex);
#elif defined(GIT_REGEX_PCRE2)
cl_assert_equal_s("pcre2", regex);
#elif defined(GIT_REGEX_BUILTIN)
cl_assert_equal_s("builtin", regex);
#else
cl_assert(0);
#endif
#if defined(GIT_USE_ICONV)
cl_assert_equal_s("iconv", i18n);
#else
cl_assert(i18n == NULL);
#endif
#if defined(GIT_NTLM)
cl_assert_equal_s("ntlmclient", ntlm);
#elif defined(GIT_WIN32)
cl_assert_equal_s("sspi", ntlm);
#else
cl_assert(ntlm == NULL);
#endif
#if defined(GIT_GSSAPI)
cl_assert_equal_s("gssapi", negotiate);
#elif defined(GIT_WIN32)
cl_assert_equal_s("sspi", negotiate);
#else
cl_assert(negotiate == NULL);
#endif
#if defined(GIT_COMPRESSION_BUILTIN)
cl_assert_equal_s("builtin", compression);
#elif defined(GIT_COMPRESSION_ZLIB)
cl_assert_equal_s("zlib", compression);
#else
cl_assert(0);
#endif
#if defined(GIT_SHA1_COLLISIONDETECT)
cl_assert_equal_s("builtin", sha1);
#elif defined(GIT_SHA1_OPENSSL)
cl_assert_equal_s("openssl", sha1);
#elif defined(GIT_SHA1_OPENSSL_FIPS)
cl_assert_equal_s("openssl-fips", sha1);
#elif defined(GIT_SHA1_OPENSSL_DYNAMIC)
cl_assert_equal_s("openssl-dynamic", sha1);
#elif defined(GIT_SHA1_MBEDTLS)
cl_assert_equal_s("mbedtls", sha1);
#elif defined(GIT_SHA1_COMMON_CRYPTO)
cl_assert_equal_s("commoncrypto", sha1);
#elif defined(GIT_SHA1_WIN32)
cl_assert_equal_s("win32", sha1);
#else
cl_assert(0);
#endif
#if defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_BUILTIN)
cl_assert_equal_s("builtin", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL)
cl_assert_equal_s("openssl", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_FIPS)
cl_assert_equal_s("openssl-fips", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_OPENSSL_DYNAMIC)
cl_assert_equal_s("openssl-dynamic", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_MBEDTLS)
cl_assert_equal_s("mbedtls", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_COMMON_CRYPTO)
cl_assert_equal_s("commoncrypto", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256) && defined(GIT_SHA256_WIN32)
cl_assert_equal_s("win32", sha256);
#elif defined(GIT_EXPERIMENTAL_SHA256)
cl_assert(0);
#else
cl_assert(sha256 == NULL);
#endif
}

View File

@@ -1,5 +1,15 @@
#include "clar_libgit2.h"
void test_core_version__query(void)
{
int major, minor, rev;
git_libgit2_version(&major, &minor, &rev);
cl_assert_equal_i(LIBGIT2_VERSION_MAJOR, major);
cl_assert_equal_i(LIBGIT2_VERSION_MINOR, minor);
cl_assert_equal_i(LIBGIT2_VERSION_REVISION, rev);
}
void test_core_version__check(void)
{
#if !LIBGIT2_VERSION_CHECK(1,6,3)