diff options
| -rw-r--r-- | azure-pipelines.yml | 2 | ||||
| -rw-r--r-- | azure-pipelines/nightly.yml | 2 | ||||
| -rw-r--r-- | cmake/Modules/FindGSSFramework.cmake | 28 | ||||
| -rw-r--r-- | cmake/Modules/SelectGSSAPI.cmake | 53 | ||||
| -rw-r--r-- | cmake/Modules/SelectHTTPSBackend.cmake | 2 | ||||
| -rw-r--r-- | fuzzers/corpora/patch_parse/edit-file.diff | 13 | ||||
| -rw-r--r-- | fuzzers/corpora/patch_parse/patch_fuzzer-patch.diff | 45 | ||||
| -rw-r--r-- | fuzzers/patch_parse_fuzzer.c | 38 | ||||
| -rw-r--r-- | include/git2/submodule.h | 19 | ||||
| -rw-r--r-- | src/CMakeLists.txt | 12 | ||||
| -rw-r--r-- | src/clone.c | 25 | ||||
| -rw-r--r-- | src/clone.h | 4 | ||||
| -rw-r--r-- | src/features.h.in | 4 | ||||
| -rw-r--r-- | src/patch_parse.c | 1 | ||||
| -rw-r--r-- | src/submodule.c | 59 | ||||
| -rw-r--r-- | src/transports/auth_negotiate.c | 6 | ||||
| -rw-r--r-- | src/transports/auth_negotiate.h | 2 | ||||
| -rw-r--r-- | src/util.c | 5 | ||||
| -rw-r--r-- | tests/clone/nonetwork.c | 54 | ||||
| -rw-r--r-- | tests/diff/parse.c | 10 | ||||
| -rw-r--r-- | tests/patch/patch_common.h | 10 | ||||
| -rw-r--r-- | tests/submodule/add.c | 66 |
22 files changed, 386 insertions, 74 deletions
diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 00cca7e14..d74b51449 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -79,7 +79,7 @@ jobs: TMPDIR: $(Agent.TempDirectory) PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON SKIP_SSH_TESTS: true - job: windows_vs_amd64 diff --git a/azure-pipelines/nightly.yml b/azure-pipelines/nightly.yml index b8d550f28..a193747b5 100644 --- a/azure-pipelines/nightly.yml +++ b/azure-pipelines/nightly.yml @@ -79,7 +79,7 @@ jobs: TMPDIR: $(Agent.TempDirectory) PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig CMAKE_GENERATOR: Ninja - CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks + CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON RUN_INVASIVE_TESTS: true SKIP_SSH_TESTS: true diff --git a/cmake/Modules/FindGSSFramework.cmake b/cmake/Modules/FindGSSFramework.cmake new file mode 100644 index 000000000..dcf724916 --- /dev/null +++ b/cmake/Modules/FindGSSFramework.cmake @@ -0,0 +1,28 @@ +# Find GSS.framework +# This will define : +# +# GSSFRAMEWORK_FOUND +# GSSFRAMEWORK_INCLUDE_DIR +# GSSFRAMEWORK_LIBRARIES +# GSSFRAMEWORK_LDFLAGS +# + +FIND_PATH(GSSFRAMEWORK_INCLUDE_DIR NAMES GSS.h) +FIND_LIBRARY(GSSFRAMEWORK_LIBRARIES NAMES GSS) +IF (GSSFRAMEWORK_INCLUDE_DIR AND GSSFRAMEWORK_LIBRARIES) + IF (NOT CoreFoundation_FIND_QUIETLY) + MESSAGE(STATUS "Found GSS.framework ${GSSFRAMEWORK_LIBRARIES}") + ENDIF() + SET(GSSFRAMEWORK_FOUND TRUE) + SET(GSSFRAMEWORK_LDFLAGS "-framework GSS") +ENDIF () + +IF (GSS_FIND_REQUIRED AND NOT GSSFRAMEWORK_FOUND) + MESSAGE(FATAL_ERROR "CoreFoundation not found") +ENDIF() + +MARK_AS_ADVANCED( + GSSFRAMEWORK_INCLUDE_DIR + GSSFRAMEWORK_LIBRARIES + GSSFRAMEWORK_LDFLAGS +) diff --git a/cmake/Modules/SelectGSSAPI.cmake b/cmake/Modules/SelectGSSAPI.cmake new file mode 100644 index 000000000..41f837587 --- /dev/null +++ b/cmake/Modules/SelectGSSAPI.cmake @@ -0,0 +1,53 @@ +# Select the backend to use + +# We try to find any packages our backends might use + +FIND_PACKAGE(GSSAPI) +IF (CMAKE_SYSTEM_NAME MATCHES "Darwin") + INCLUDE(FindGSSFramework) +ENDIF() + +# Auto-select GSS backend +IF (USE_GSSAPI STREQUAL ON) + IF (GSSFRAMEWORK_FOUND) + SET(GSS_BACKEND "GSS.framework") + ELSEIF(GSSAPI_FOUND) + SET(GSS_BACKEND "gssapi") + ELSE() + MESSAGE(FATAL_ERROR "Unable to autodetect a usable GSS backend." + "Please pass the backend name explicitly (-DUSE_GSS=backend)") + ENDIF() +ELSEIF(USE_GSSAPI) + # Backend was explicitly set + SET(GSS_BACKEND ${USE_GSSAPI}) +ELSE() + SET(GSS_BACKEND NO) +ENDIF() + +IF(GSS_BACKEND) + # Check that we can find what's required for the selected backend + IF (GSS_BACKEND STREQUAL "GSS.framework") + IF (NOT GSSFRAMEWORK_FOUND) + MESSAGE(FATAL_ERROR "Asked for GSS.framework backend, but it wasn't found") + ENDIF() + + LIST(APPEND LIBGIT2_LIBS ${GSSFRAMEWORK_LIBRARIES}) + + SET(GIT_GSSFRAMEWORK 1) + ADD_FEATURE_INFO(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${GSS_BACKEND})") + ELSEIF (GSS_BACKEND STREQUAL "gssapi") + IF (NOT GSSAPI_FOUND) + MESSAGE(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found") + ENDIF() + + LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES}) + + SET(GIT_GSSAPI 1) + ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${GSS_BACKEND})") + ELSE() + MESSAGE(FATAL_ERROR "Asked for backend ${GSS_BACKEND} but it wasn't found") + ENDIF() +ELSE() + SET(GIT_GSSAPI 0) + ADD_FEATURE_INFO(SPNEGO NO "") +ENDIF() diff --git a/cmake/Modules/SelectHTTPSBackend.cmake b/cmake/Modules/SelectHTTPSBackend.cmake index 81f3f8b58..c7f6b8f1d 100644 --- a/cmake/Modules/SelectHTTPSBackend.cmake +++ b/cmake/Modules/SelectHTTPSBackend.cmake @@ -49,7 +49,7 @@ IF(HTTPS_BACKEND) SET(GIT_SECURE_TRANSPORT 1) LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR}) - LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LIBRARIES} ${SECURITY_LIBRARIES}) + LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) LIST(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS}) ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL") IF (NOT OPENSSL_FOUND) diff --git a/fuzzers/corpora/patch_parse/edit-file.diff b/fuzzers/corpora/patch_parse/edit-file.diff new file mode 100644 index 000000000..d9e783a7f --- /dev/null +++ b/fuzzers/corpora/patch_parse/edit-file.diff @@ -0,0 +1,13 @@ +diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c +index 76186b6fb..f7ce73ac8 100644 +--- a/fuzzers/patch_fuzzer.c ++++ b/fuzzers/patch_fuzzer.c +@@ -32,7 +32,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) + git_patch* patch; + git_patch_options opts = {(uint32_t)data[0]}; + int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts); +- if (status == 0 && patch) { ++ if (patch) { + git_patch_free(patch); + } + return 0; diff --git a/fuzzers/corpora/patch_parse/patch_fuzzer-patch.diff b/fuzzers/corpora/patch_parse/patch_fuzzer-patch.diff new file mode 100644 index 000000000..7c98d8ad4 --- /dev/null +++ b/fuzzers/corpora/patch_parse/patch_fuzzer-patch.diff @@ -0,0 +1,45 @@ +diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c +new file mode 100644 +index 000000000..76186b6fb +--- /dev/null ++++ b/fuzzers/patch_fuzzer.c +@@ -0,0 +1,39 @@ ++/* ++ * libgit2 patch fuzzer target. ++ * ++ * Copyright (C) the libgit2 contributors. All rights reserved. ++ * ++ * This file is part of libgit2, distributed under the GNU GPL v2 with ++ * a Linking Exception. For full terms see the included COPYING file. ++ */ ++ ++#include "git2.h" ++#include "patch.h" ++#include "patch_parse.h" ++ ++#define UNUSED(x) (void)(x) ++ ++int LLVMFuzzerInitialize(int *argc, char ***argv) ++{ ++ UNUSED(argc); ++ UNUSED(argv); ++ ++ if (git_libgit2_init() < 0) ++ abort(); ++ ++ return 0; ++} ++ ++int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) ++{ ++ if (size < 1) { ++ return 0; ++ } ++ git_patch* patch; ++ git_patch_options opts = {(uint32_t)data[0]}; ++ int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts); ++ if (status == 0 && patch) { ++ git_patch_free(patch); ++ } ++ return 0; ++} diff --git a/fuzzers/patch_parse_fuzzer.c b/fuzzers/patch_parse_fuzzer.c new file mode 100644 index 000000000..a9b02ad4d --- /dev/null +++ b/fuzzers/patch_parse_fuzzer.c @@ -0,0 +1,38 @@ +/* + * libgit2 patch parser fuzzer target. + * + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "git2.h" +#include "patch.h" +#include "patch_parse.h" + +#define UNUSED(x) (void)(x) + +int LLVMFuzzerInitialize(int *argc, char ***argv) +{ + UNUSED(argc); + UNUSED(argv); + + if (git_libgit2_init() < 0) + abort(); + + return 0; +} + +int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) +{ + if (size) { + git_patch *patch = NULL; + git_patch_options opts = GIT_PATCH_OPTIONS_INIT; + opts.prefix_len = (uint32_t)data[0]; + git_patch_from_buffer(&patch, (const char *)data + 1, size - 1, + &opts); + git_patch_free(patch); + } + return 0; +} diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 62f250b2b..bedd76d6a 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -263,7 +263,8 @@ GIT_EXTERN(int) git_submodule_foreach( * from the working directory to the new repo. * * To fully emulate "git submodule add" call this function, then open the - * submodule repo and perform the clone step as needed. Lastly, call + * submodule repo and perform the clone step as needed (if you don't need + * anything custom see `git_submodule_add_clone()`). Lastly, call * `git_submodule_add_finalize()` to wrap up adding the new submodule and * .gitmodules to the index to be ready to commit. * @@ -286,6 +287,22 @@ GIT_EXTERN(int) git_submodule_add_setup( int use_gitlink); /** + * Perform the clone step for a newly created submodule. + * + * This performs the necessary `git_clone` to setup a newly-created submodule. + * + * @param out The newly created repository object. Optional. + * @param submodule The submodule currently waiting for its clone. + * @param opts The options to use. + * + * @return 0 on success, -1 on other errors (see git_clone). + */ +GIT_EXTERN(int) git_submodule_clone( + git_repository **out, + git_submodule *submodule, + const git_submodule_update_options *opts); + +/** * Resolve the setup of a new git submodule. * * This should be called on a submodule once you have called add setup diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9d2b0229d..0ca1e7374 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -233,15 +233,9 @@ IF (USE_NTLMCLIENT) ENDIF() ADD_FEATURE_INFO(ntlmclient GIT_NTLM "NTLM authentication support for Unix") -# Optional external dependency: libgssapi -IF (USE_GSSAPI) - FIND_PACKAGE(GSSAPI) -ENDIF() -IF (GSSAPI_FOUND) - SET(GIT_GSSAPI 1) - LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES}) -ENDIF() -ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support") +# Optional external dependency: GSSAPI + +INCLUDE(SelectGSSAPI) # Optional external dependency: iconv IF (USE_ICONV) diff --git a/src/clone.c b/src/clone.c index e0b43f149..e8972b482 100644 --- a/src/clone.c +++ b/src/clone.c @@ -382,11 +382,12 @@ done: return is_local; } -int git_clone( +static int git__clone( git_repository **out, const char *url, const char *local_path, - const git_clone_options *_options) + const git_clone_options *_options, + int use_existing) { int error = 0; git_repository *repo = NULL; @@ -403,7 +404,7 @@ int git_clone( GIT_ERROR_CHECK_VERSION(&options, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); /* Only clone to a new directory or an empty directory */ - if (git_path_exists(local_path) && !git_path_is_empty_dir(local_path)) { + if (git_path_exists(local_path) && !use_existing && !git_path_is_empty_dir(local_path)) { git_error_set(GIT_ERROR_INVALID, "'%s' exists and is not an empty directory", local_path); return GIT_EEXISTS; @@ -455,6 +456,24 @@ int git_clone( return error; } +int git_clone( + git_repository **out, + const char *url, + const char *local_path, + const git_clone_options *_options) +{ + return git__clone(out, url, local_path, _options, 0); +} + +int git_clone__submodule( + git_repository **out, + const char *url, + const char *local_path, + const git_clone_options *_options) +{ + return git__clone(out, url, local_path, _options, 1); +} + int git_clone_options_init(git_clone_options *opts, unsigned int version) { GIT_INIT_STRUCTURE_FROM_TEMPLATE( diff --git a/src/clone.h b/src/clone.h index 864b59029..7d73cabd5 100644 --- a/src/clone.h +++ b/src/clone.h @@ -11,6 +11,10 @@ #include "git2/clone.h" +extern int git_clone__submodule(git_repository **out, + const char *url, const char *local_path, + const git_clone_options *_options); + extern int git_clone__should_clone_local(const char *url, git_clone_local_t local); #endif diff --git a/src/features.h.in b/src/features.h.in index f2931cb11..e000de5e0 100644 --- a/src/features.h.in +++ b/src/features.h.in @@ -27,9 +27,9 @@ #cmakedefine GIT_NTLM 1 #cmakedefine GIT_GSSAPI 1 -#cmakedefine GIT_WINHTTP 1 -#cmakedefine GIT_NTLM 1 +#cmakedefine GIT_GSSFRAMEWORK 1 +#cmakedefine GIT_WINHTTP 1 #cmakedefine GIT_HTTPS 1 #cmakedefine GIT_OPENSSL 1 #cmakedefine GIT_SECURE_TRANSPORT 1 diff --git a/src/patch_parse.c b/src/patch_parse.c index 51c4bb200..126918249 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -389,6 +389,7 @@ static const parse_header_transition transitions[] = { { "index " , STATE_DIFF, STATE_INDEX, parse_header_git_index }, { "index " , STATE_END, STATE_INDEX, parse_header_git_index }, + { "--- " , STATE_DIFF, STATE_PATH, parse_header_git_oldpath }, { "--- " , STATE_INDEX, STATE_PATH, parse_header_git_oldpath }, { "+++ " , STATE_PATH, STATE_END, parse_header_git_newpath }, { "GIT binary patch" , STATE_INDEX, STATE_END, NULL }, diff --git a/src/submodule.c b/src/submodule.c index cf89fc99b..d12dbcfee 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -23,6 +23,7 @@ #include "path.h" #include "index.h" #include "worktree.h" +#include "clone.h" #define GIT_MODULES_FILE ".gitmodules" @@ -815,6 +816,64 @@ done: return error; } +static int clone_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) +{ + GIT_UNUSED(url); + GIT_UNUSED(payload); + return git_remote_lookup(out, repo, name); +} + +static int clone_return_repo(git_repository **out, const char *path, int bare, void *payload) +{ + git_submodule *sm = payload; + + GIT_UNUSED(path); + GIT_UNUSED(bare); + return git_submodule_open(out, sm); +} + +int git_submodule_clone(git_repository **out, git_submodule *submodule, const git_submodule_update_options *given_opts) +{ + int error; + git_repository *clone; + git_buf rel_path = GIT_BUF_INIT; + git_submodule_update_options sub_opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT; + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + + assert(submodule); + + if (given_opts) + memcpy(&sub_opts, given_opts, sizeof(sub_opts)); + + GIT_ERROR_CHECK_VERSION(&sub_opts, GIT_SUBMODULE_UPDATE_OPTIONS_VERSION, "git_submodule_update_options"); + + memcpy(&opts.checkout_opts, &sub_opts.checkout_opts, sizeof(sub_opts.checkout_opts)); + memcpy(&opts.fetch_opts, &sub_opts.fetch_opts, sizeof(sub_opts.fetch_opts)); + opts.repository_cb = clone_return_repo; + opts.repository_cb_payload = submodule; + opts.remote_cb = clone_return_origin; + opts.remote_cb_payload = submodule; + + git_buf_puts(&rel_path, git_repository_workdir(git_submodule_owner(submodule))); + git_buf_joinpath(&rel_path, git_buf_cstr(&rel_path), git_submodule_path(submodule)); + + GIT_ERROR_CHECK_ALLOC_BUF(&rel_path); + + error = git_clone__submodule(&clone, git_submodule_url(submodule), git_buf_cstr(&rel_path), &opts); + if (error < 0) + goto cleanup; + + if (!out) + git_repository_free(clone); + else + *out = clone; + +cleanup: + git_buf_dispose(&rel_path); + + return error; +} + int git_submodule_add_finalize(git_submodule *sm) { int error; diff --git a/src/transports/auth_negotiate.c b/src/transports/auth_negotiate.c index b7eb42581..26315433d 100644 --- a/src/transports/auth_negotiate.c +++ b/src/transports/auth_negotiate.c @@ -7,15 +7,19 @@ #include "auth_negotiate.h" -#ifdef GIT_GSSAPI +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) #include "git2.h" #include "buffer.h" #include "auth.h" #include "git2/sys/cred.h" +#ifdef GIT_GSSFRAMEWORK +#import <GSS/GSS.h> +#elif defined(GIT_GSSAPI) #include <gssapi.h> #include <krb5.h> +#endif static gss_OID_desc negotiate_oid_spnego = { 6, (void *) "\x2b\x06\x01\x05\x05\x02" }; diff --git a/src/transports/auth_negotiate.h b/src/transports/auth_negotiate.h index d3f2ba2a1..34aff295b 100644 --- a/src/transports/auth_negotiate.h +++ b/src/transports/auth_negotiate.h @@ -12,7 +12,7 @@ #include "git2.h" #include "auth.h" -#ifdef GIT_GSSAPI +#if defined(GIT_GSSAPI) || defined(GIT_GSSFRAMEWORK) extern int git_http_auth_negotiate( git_http_auth_context **out, diff --git a/src/util.c b/src/util.c index fdd8e9afa..859e0a82b 100644 --- a/src/util.c +++ b/src/util.c @@ -719,6 +719,10 @@ static int GIT_STDLIB_CALL git__qsort_r_glue_cmp( } #endif + +#if !defined(HAVE_QSORT_R_BSD) && \ + !defined(HAVE_QSORT_R_GNU) && \ + !defined(HAVE_QSORT_S) static void swap(uint8_t *a, uint8_t *b, size_t elsize) { char tmp[256]; @@ -744,6 +748,7 @@ static void insertsort( for (j = i; j > base && cmp(j, j - elsize, payload) < 0; j -= elsize) swap(j, j - elsize, elsize); } +#endif void git__qsort_r( void *els, size_t nel, size_t elsize, git__sort_r_cmp cmp, void *payload) diff --git a/tests/clone/nonetwork.c b/tests/clone/nonetwork.c index 2b8081f8a..7ca49085c 100644 --- a/tests/clone/nonetwork.c +++ b/tests/clone/nonetwork.c @@ -1,7 +1,6 @@ #include "clar_libgit2.h" #include "git2/clone.h" -#include "git2/sys/commit.h" #include "../submodule/submodule_helpers.h" #include "remote.h" #include "futils.h" @@ -352,56 +351,3 @@ void test_clone_nonetwork__clone_from_empty_sets_upstream(void) git_repository_free(repo); cl_fixture_cleanup("./repowithunborn"); } - -static int just_return_origin(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload) -{ - GIT_UNUSED(url); GIT_UNUSED(payload); - - return git_remote_lookup(out, repo, name); -} - -static int just_return_repo(git_repository **out, const char *path, int bare, void *payload) -{ - git_submodule *sm = payload; - - GIT_UNUSED(path); GIT_UNUSED(bare); - - return git_submodule_open(out, sm); -} - -void test_clone_nonetwork__clone_submodule(void) -{ - git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; - git_index *index; - git_oid tree_id, commit_id; - git_submodule *sm; - git_signature *sig; - git_repository *sm_repo; - - cl_git_pass(git_repository_init(&g_repo, "willaddsubmodule", false)); - - - /* Create the submodule structure, clone into it and finalize */ - cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "testrepo", true)); - - clone_opts.repository_cb = just_return_repo; - clone_opts.repository_cb_payload = sm; - clone_opts.remote_cb = just_return_origin; - clone_opts.remote_cb_payload = sm; - cl_git_pass(git_clone(&sm_repo, cl_fixture("testrepo.git"), "testrepo", &clone_opts)); - cl_git_pass(git_submodule_add_finalize(sm)); - git_repository_free(sm_repo); - git_submodule_free(sm); - - cl_git_pass(git_repository_index(&index, g_repo)); - cl_git_pass(git_index_write_tree(&tree_id, index)); - git_index_free(index); - - cl_git_pass(git_signature_now(&sig, "Submoduler", "submoduler@local")); - cl_git_pass(git_commit_create_from_ids(&commit_id, g_repo, "HEAD", sig, sig, NULL, "A submodule\n", - &tree_id, 0, NULL)); - - git_signature_free(sig); - - assert_submodule_exists(g_repo, "testrepo"); -} diff --git a/tests/diff/parse.c b/tests/diff/parse.c index 7d9f4b2e5..b004d1e23 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -98,6 +98,16 @@ void test_diff_parse__empty_file(void) git_diff_free(diff); } +void test_diff_parse__no_extended_headers(void) +{ + const char *content = PATCH_NO_EXTENDED_HEADERS; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer( + &diff, content, strlen(content))); + git_diff_free(diff); +} + void test_diff_parse__invalid_patches_fails(void) { test_parse_invalid_diff(PATCH_CORRUPT_MISSING_NEW_FILE); diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h index 690e0a662..d730d142c 100644 --- a/tests/patch/patch_common.h +++ b/tests/patch/patch_common.h @@ -895,3 +895,13 @@ "+++ b/test-file\r\n" \ "@@ -0,0 +1 @@\r\n" \ "+a contents\r\n" + +#define PATCH_NO_EXTENDED_HEADERS \ + "diff --git a/file b/file\n" \ + "--- a/file\n" \ + "+++ b/file\n" \ + "@@ -1,3 +1,3 @@\n" \ + " a\n" \ + "-b\n" \ + "+bb\n" \ + " c\n" diff --git a/tests/submodule/add.c b/tests/submodule/add.c index b251b331e..f4d1e3b79 100644 --- a/tests/submodule/add.c +++ b/tests/submodule/add.c @@ -5,6 +5,7 @@ #include "config/config_helpers.h" #include "futils.h" #include "repository.h" +#include "git2/sys/commit.h" static git_repository *g_repo = NULL; static const char *valid_blob_id = "fa49b077972391ad58037050f2a75f74e3671e92"; @@ -183,3 +184,68 @@ void test_submodule_add__file_exists_in_index(void) git_submodule_free(sm); git_buf_dispose(&name); } + +void test_submodule_add__submodule_clone(void) +{ + git_oid tree_id, commit_id; + git_signature *sig; + git_submodule *sm; + git_index *index; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + /* Create the submodule structure, clone into it and finalize */ + cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "testrepo-add", true)); + cl_git_pass(git_submodule_clone(NULL, sm, NULL)); + cl_git_pass(git_submodule_add_finalize(sm)); + + /* Create the submodule commit */ + cl_git_pass(git_repository_index(&index, g_repo)); + cl_git_pass(git_index_write_tree(&tree_id, index)); + cl_git_pass(git_signature_now(&sig, "Submoduler", "submoduler@local")); + cl_git_pass(git_commit_create_from_ids(&commit_id, g_repo, "HEAD", sig, sig, NULL, "A submodule\n", + &tree_id, 0, NULL)); + + assert_submodule_exists(g_repo, "testrepo-add"); + + git_signature_free(sig); + git_submodule_free(sm); + git_index_free(index); +} + +void test_submodule_add__submodule_clone_into_nonempty_dir_succeeds(void) +{ + git_submodule *sm; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + cl_git_pass(p_mkdir("empty_standard_repo/sm", 0777)); + cl_git_mkfile("empty_standard_repo/sm/foobar", ""); + + /* Create the submodule structure, clone into it and finalize */ + cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "sm", true)); + cl_git_pass(git_submodule_clone(NULL, sm, NULL)); + cl_git_pass(git_submodule_add_finalize(sm)); + + cl_assert(git_path_exists("empty_standard_repo/sm/foobar")); + + assert_submodule_exists(g_repo, "sm"); + + git_submodule_free(sm); +} + +void test_submodule_add__submodule_clone_twice_fails(void) +{ + git_submodule *sm; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + /* Create the submodule structure, clone into it and finalize */ + cl_git_pass(git_submodule_add_setup(&sm, g_repo, cl_fixture("testrepo.git"), "sm", true)); + cl_git_pass(git_submodule_clone(NULL, sm, NULL)); + cl_git_pass(git_submodule_add_finalize(sm)); + + cl_git_fail(git_submodule_clone(NULL, sm, NULL)); + + git_submodule_free(sm); +} |
