diff --git a/include/git2/errors.h b/include/git2/errors.h index a81aa05d9..e189e55f1 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -48,6 +48,7 @@ typedef enum { GIT_EEOF = -20, /**< Unexpected EOF */ GIT_EINVALID = -21, /**< Invalid operation or input */ GIT_EUNCOMMITTED = -22, /**< Uncommitted changes in index prevented operation */ + GIT_EDIRECTORY = -23, /**< The operation is not valid for a directory */ GIT_PASSTHROUGH = -30, /**< Internal only */ GIT_ITEROVER = -31, /**< Signals end of iteration with iterator */ diff --git a/src/blob.c b/src/blob.c index 07c4d92c8..ad0f4ac62 100644 --- a/src/blob.c +++ b/src/blob.c @@ -185,6 +185,12 @@ int git_blob__create_from_paths( (error = git_repository_odb(&odb, repo)) < 0) goto done; + if (S_ISDIR(st.st_mode)) { + giterr_set(GITERR_ODB, "cannot create blob from '%s'; it is a directory", content_path); + error = GIT_EDIRECTORY; + goto done; + } + if (out_st) memcpy(out_st, &st, sizeof(st)); diff --git a/src/index.c b/src/index.c index 5ce5522f8..501498e9e 100644 --- a/src/index.c +++ b/src/index.c @@ -1236,10 +1236,30 @@ int git_index_add_bypath(git_index *index, const char *path) assert(index && path); - if ((ret = index_entry_init(&entry, index, path)) < 0 || - (ret = index_insert(index, &entry, 1, false)) < 0) + if ((ret = index_entry_init(&entry, index, path)) == 0) + ret = index_insert(index, &entry, 1, false); + + /* If we were given a directory, let's see if it's a submodule */ + if (ret < 0 && ret != GIT_EDIRECTORY) return ret; + if (ret == GIT_EDIRECTORY) { + git_submodule *sm; + git_error_state err; + + giterr_capture(&err, ret); + + ret = git_submodule_lookup(&sm, INDEX_OWNER(index), path); + if (ret == GIT_ENOTFOUND) + return giterr_restore(&err); + else + git__free(err.error_msg.message); + + ret = git_submodule_add_to_index(sm, false); + git_submodule_free(sm); + return ret; + } + /* Adding implies conflict was resolved, move conflict entries to REUC */ if ((ret = index_conflict_to_reuc(index, path)) < 0 && ret != GIT_ENOTFOUND) return ret; diff --git a/tests/index/bypath.c b/tests/index/bypath.c new file mode 100644 index 000000000..ddb766a22 --- /dev/null +++ b/tests/index/bypath.c @@ -0,0 +1,35 @@ +#include "clar_libgit2.h" +#include "repository.h" +#include "../submodule/submodule_helpers.h" + +static git_repository *g_repo; +static git_index *g_idx; + +void test_index_bypath__initialize(void) +{ + g_repo = setup_fixture_submod2(); + cl_git_pass(git_repository_index__weakptr(&g_idx, g_repo)); +} + +void test_index_bypath__cleanup(void) +{ + g_repo = NULL; + g_idx = NULL; +} + +void test_index_bypath__add_directory(void) +{ + cl_git_fail_with(GIT_EDIRECTORY, git_index_add_bypath(g_idx, "just_a_dir")); +} + +void test_index_bypath__add_submodule(void) +{ + unsigned int status; + const char *sm_name = "sm_changed_head"; + + cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0)); + cl_assert_equal_i(GIT_SUBMODULE_STATUS_WD_MODIFIED, status & GIT_SUBMODULE_STATUS_WD_MODIFIED); + cl_git_pass(git_index_add_bypath(g_idx, sm_name)); + cl_git_pass(git_submodule_status(&status, g_repo, sm_name, 0)); + cl_assert_equal_i(0, status & GIT_SUBMODULE_STATUS_WD_MODIFIED); +} diff --git a/tests/submodule/add.c b/tests/submodule/add.c index 01625d3aa..c3b3e6364 100644 --- a/tests/submodule/add.c +++ b/tests/submodule/add.c @@ -4,6 +4,7 @@ #include "submodule_helpers.h" #include "config/config_helpers.h" #include "fileops.h" +#include "repository.h" static git_repository *g_repo = NULL;