]> git.proxmox.com Git - libgit2.git/commitdiff
Merge pull request #3328 from libgit2/cmn/iterator-skip-diriter
authorEdward Thomson <ethomson@edwardthomson.com>
Wed, 29 Jul 2015 21:46:47 +0000 (16:46 -0500)
committerEdward Thomson <ethomson@edwardthomson.com>
Wed, 29 Jul 2015 21:46:47 +0000 (16:46 -0500)
iterator: skip over errors in diriter init

17 files changed:
CHANGELOG.md
include/git2/errors.h
include/git2/sys/refdb_backend.h
src/blob.c
src/branch.c
src/filter.c
src/global.c
src/index.c
src/path.c
src/path.h
src/refdb_fs.c
src/submodule.c
src/transports/http.c
tests/index/bypath.c [new file with mode: 0644]
tests/refs/branches/delete.c
tests/submodule/add.c
tests/submodule/lookup.c

index c0a819ed7968c395e32afb8596f895162d1ce06c..243b696d723619e3107488468fbe6416959799b4 100644 (file)
@@ -15,6 +15,10 @@ v0.23 + 1
 
 * `git_cert` descendent types now have a proper `parent` member
 
+* It is the responsibility fo the refdb backend to decide what to do
+  with the reflog on ref deletion. The file-based backend must delete
+  it, a database-backed one may wish to archive it.
+
 v0.23
 ------
 
index a81aa05d9ceb7f11c4c1e23eceb2e9ec2aca395a..e189e55f17e6faa910ca91c2aa83ff4c370276d3 100644 (file)
@@ -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 */
index d943e550f46c2390a97e97ce75a1c35caac8560c..9f2a99b7ebb78f39bf8e79d61ccae7cec2b27e3d 100644 (file)
@@ -103,8 +103,9 @@ struct git_refdb_backend {
                const git_signature *who, const char *message);
 
        /**
-        * Deletes the given reference from the refdb.  A refdb implementation
-        * must provide this function.
+        * Deletes the given reference (and if necessary its reflog)
+        * from the refdb.  A refdb implementation must provide this
+        * function.
         */
        int (*del)(git_refdb_backend *backend, const char *ref_name, const git_oid *old_id, const char *old_target);
 
index 07c4d92c84b826772f6f1b00e982594384410f2c..ad0f4ac62aa77ea4e1dd298f5353058a98052767 100644 (file)
@@ -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));
 
index 791d551067ec4be5fd9c68414d85f7b3473c18e5..0dcc14c297e469814fda472bca0c23c49bd2093f 100644 (file)
@@ -155,18 +155,7 @@ int git_branch_delete(git_reference *branch)
                git_reference_owner(branch), git_buf_cstr(&config_section), NULL) < 0)
                goto on_error;
 
-       if (git_reference_delete(branch) < 0)
-               goto on_error;
-
-       if ((error = git_reflog_delete(git_reference_owner(branch), git_reference_name(branch))) < 0) {
-               if (error == GIT_ENOTFOUND) {
-                       giterr_clear();
-                       error = 0;
-               }
-               goto on_error;
-       }
-
-       error = 0;
+       error = git_reference_delete(branch);
 
 on_error:
        git_buf_free(&config_section);
index 70c4fa3824b0eb75b772995cc49f5dd7253c56f2..60473e4e12c27c6036138bebe9b0a4f9ea7147b2 100644 (file)
@@ -950,18 +950,20 @@ int git_filter_list_stream_data(
 {
        git_vector filter_streams = GIT_VECTOR_INIT;
        git_writestream *stream_start;
-       int error = 0;
+       int error = 0, close_error;
 
        git_buf_sanitize(data);
 
-       if ((error = stream_list_init(
-                       &stream_start, &filter_streams, filters, target)) == 0 &&
-               (error =
-                       stream_start->write(stream_start, data->ptr, data->size)) == 0)
-               error = stream_start->close(stream_start);
+       if ((error = stream_list_init(&stream_start, &filter_streams, filters, target)) < 0)
+               goto out;
 
+       error = stream_start->write(stream_start, data->ptr, data->size);
+
+out:
+       close_error = stream_start->close(stream_start);
        stream_list_free(&filter_streams);
-       return error;
+       /* propagate the stream init or write error */
+       return error < 0 ? error : close_error;
 }
 
 int git_filter_list_stream_blob(
index fc6337adc0bfb99a89edb9420a848ae2ecd1e6ae..37a47bd27ada85c378b14de496554cf74620b451 100644 (file)
@@ -344,8 +344,8 @@ int git_libgit2_init(void)
 {
        int ret;
 
-       pthread_once(&_once_init, init_once);
        ret = git_atomic_inc(&git__n_inits);
+       pthread_once(&_once_init, init_once);
 
        return init_error ? init_error : ret;
 }
index 5ce5522f8aa360b7c28f50e8cd0606f83106d619..501498e9e07bf7e0d5529cdd30e954e76ae3d3f2 100644 (file)
@@ -1236,9 +1236,29 @@ 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)
index 2558058dd8bb58880556cbc5950beeb27c1211a2..8317aaaa7ca8856e525920b38d1526a7590bca9e 100644 (file)
@@ -12,6 +12,7 @@
 #include "win32/posix.h"
 #include "win32/buffer.h"
 #include "win32/w32_util.h"
+#include "win32/version.h"
 #else
 #include <dirent.h>
 #endif
@@ -1085,7 +1086,7 @@ int git_path_direach(
 #if defined(GIT_WIN32) && !defined(__MINGW32__)
 
 /* Using _FIND_FIRST_EX_LARGE_FETCH may increase performance in Windows 7
- * and better.  Prior versions will ignore this.
+ * and better.
  */
 #ifndef FIND_FIRST_EX_LARGE_FETCH
 # define FIND_FIRST_EX_LARGE_FETCH 2
@@ -1099,6 +1100,10 @@ int git_path_diriter_init(
        git_win32_path path_filter;
        git_buf hack = {0};
 
+       static int is_win7_or_later = -1;
+       if (is_win7_or_later < 0)
+               is_win7_or_later = git_has_win32_version(6, 1, 0);
+
        assert(diriter && path);
 
        memset(diriter, 0, sizeof(git_path_diriter));
@@ -1122,11 +1127,11 @@ int git_path_diriter_init(
 
        diriter->handle = FindFirstFileExW(
                path_filter,
-               FindExInfoBasic,
+               is_win7_or_later ? FindExInfoBasic : FindExInfoStandard,
                &diriter->current,
                FindExSearchNameMatch,
                NULL,
-               FIND_FIRST_EX_LARGE_FETCH);
+               is_win7_or_later ? FIND_FIRST_EX_LARGE_FETCH : 0);
 
        if (diriter->handle == INVALID_HANDLE_VALUE) {
                giterr_set(GITERR_OS, "Could not open directory '%s'", path);
@@ -1671,3 +1676,19 @@ bool git_path_isvalid(
 
        return verify_component(repo, start, (c - start), flags);
 }
+
+int git_path_normalize_slashes(git_buf *out, const char *path)
+{
+       int error;
+       char *p;
+
+       if ((error = git_buf_puts(out, path)) < 0)
+               return error;
+
+       for (p = out->ptr; *p; p++) {
+               if (*p == '\\')
+                       *p = '/';
+       }
+
+       return 0;
+}
index 5927a53812c12d9f5ac23bae1ade2474d6f989ad..adb76865e989c3b4f22914956c913ca6b3d5bb4a 100644 (file)
@@ -591,4 +591,9 @@ extern bool git_path_isvalid(
        const char *path,
        unsigned int flags);
 
+/**
+ * Convert any backslashes into slashes
+ */
+int git_path_normalize_slashes(git_buf *out, const char *path);
+
 #endif
index e1a77f3ff8db2f757c1b04034646d0c4a83c6a1f..55d535eb4b3ba8eb1a32435b4a93b51e79c9f768 100644 (file)
@@ -63,6 +63,8 @@ typedef struct refdb_fs_backend {
        uint32_t direach_flags;
 } refdb_fs_backend;
 
+static int refdb_reflog_fs__delete(git_refdb_backend *_backend, const char *name);
+
 static int packref_cmp(const void *a_, const void *b_)
 {
        const struct packref *a = a_, *b = b_;
@@ -1217,6 +1219,11 @@ static int refdb_fs_backend__delete(
        if ((error = loose_lock(&file, backend, ref_name)) < 0)
                return error;
 
+       if ((error = refdb_reflog_fs__delete(_backend, ref_name)) < 0) {
+               git_filebuf_cleanup(&file);
+               return error;
+       }
+
        return refdb_fs_backend__delete_tail(_backend, &file, ref_name, old_id, old_target);
 }
 
index 892c983041ad672f20b7d7b78f8e207254e289de..991ebc8f396d4f3bfa2f08c527eb4a358124b6ed 100644 (file)
@@ -781,11 +781,21 @@ const char *git_submodule_url(git_submodule *submodule)
 int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *url)
 {
        int error = 0;
+       git_buf normalized = GIT_BUF_INIT;
 
        assert(out && repo && url);
 
        git_buf_sanitize(out);
 
+       /* We do this in all platforms in case someone on Windows created the .gitmodules */
+       if (strchr(url, '\\')) {
+               if ((error = git_path_normalize_slashes(&normalized, url)) < 0)
+                       return error;
+
+               url = normalized.ptr;
+       }
+
+
        if (git_path_is_relative(url)) {
                if (!(error = get_url_base(out, repo)))
                        error = git_path_apply_relative(out, url);
@@ -796,6 +806,7 @@ int git_submodule_resolve_url(git_buf *out, git_repository *repo, const char *ur
                error = -1;
        }
 
+       git_buf_free(&normalized);
        return error;
 }
 
index 1ed292be5fed87eef3c64a83959e3554e69c117d..e3d90de11a456302a47077666cf363468d43f097 100644 (file)
@@ -255,7 +255,7 @@ static int on_header_ready(http_subtransport *t)
                        GITERR_CHECK_ALLOC(t->content_type);
                }
        }
-       else if (!strcmp("WWW-Authenticate", git_buf_cstr(name))) {
+       else if (!strcasecmp("WWW-Authenticate", git_buf_cstr(name))) {
                char *dup = git__strdup(git_buf_cstr(value));
                GITERR_CHECK_ALLOC(dup);
 
diff --git a/tests/index/bypath.c b/tests/index/bypath.c
new file mode 100644 (file)
index 0000000..ddb766a
--- /dev/null
@@ -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);
+}
index 343ff0f5084ca9936ae26d65283c189c21488703..8807db2319725a8a156808e60513afa16d129e97 100644 (file)
@@ -132,6 +132,8 @@ void test_refs_branches_delete__removes_reflog(void)
        cl_git_pass(git_branch_delete(branch));
        git_reference_free(branch);
 
+       cl_assert_equal_i(false, git_reference_has_log(repo, "refs/heads/track-local"));
+
        /* Reading a nonexistant reflog creates it, but it should be empty */
        cl_git_pass(git_reflog_read(&log, repo, "refs/heads/track-local"));
        cl_assert_equal_i(0, git_reflog_entrycount(log));
index 01625d3aa50fb9220c28c27bd09b662cc3071939..c3b3e63648def71c263bbecdf956beda8fe0c04c 100644 (file)
@@ -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;
 
index 9b2b3aa196438befee753effb6b2c5d83f20a2db..ecea694e511d75735d689ceeaf738c877f5921db 100644 (file)
@@ -151,6 +151,29 @@ void test_submodule_lookup__lookup_even_with_missing_index(void)
        test_submodule_lookup__simple_lookup(); /* baseline should still pass */
 }
 
+void test_submodule_lookup__backslashes(void)
+{
+       git_config *cfg;
+       git_submodule *sm;
+       git_repository *subrepo;
+       git_buf buf = GIT_BUF_INIT;
+       const char *backslashed_path = "..\\submod2_target";
+
+       cl_git_pass(git_config_open_ondisk(&cfg, "submod2/.gitmodules"));
+       cl_git_pass(git_config_set_string(cfg, "submodule.sm_unchanged.url", backslashed_path));
+       git_config_free(cfg);
+
+       cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_unchanged"));
+       cl_assert_equal_s(backslashed_path, git_submodule_url(sm));
+       cl_git_pass(git_submodule_open(&subrepo, sm));
+
+       cl_git_pass(git_submodule_resolve_url(&buf, g_repo, backslashed_path));
+
+       git_buf_free(&buf);
+       git_submodule_free(sm);
+       git_repository_free(subrepo);
+}
+
 static void baseline_tests(void)
 {
        /* small baseline that should work even if we change the index or make