summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.travis.yml2
-rw-r--r--include/git2/branch.h19
-rw-r--r--include/git2/diff.h138
-rw-r--r--include/git2/errors.h2
-rw-r--r--include/git2/object.h11
-rw-r--r--include/git2/refs.h58
-rw-r--r--include/git2/reset.h2
-rw-r--r--include/git2/revwalk.h2
-rw-r--r--include/git2/windows.h59
-rw-r--r--libgit2_clar.supp12
-rw-r--r--src/attr.c1
-rw-r--r--src/branch.c59
-rw-r--r--src/config_file.c1
-rw-r--r--src/diff.c14
-rw-r--r--src/diff.h1
-rw-r--r--src/diff_output.c1015
-rw-r--r--src/fetch.c2
-rw-r--r--src/fileops.c36
-rw-r--r--src/netops.c48
-rw-r--r--src/object.c51
-rw-r--r--src/odb_pack.c2
-rw-r--r--src/path.c5
-rw-r--r--src/pool.h11
-rw-r--r--src/refs.c117
-rw-r--r--src/repository.c4
-rw-r--r--src/reset.c30
-rw-r--r--src/revparse.c2
-rw-r--r--src/revwalk.c50
-rw-r--r--src/signature.c22
-rw-r--r--src/status.c3
-rw-r--r--src/submodule.c1
-rw-r--r--src/tag.c17
-rw-r--r--src/unix/map.c2
-rw-r--r--src/win32/dir.c29
-rw-r--r--src/win32/posix.h9
-rw-r--r--src/win32/posix_w32.c146
-rw-r--r--src/win32/utf-conv.c131
-rw-r--r--src/win32/utf-conv.h7
-rw-r--r--tests-clar/clar_helpers.c27
-rw-r--r--tests-clar/diff/blob.c118
-rw-r--r--tests-clar/diff/diff_helpers.c71
-rw-r--r--tests-clar/diff/diff_helpers.h6
-rw-r--r--tests-clar/diff/diffiter.c116
-rw-r--r--tests-clar/diff/index.c38
-rw-r--r--tests-clar/diff/tree.c72
-rw-r--r--tests-clar/diff/workdir.c485
-rw-r--r--tests-clar/object/peel.c16
-rw-r--r--tests-clar/refs/branches/delete.c43
-rw-r--r--tests-clar/refs/normalize.c346
-rw-r--r--tests-clar/repo/init.c15
-rw-r--r--tests-clar/resources/attr/.gitted/indexbin1856 -> 1856 bytes
-rw-r--r--tests-clar/resources/issue_592/.gitted/indexbin392 -> 392 bytes
-rw-r--r--tests-clar/resources/status/.gitted/indexbin1160 -> 1160 bytes
-rw-r--r--tests-clar/resources/submod2/gitmodules3
-rw-r--r--tests-clar/revwalk/basic.c8
-rw-r--r--tests-clar/submodule/lookup.c6
57 files changed, 2288 insertions, 1204 deletions
diff --git a/.gitignore b/.gitignore
index 45d7b195..7fa7d547 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@ CMake*
*.cmake
.DS_Store
*~
+tags
diff --git a/.travis.yml b/.travis.yml
index 29ef9d40..54da48a4 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -32,7 +32,7 @@ script:
# Run Tests
after_script:
- ctest -V .
- - if [ -f ./libgit2_clar ]; then valgrind --leak-check=full --show-reachable=yes ./libgit2_clar; else echo "Skipping valgrind"; fi
+ - if [ -f ./libgit2_clar ]; then valgrind --leak-check=full --show-reachable=yes --suppressions=../libgit2_clar.supp ./libgit2_clar; else echo "Skipping valgrind"; fi
# Only watch the development branch
branches:
diff --git a/include/git2/branch.h b/include/git2/branch.h
index 8bf7eb9d..f072799c 100644
--- a/include/git2/branch.h
+++ b/include/git2/branch.h
@@ -8,6 +8,7 @@
#define INCLUDE_git_branch_h__
#include "common.h"
+#include "oid.h"
#include "types.h"
/**
@@ -55,21 +56,13 @@ GIT_EXTERN(int) git_branch_create(
/**
* Delete an existing branch reference.
*
- * @param repo Repository where lives the branch.
+ * If the branch is successfully deleted, the passed reference
+ * object will be freed and invalidated.
*
- * @param branch_name Name of the branch to be deleted;
- * this name is validated for consistency.
- *
- * @param branch_type Type of the considered branch. This should
- * be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE.
- *
- * @return 0 on success, GIT_ENOTFOUND if the branch
- * doesn't exist or an error code.
+ * @param branch A valid reference representing a branch
+ * @return 0 on success, or an error code.
*/
-GIT_EXTERN(int) git_branch_delete(
- git_repository *repo,
- const char *branch_name,
- git_branch_t branch_type);
+GIT_EXTERN(int) git_branch_delete(git_reference *branch);
/**
* Loop over all the branches and issue a callback for each one.
diff --git a/include/git2/diff.h b/include/git2/diff.h
index 088e1ecf..85bb308d 100644
--- a/include/git2/diff.h
+++ b/include/git2/diff.h
@@ -169,7 +169,7 @@ enum {
GIT_DIFF_LINE_CONTEXT = ' ',
GIT_DIFF_LINE_ADDITION = '+',
GIT_DIFF_LINE_DELETION = '-',
- GIT_DIFF_LINE_ADD_EOFNL = '\n', /**< DEPRECATED */
+ GIT_DIFF_LINE_ADD_EOFNL = '\n', /**< DEPRECATED - will not be returned */
GIT_DIFF_LINE_DEL_EOFNL = '\0', /**< LF was removed at end of file */
/* The following values will only be sent to a `git_diff_data_fn` when
@@ -197,6 +197,11 @@ typedef int (*git_diff_data_fn)(
const char *content,
size_t content_len);
+/**
+ * The diff iterator object is used to scan a diff list.
+ */
+typedef struct git_diff_iterator git_diff_iterator;
+
/** @name Diff List Generator Functions
*
* These are the functions you would use to create (or destroy) a
@@ -354,6 +359,137 @@ GIT_EXTERN(int) git_diff_foreach(
git_diff_data_fn line_cb);
/**
+ * Create a diff iterator object that can be used to traverse a diff.
+ *
+ * This iterator can be used instead of `git_diff_foreach` in situations
+ * where callback functions are awkward to use. Because of the way that
+ * diffs are calculated internally, using an iterator will use somewhat
+ * more memory than `git_diff_foreach` would.
+ *
+ * @param iterator Output parameter of newly created iterator.
+ * @param diff Diff over which you wish to iterate.
+ * @return 0 on success, < 0 on error
+ */
+GIT_EXTERN(int) git_diff_iterator_new(
+ git_diff_iterator **iterator,
+ git_diff_list *diff);
+
+/**
+ * Release the iterator object.
+ *
+ * Call this when you are done using the iterator.
+ *
+ * @param iterator The diff iterator to be freed.
+ */
+GIT_EXTERN(void) git_diff_iterator_free(git_diff_iterator *iterator);
+
+/**
+ * Return the number of files in the diff.
+ *
+ * Note that there is an uncommon scenario where this number might be too
+ * high -- if a file in the working directory has been "touched" on disk but
+ * the contents were then reverted, it might have been added to the
+ * `git_diff_list` as a MODIFIED file along with a note that the status
+ * needs to be confirmed when the file contents are loaded into memory. In
+ * that case, when the file is loaded, we will check the contents and might
+ * switch it back to UNMODIFIED. The loading of the file is deferred until
+ * as late as possible. As a result, this might return a value what was too
+ * high in those circumstances.
+ *
+ * This is true of `git_diff_foreach` as well, but the only implication
+ * there is that the `progress` value would not advance evenly.
+ *
+ * @param iterator The iterator object
+ * @return The maximum number of files to be iterated over
+ */
+GIT_EXTERN(int) git_diff_iterator_num_files(git_diff_iterator *iterator);
+
+/**
+ * Return the number of hunks in the current file
+ *
+ * This will return the number of diff hunks in the current file. If the
+ * diff has not been performed yet, this may result in loading the file and
+ * performing the diff.
+ *
+ * @param iterator The iterator object
+ * @return The number of hunks in the current file or <0 on loading failure
+ */
+GIT_EXTERN(int) git_diff_iterator_num_hunks_in_file(git_diff_iterator *iterator);
+
+/**
+ * Return the number of lines in the hunk currently being examined.
+ *
+ * This will return the number of lines in the current hunk. If the diff
+ * has not been performed yet, this may result in loading the file and
+ * performing the diff.
+ *
+ * @param iterator The iterator object
+ * @return The number of lines in the current hunk (context, added, and
+ * removed all added together) or <0 on loading failure
+ */
+GIT_EXTERN(int) git_diff_iterator_num_lines_in_hunk(git_diff_iterator *iterator);
+
+/**
+ * Return the delta information for the next file in the diff.
+ *
+ * This will return a pointer to the next git_diff_delta` to be processed or
+ * NULL if the iterator is at the end of the diff, then advance. This
+ * returns the value `GIT_ITEROVER` after processing the last file.
+ *
+ * @param delta Output parameter for the next delta object
+ * @param iterator The iterator object
+ * @return 0 on success, GIT_ITEROVER when done, other value < 0 on error
+ */
+GIT_EXTERN(int) git_diff_iterator_next_file(
+ git_diff_delta **delta,
+ git_diff_iterator *iterator);
+
+/**
+ * Return the hunk information for the next hunk in the current file.
+ *
+ * It is recommended that you not call this if the file is a binary
+ * file, but it is allowed to do so.
+ *
+ * Warning! Call this function for the first time on a file is when the
+ * actual text diff will be computed (it cannot be computed incrementally)
+ * so the first call for a new file is expensive (at least in relative
+ * terms - in reality, it is still pretty darn fast).
+ *
+ * @param range Pointer where to store the range for the hunk
+ * @param header Pointer where to store the header for the chunk;
+ * this string is owned by the library and should not be freed by
+ * the user
+ * @param header_len Pointer where to store the length of the returned header
+ * @param iterator The iterator object
+ * @return 0 on success, GIT_ITEROVER when done with current file, other
+ * value < 0 on error
+ */
+GIT_EXTERN(int) git_diff_iterator_next_hunk(
+ git_diff_range **range,
+ const char **header,
+ size_t *header_len,
+ git_diff_iterator *iterator);
+
+/**
+ * Return the next line of the current hunk of diffs.
+ *
+ * @param line_origin Pointer where to store a GIT_DIFF_LINE_ value;
+ * this value is a single character, not a buffer
+ * @param content Pointer where to store the content of the line;
+ * this string is owned by the library and should not be freed by
+ * the user
+ * @param Pointer where to store the length of the returned content
+ * @param iterator The iterator object
+ * @return 0 on success, GIT_ITEROVER when done with current line, other
+ * value < 0 on error
+ */
+GIT_EXTERN(int) git_diff_iterator_next_line(
+ char *line_origin, /**< GIT_DIFF_LINE_... value from above */
+ const char **content,
+ size_t *content_len,
+ git_diff_iterator *iterator);
+
+/**
* Iterate over a diff generating text output like "git diff --name-status".
*
* Returning a non-zero value from the callbacks will terminate the
diff --git a/include/git2/errors.h b/include/git2/errors.h
index b55f8c30..f6671c49 100644
--- a/include/git2/errors.h
+++ b/include/git2/errors.h
@@ -28,7 +28,7 @@ enum {
GIT_EUSER = -7,
GIT_PASSTHROUGH = -30,
- GIT_REVWALKOVER = -31,
+ GIT_ITEROVER = -31,
};
typedef struct {
diff --git a/include/git2/object.h b/include/git2/object.h
index 722434de..fd6ae95c 100644
--- a/include/git2/object.h
+++ b/include/git2/object.h
@@ -168,11 +168,14 @@ GIT_EXTERN(int) git_object_typeisloose(git_otype type);
GIT_EXTERN(size_t) git_object__size(git_otype type);
/**
- * Recursively peel an object until an object of the specified
- * type is met
+ * Recursively peel an object until an object of the specified type is met.
*
- * The retrieved `peeled` object is owned by the repository
- * and should be closed with the `git_object_free` method.
+ * The retrieved `peeled` object is owned by the repository and should be
+ * closed with the `git_object_free` method.
+ *
+ * If you pass `GIT_OBJ_ANY` as the target type, then the object will be
+ * peeled until the type changes (e.g. a tag will be chased until the
+ * referenced object is no longer a tag).
*
* @param peeled Pointer to the peeled git_object
* @param object The object to be processed
diff --git a/include/git2/refs.h b/include/git2/refs.h
index 9e706007..660b48b5 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -376,6 +376,64 @@ GIT_EXTERN(int) git_reference_has_log(git_reference *ref);
*/
GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
+/**
+ * Check if a reference is a remote tracking branch
+ *
+ * @param ref A git reference
+ *
+ * @return 1 when the reference lives in the refs/remotes
+ * namespace; 0 otherwise.
+ */
+GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
+
+enum {
+ GIT_REF_FORMAT_NORMAL = 0,
+
+ /**
+ * Control whether one-level refnames are accepted
+ * (i.e., refnames that do not contain multiple /-separated
+ * components)
+ */
+ GIT_REF_FORMAT_ALLOW_ONELEVEL = (1 << 0),
+
+ /**
+ * Interpret the provided name as a reference pattern for a
+ * refspec (as used with remote repositories). If this option
+ * is enabled, the name is allowed to contain a single * (<star>)
+ * in place of a one full pathname component
+ * (e.g., foo/<star>/bar but not foo/bar<star>).
+ */
+ GIT_REF_FORMAT_REFSPEC_PATTERN = (1 << 1),
+};
+
+/**
+ * Normalize the reference name by removing any leading
+ * slash (/) characters and collapsing runs of adjacent slashes
+ * between name components into a single slash.
+ *
+ * Once normalized, if the reference name is valid, it will be
+ * returned in the user allocated buffer.
+ *
+ * TODO: Implement handling of GIT_REF_FORMAT_REFSPEC_PATTERN
+ *
+ * @param buffer_out The user allocated buffer where the
+ * normalized name will be stored.
+ *
+ * @param buffer_size buffer_out size
+ *
+ * @param name name to be checked.
+ *
+ * @param flags Flags to determine the options to be applied while
+ * checking the validatity of the name.
+ *
+ * @return 0 or an error code.
+ */
+GIT_EXTERN(int) git_reference_normalize_name(
+ char *buffer_out,
+ size_t buffer_size,
+ const char *name,
+ unsigned int flags);
+
/** @} */
GIT_END_DECL
#endif
diff --git a/include/git2/reset.h b/include/git2/reset.h
index 12517874..cd263fa9 100644
--- a/include/git2/reset.h
+++ b/include/git2/reset.h
@@ -37,7 +37,7 @@ GIT_BEGIN_DECL
*
* @return GIT_SUCCESS or an error code
*/
-GIT_EXTERN(int) git_reset(git_repository *repo, const git_object *target, git_reset_type reset_type);
+GIT_EXTERN(int) git_reset(git_repository *repo, git_object *target, git_reset_type reset_type);
/** @} */
GIT_END_DECL
diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h
index d86bb28e..0a85a4c6 100644
--- a/include/git2/revwalk.h
+++ b/include/git2/revwalk.h
@@ -201,7 +201,7 @@ GIT_EXTERN(int) git_revwalk_hide_ref(git_revwalk *walk, const char *refname);
* @param oid Pointer where to store the oid of the next commit
* @param walk the walker to pop the commit from.
* @return 0 if the next commit was found;
- * GIT_REVWALKOVER if there are no commits left to iterate
+ * GIT_ITEROVER if there are no commits left to iterate
*/
GIT_EXTERN(int) git_revwalk_next(git_oid *oid, git_revwalk *walk);
diff --git a/include/git2/windows.h b/include/git2/windows.h
deleted file mode 100644
index 8b743f0a..00000000
--- a/include/git2/windows.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2009-2012 the libgit2 contributors
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_git_windows_h__
-#define INCLUDE_git_windows_h__
-
-#include "common.h"
-
-/**
- * @file git2/windows.h
- * @brief Windows-specific functions
- * @ingroup Git
- * @{
- */
-GIT_BEGIN_DECL
-
-/**
- * Set the active codepage for Windows syscalls
- *
- * All syscalls performed by the library will assume
- * this codepage when converting paths and strings
- * to use by the Windows kernel.
- *
- * The default value of UTF-8 will work automatically
- * with most Git repositories created on Unix systems.
- *
- * This settings needs only be changed when working
- * with repositories that contain paths in specific,
- * non-UTF codepages.
- *
- * A full list of all available codepage identifiers may
- * be found at:
- *
- * http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx
- *
- * @param codepage numeric codepage identifier
- */
-GIT_EXTERN(void) gitwin_set_codepage(unsigned int codepage);
-
-/**
- * Return the active codepage for Windows syscalls
- *
- * @return numeric codepage identifier
- */
-GIT_EXTERN(unsigned int) gitwin_get_codepage(void);
-
-/**
- * Set the active Windows codepage to UTF-8 (this is
- * the default value)
- */
-GIT_EXTERN(void) gitwin_set_utf8(void);
-
-/** @} */
-GIT_END_DECL
-#endif
-
diff --git a/libgit2_clar.supp b/libgit2_clar.supp
new file mode 100644
index 00000000..f49eb005
--- /dev/null
+++ b/libgit2_clar.supp
@@ -0,0 +1,12 @@
+{
+ ignore-zlib-errors-cond
+ Memcheck:Cond
+ obj:*libz.so*
+}
+
+{
+ ignore-giterr-set-leak
+ Memcheck:Leak
+ ...
+ fun:giterr_set
+}
diff --git a/src/attr.c b/src/attr.c
index 99322066..68f8d7de 100644
--- a/src/attr.c
+++ b/src/attr.c
@@ -188,6 +188,7 @@ int git_attr_foreach(
error = callback(assign->name, assign->value, payload);
if (error) {
+ giterr_clear();
error = GIT_EUSER;
goto cleanup;
}
diff --git a/src/branch.c b/src/branch.c
index 52fed67a..cd5c10ed 100644
--- a/src/branch.c
+++ b/src/branch.c
@@ -50,6 +50,12 @@ static int create_error_invalid(const char *msg)
return -1;
}
+static int not_a_local_branch(git_reference *ref)
+{
+ giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
+ return -1;
+}
+
int git_branch_create(
git_reference **ref_out,
git_repository *repository,
@@ -57,7 +63,6 @@ int git_branch_create(
const git_object *target,
int force)
{
- git_otype target_type = GIT_OBJ_BAD;
git_object *commit = NULL;
git_reference *branch = NULL;
git_buf canonical_branch_name = GIT_BUF_INIT;
@@ -66,27 +71,8 @@ int git_branch_create(
assert(branch_name && target && ref_out);
assert(git_object_owner(target) == repository);
- target_type = git_object_type(target);
-
- switch (target_type)
- {
- case GIT_OBJ_TAG:
- if (git_tag_peel(&commit, (git_tag *)target) < 0)
- goto cleanup;
-
- if (git_object_type(commit) != GIT_OBJ_COMMIT) {
- create_error_invalid("The given target does not resolve to a commit");
- goto cleanup;
- }
- break;
-
- case GIT_OBJ_COMMIT:
- commit = (git_object *)target;
- break;
-
- default:
- return create_error_invalid("Only git_tag and git_commit objects are valid targets.");
- }
+ if (git_object_peel(&commit, (git_object *)target, GIT_OBJ_COMMIT) < 0)
+ return create_error_invalid("The given target does not resolve to a commit");
if (git_buf_joinpath(&canonical_branch_name, GIT_REFS_HEADS_DIR, branch_name) < 0)
goto cleanup;
@@ -99,26 +85,24 @@ int git_branch_create(
error = 0;
cleanup:
- if (target_type == GIT_OBJ_TAG)
- git_object_free(commit);
-
+ git_object_free(commit);
git_buf_free(&canonical_branch_name);
return error;
}
-int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_t branch_type)
+int git_branch_delete(git_reference *branch)
{
- git_reference *branch = NULL;
git_reference *head = NULL;
- int error;
- assert(repo && branch_name);
- assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE));
+ assert(branch);
- if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0)
- return error;
+ if (!git_reference_is_branch(branch) &&
+ !git_reference_is_remote(branch)) {
+ giterr_set(GITERR_INVALID, "Reference '%s' is not a valid branch.", git_reference_name(branch));
+ return -1;
+ }
- if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) {
+ if (git_reference_lookup(&head, git_reference_owner(branch), GIT_HEAD_FILE) < 0) {
giterr_set(GITERR_REFERENCE, "Cannot locate HEAD.");
goto on_error;
}
@@ -126,7 +110,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
if ((git_reference_type(head) == GIT_REF_SYMBOLIC)
&& (strcmp(git_reference_target(head), git_reference_name(branch)) == 0)) {
giterr_set(GITERR_REFERENCE,
- "Cannot delete branch '%s' as it is the current HEAD of the repository.", branch_name);
+ "Cannot delete branch '%s' as it is the current HEAD of the repository.", git_reference_name(branch));
goto on_error;
}
@@ -138,7 +122,6 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_
on_error:
git_reference_free(head);
- git_reference_free(branch);
return -1;
}
@@ -185,12 +168,6 @@ int git_branch_foreach(
return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter);
}
-static int not_a_local_branch(git_reference *ref)
-{
- giterr_set(GITERR_INVALID, "Reference '%s' is not a local branch.", git_reference_name(ref));
- return -1;
-}
-
int git_branch_move(
git_reference *branch,
const char *new_branch_name,
diff --git a/src/config_file.c b/src/config_file.c
index d3fb56aa..c575649a 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -221,6 +221,7 @@ static int file_foreach(
/* abort iterator on non-zero return value */
if (fn(key, var->value, data)) {
+ giterr_clear();
result = GIT_EUSER;
goto cleanup;
}
diff --git a/src/diff.c b/src/diff.c
index 430f52e0..f8a01086 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -316,6 +316,7 @@ static git_diff_list *git_diff_list_alloc(
if (diff == NULL)
return NULL;
+ GIT_REFCOUNT_INC(diff);
diff->repo = repo;
if (git_vector_init(&diff->deltas, 0, diff_delta__cmp) < 0 ||
@@ -391,15 +392,12 @@ fail:
return NULL;
}
-void git_diff_list_free(git_diff_list *diff)
+static void diff_list_free(git_diff_list *diff)
{
git_diff_delta *delta;
git_attr_fnmatch *match;
unsigned int i;
- if (!diff)
- return;
-
git_vector_foreach(&diff->deltas, i, delta) {
git__free(delta);
diff->deltas.contents[i] = NULL;
@@ -416,6 +414,14 @@ void git_diff_list_free(git_diff_list *diff)
git__free(diff);
}
+void git_diff_list_free(git_diff_list *diff)
+{
+ if (!diff)
+ return;
+
+ GIT_REFCOUNT_DEC(diff, diff_list_free);
+}
+
static int oid_for_workdir_item(
git_repository *repo,
const git_index_entry *item,
diff --git a/src/diff.h b/src/diff.h
index 6cc854fb..2785fa42 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -26,6 +26,7 @@ enum {
};
struct git_diff_list {
+ git_refcount rc;
git_repository *repo;
git_diff_options opts;
git_vector pathspec;
diff --git a/src/diff_output.c b/src/diff_output.c
index 2bf939f3..2c64b92e 100644
--- a/src/diff_output.c
+++ b/src/diff_output.c
@@ -16,16 +16,35 @@
#include "fileops.h"
#include "filter.h"
+/*
+ * A diff_delta_context represents all of the information that goes into
+ * processing the diff of an observed file change. In the case of the
+ * git_diff_foreach() call it is an emphemeral structure that is filled
+ * in to execute each diff. In the case of a git_diff_iterator, it holds
+ * most of the information for the diff in progress.
+ */
typedef struct {
- git_diff_list *diff;
- void *cb_data;
- git_diff_hunk_fn hunk_cb;
- git_diff_data_fn line_cb;
- unsigned int index;
+ git_repository *repo;
+ git_diff_options *opts;
+ xdemitconf_t xdiff_config;
+ xpparam_t xdiff_params;
git_diff_delta *delta;
+ uint32_t prepped : 1;
+ uint32_t loaded : 1;
+ uint32_t diffable : 1;
+ uint32_t diffed : 1;
+ git_iterator_type_t old_src;
+ git_iterator_type_t new_src;
+ git_blob *old_blob;
+ git_blob *new_blob;
+ git_map old_data;
+ git_map new_data;
+ void *cb_data;
+ git_diff_hunk_fn per_hunk;
+ git_diff_data_fn per_line;
+ int cb_error;
git_diff_range range;
- int error;
-} diff_output_info;
+} diff_delta_context;
static int read_next_int(const char **str, int *value)
{
@@ -41,71 +60,89 @@ static int read_next_int(const char **str, int *value)
return (digits > 0) ? 0 : -1;
}
-static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len)
+static int parse_hunk_header(git_diff_range *range, const char *header)
{
- diff_output_info *info = priv;
-
- if (len == 1 && info->hunk_cb) {
- git_diff_range range = { -1, 0, -1, 0 };
- const char *scan = bufs[0].ptr;
+ /* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */
+ if (*header != '@')
+ return -1;
+ if (read_next_int(&header, &range->old_start) < 0)
+ return -1;
+ if (*header == ',') {
+ if (read_next_int(&header, &range->old_lines) < 0)
+ return -1;
+ } else
+ range->old_lines = 1;
+ if (read_next_int(&header, &range->new_start) < 0)
+ return -1;
+ if (*header == ',') {
+ if (read_next_int(&header, &range->new_lines) < 0)
+ return -1;
+ } else
+ range->new_lines = 1;
+ if (range->old_start < 0 || range->new_start < 0)
+ return -1;
- /* expect something of the form "@@ -%d[,%d] +%d[,%d] @@" */
- if (*scan != '@')
- info->error = -1;
- else if (read_next_int(&scan, &range.old_start) < 0)
- info->error = -1;
- else if (*scan == ',' && read_next_int(&scan, &range.old_lines) < 0)
- info->error = -1;
- else if (read_next_int(&scan, &range.new_start) < 0)
- info->error = -1;
- else if (*scan == ',' && read_next_int(&scan, &range.new_lines) < 0)
- info->error = -1;
- else if (range.old_start < 0 || range.new_start < 0)
- info->error = -1;
- else {
- memcpy(&info->range, &range, sizeof(git_diff_range));
+ return 0;
+}
- if (info->hunk_cb(
- info->cb_data, info->delta, &range, bufs[0].ptr, bufs[0].size))
- info->error = GIT_EUSER;
- }
+static int format_hunk_header(char *header, size_t len, git_diff_range *range)
+{
+ if (range->old_lines != 1) {
+ if (range->new_lines != 1)
+ return p_snprintf(
+ header, len, "@@ -%d,%d +%d,%d @@",
+ range->old_start, range->old_lines,
+ range->new_start, range->new_lines);
+ else
+ return p_snprintf(
+ header, len, "@@ -%d,%d +%d @@",
+ range->old_start, range->old_lines, range->new_start);
+ } else {
+ if (range->new_lines != 1)
+ return p_snprintf(
+ header, len, "@@ -%d +%d,%d @@",
+ range->old_start, range->new_start, range->new_lines);
+ else
+ return p_snprintf(
+ header, len, "@@ -%d +%d @@",
+ range->old_start, range->new_start);
}
+}
- if ((len == 2 || len == 3) && info->line_cb) {
- int origin;
-
- /* expect " "/"-"/"+", then data, then maybe newline */
- origin =
- (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_ADDITION :
- (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_DELETION :
- GIT_DIFF_LINE_CONTEXT;
+static bool diff_delta_is_ambiguous(git_diff_delta *delta)
+{
+ return (git_oid_iszero(&delta->new_file.oid) &&
+ (delta->new_file.flags & GIT_DIFF_FILE_VALID_OID) == 0 &&
+ delta->status == GIT_DELTA_MODIFIED);
+}
- if (info->line_cb(
- info->cb_data, info->delta, &info->range, origin, bufs[1].ptr, bufs[1].size))
- info->error = GIT_EUSER;
+static bool diff_delta_should_skip(git_diff_options *opts, git_diff_delta *delta)
+{
+ if (delta->status == GIT_DELTA_UNMODIFIED &&
+ (opts->flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
+ return true;
- /* This should only happen if we are adding a line that does not
- * have a newline at the end and the old code did. In that case,
- * we have a ADD with a DEL_EOFNL as a pair.
- */
- else if (len == 3) {
- origin = (origin == GIT_DIFF_LINE_ADDITION) ?
- GIT_DIFF_LINE_DEL_EOFNL : GIT_DIFF_LINE_ADD_EOFNL;
+ if (delta->status == GIT_DELTA_IGNORED &&
+ (opts->flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
+ return true;
- if (info->line_cb(
- info->cb_data, info->delta, &info->range, origin, bufs[2].ptr, bufs[2].size))
- info->error = GIT_EUSER;
- }
- }
+ if (delta->status == GIT_DELTA_UNTRACKED &&
+ (opts->flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
+ return true;
- return info->error;
+ return false;
}
#define BINARY_DIFF_FLAGS (GIT_DIFF_FILE_BINARY|GIT_DIFF_FILE_NOT_BINARY)
-static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file)
+static int update_file_is_binary_by_attr(
+ git_repository *repo, git_diff_file *file)
{
const char *value;
+
+ if (!repo)
+ return 0;
+
if (git_attr_get(&value, repo, 0, file->path, "diff") < 0)
return -1;
@@ -129,11 +166,10 @@ static void update_delta_is_binary(git_diff_delta *delta)
/* otherwise leave delta->binary value untouched */
}
-static int file_is_binary_by_attr(
- git_diff_list *diff,
- git_diff_delta *delta)
+static int diff_delta_is_binary_by_attr(diff_delta_context *ctxt)
{
int error = 0, mirror_new;
+ git_diff_delta *delta = ctxt->delta;
delta->binary = -1;
@@ -148,7 +184,7 @@ static int file_is_binary_by_attr(
}
/* check if user is forcing us to text diff these files */
- if (diff->opts.flags & GIT_DIFF_FORCE_TEXT) {
+ if (ctxt->opts->flags & GIT_DIFF_FORCE_TEXT) {
delta->old_file.flags |= GIT_DIFF_FILE_NOT_BINARY;
delta->new_file.flags |= GIT_DIFF_FILE_NOT_BINARY;
delta->binary = 0;
@@ -156,7 +192,7 @@ static int file_is_binary_by_attr(
}
/* check diff attribute +, -, or 0 */
- if (update_file_is_binary_by_attr(diff->repo, &delta->old_file) < 0)
+ if (update_file_is_binary_by_attr(ctxt->repo, &delta->old_file) < 0)
return -1;
mirror_new = (delta->new_file.path == delta->old_file.path ||
@@ -164,23 +200,21 @@ static int file_is_binary_by_attr(
if (mirror_new)
delta->new_file.flags |= (delta->old_file.flags & BINARY_DIFF_FLAGS);
else
- error = update_file_is_binary_by_attr(diff->repo, &delta->new_file);
+ error = update_file_is_binary_by_attr(ctxt->repo, &delta->new_file);
update_delta_is_binary(delta);
return error;
}
-static int file_is_binary_by_content(
- git_diff_delta *delta,
- git_map *old_data,
- git_map *new_data)
+static int diff_delta_is_binary_by_content(diff_delta_context *ctxt)
{
+ git_diff_delta *delta = ctxt->delta;
git_buf search;
if ((delta->old_file.flags & BINARY_DIFF_FLAGS) == 0) {
- search.ptr = old_data->data;
- search.size = min(old_data->len, 4000);
+ search.ptr = ctxt->old_data.data;
+ search.size = min(ctxt->old_data.len, 4000);
if (git_buf_is_binary(&search))
delta->old_file.flags |= GIT_DIFF_FILE_BINARY;
@@ -189,8 +223,8 @@ static int file_is_binary_by_content(
}
if ((delta->new_file.flags & BINARY_DIFF_FLAGS) == 0) {
- search.ptr = new_data->data;
- search.size = min(new_data->len, 4000);
+ search.ptr = ctxt->new_data.data;
+ search.size = min(ctxt->new_data.len, 4000);
if (git_buf_is_binary(&search))
delta->new_file.flags |= GIT_DIFF_FILE_BINARY;
@@ -256,16 +290,21 @@ static int get_workdir_content(
return -1;
if (S_ISLNK(file->mode)) {
- ssize_t read_len;
+ ssize_t alloc_len, read_len;
file->flags |= GIT_DIFF_FILE_FREE_DATA;
file->flags |= GIT_DIFF_FILE_BINARY;
- map->data = git__malloc((size_t)file->size + 1);
+ /* link path on disk could be UTF-16, so prepare a buffer that is
+ * big enough to handle some UTF-8 data expansion
+ */
+ alloc_len = (ssize_t)(file->size * 2) + 1;
+
+ map->data = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(map->data);
- read_len = p_readlink(path.ptr, map->data, (size_t)file->size + 1);
- if (read_len != (ssize_t)file->size) {
+ read_len = p_readlink(path.ptr, map->data, (int)alloc_len);
+ if (read_len < 0) {
giterr_set(GITERR_OS, "Failed to read symlink '%s'", file->path);
error = -1;
} else
@@ -286,189 +325,304 @@ static void release_content(git_diff_file *file, git_map *map, git_blob *blob)
if (file->flags & GIT_DIFF_FILE_FREE_DATA) {
git__free(map->data);
- map->data = NULL;
+ map->data = "";
+ map->len = 0;
file->flags &= ~GIT_DIFF_FILE_FREE_DATA;
}
else if (file->flags & GIT_DIFF_FILE_UNMAP_DATA) {
git_futils_mmap_free(map);
- map->data = NULL;
+ map->data = "";
+ map->len = 0;
file->flags &= ~GIT_DIFF_FILE_UNMAP_DATA;
}
}
-static void fill_map_from_mmfile(git_map *dst, mmfile_t *src) {
- assert(dst && src);
+static void diff_delta_init_context(
+ diff_delta_context *ctxt,
+ git_repository *repo,
+ git_diff_options *opts,
+ git_iterator_type_t old_src,
+ git_iterator_type_t new_src)
+{
+ memset(ctxt, 0, sizeof(diff_delta_context));
+
+ ctxt->repo = repo;
+ ctxt->opts = opts;
+ ctxt->old_src = old_src;
+ ctxt->new_src = new_src;
- dst->data = src->ptr;
- dst->len = src->size;
-#ifdef GIT_WIN32
- dst->fmh = NULL;
-#endif
+ setup_xdiff_options(opts, &ctxt->xdiff_config, &ctxt->xdiff_params);
}
-int git_diff_foreach(
- git_diff_list *diff,
- void *data,
- git_diff_file_fn file_cb,
- git_diff_hunk_fn hunk_cb,
- git_diff_data_fn line_cb)
+static void diff_delta_init_context_from_diff_list(
+ diff_delta_context *ctxt,
+ git_diff_list *diff)
{
- int error = 0;
- diff_output_info info;
- git_diff_delta *delta;
- xpparam_t xdiff_params;
- xdemitconf_t xdiff_config;
- xdemitcb_t xdiff_callback;
+ diff_delta_init_context(
+ ctxt, diff->repo, &diff->opts, diff->old_src, diff->new_src);
+}
- memset(&info, 0, sizeof(info));
- info.diff = diff;
- info.cb_data = data;
- info.hunk_cb = hunk_cb;
- info.line_cb = line_cb;
+static void diff_delta_unload(diff_delta_context *ctxt)
+{
+ ctxt->diffed = 0;
- setup_xdiff_options(&diff->opts, &xdiff_config, &xdiff_params);
- memset(&xdiff_callback, 0, sizeof(xdiff_callback));
- xdiff_callback.outf = diff_output_cb;
- xdiff_callback.priv = &info;
+ if (ctxt->loaded) {
+ release_content(&ctxt->delta->old_file, &ctxt->old_data, ctxt->old_blob);
+ release_content(&ctxt->delta->new_file, &ctxt->new_data, ctxt->new_blob);
+ ctxt->loaded = 0;
+ }
- git_vector_foreach(&diff->deltas, info.index, delta) {
- git_blob *old_blob = NULL, *new_blob = NULL;
- git_map old_data, new_data;
- mmfile_t old_xdiff_data, new_xdiff_data;
+ ctxt->delta = NULL;
+ ctxt->prepped = 0;
+}
- if (delta->status == GIT_DELTA_UNMODIFIED &&
- (diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
- continue;
+static int diff_delta_prep(diff_delta_context *ctxt)
+{
+ int error;
- if (delta->status == GIT_DELTA_IGNORED &&
- (diff->opts.flags & GIT_DIFF_INCLUDE_IGNORED) == 0)
- continue;
+ if (ctxt->prepped || !ctxt->delta)
+ return 0;
- if (delta->status == GIT_DELTA_UNTRACKED &&
- (diff->opts.flags & GIT_DIFF_INCLUDE_UNTRACKED) == 0)
- continue;
+ error = diff_delta_is_binary_by_attr(ctxt);
- if ((error = file_is_binary_by_attr(diff, delta)) < 0)
- goto cleanup;
+ ctxt->prepped = !error;
- old_data.data = "";
- old_data.len = 0;
- new_data.data = "";
- new_data.len = 0;
+ return error;
+}
- /* TODO: Partial blob reading to defer loading whole blob.
- * I.e. I want a blob with just the first 4kb loaded, then
- * later on I will read the rest of the blob if needed.
- */
+static int diff_delta_load(diff_delta_context *ctxt)
+{
+ int error = 0;
+ git_diff_delta *delta = ctxt->delta;
- /* map files */
- if (delta->binary != 1 &&
- (hunk_cb || line_cb || git_oid_iszero(&delta->old_file.oid)) &&
- (delta->status == GIT_DELTA_DELETED ||
- delta->status == GIT_DELTA_MODIFIED))
- {
- if (diff->old_src == GIT_ITERATOR_WORKDIR)
- error = get_workdir_content(diff->repo, &delta->old_file, &old_data);
- else
- error = get_blob_content(
- diff->repo, &delta->old_file.oid, &old_data, &old_blob);
+ if (ctxt->loaded || !ctxt->delta)
+ return 0;
- if (error < 0)
- goto cleanup;
+ if (!ctxt->prepped && (error = diff_delta_prep(ctxt)) < 0)
+ goto cleanup;
+
+ ctxt->old_data.data = "";
+ ctxt->old_data.len = 0;
+ ctxt->old_blob = NULL;
+
+ if (!error && delta->binary != 1 &&
+ (delta->status == GIT_DELTA_DELETED ||
+ delta->status == GIT_DELTA_MODIFIED))
+ {
+ if (ctxt->old_src == GIT_ITERATOR_WORKDIR)
+ error = get_workdir_content(
+ ctxt->repo, &delta->old_file, &ctxt->old_data);
+ else {
+ error = get_blob_content(
+ ctxt->repo, &delta->old_file.oid,
+ &ctxt->old_data, &ctxt->old_blob);
+
+ if (ctxt->new_src == GIT_ITERATOR_WORKDIR) {
+ /* TODO: convert crlf of blob content */
+ }
}
+ }
- if (delta->binary != 1 &&
- (hunk_cb || line_cb || git_oid_iszero(&delta->new_file.oid)) &&
- (delta->status == GIT_DELTA_ADDED ||
- delta->status == GIT_DELTA_MODIFIED))
- {
- if (diff->new_src == GIT_ITERATOR_WORKDIR)
- error = get_workdir_content(diff->repo, &delta->new_file, &new_data);
- else
- error = get_blob_content(
- diff->repo, &delta->new_file.oid, &new_data, &new_blob);
+ ctxt->new_data.data = "";
+ ctxt->new_data.len = 0;
+ ctxt->new_blob = NULL;
+
+ if (!error && delta->binary != 1 &&
+ (delta->status == GIT_DELTA_ADDED ||
+ delta->status == GIT_DELTA_MODIFIED))
+ {
+ if (ctxt->new_src == GIT_ITERATOR_WORKDIR)
+ error = get_workdir_content(
+ ctxt->repo, &delta->new_file, &ctxt->new_data);
+ else {
+ error = get_blob_content(
+ ctxt->repo, &delta->new_file.oid,
+ &ctxt->new_data, &ctxt->new_blob);
+ if (ctxt->old_src == GIT_ITERATOR_WORKDIR) {
+ /* TODO: convert crlf of blob content */
+ }
+ }
+
+ if (!error && !(delta->new_file.flags & GIT_DIFF_FILE_VALID_OID)) {
+ error = git_odb_hash(
+ &delta->new_file.oid, ctxt->new_data.data,
+ ctxt->new_data.len, GIT_OBJ_BLOB);
if (error < 0)
goto cleanup;
- if ((delta->new_file.flags & GIT_DIFF_FILE_VALID_OID) == 0) {
- error = git_odb_hash(
- &delta->new_file.oid, new_data.data, new_data.len, GIT_OBJ_BLOB);
+ delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
- if (error < 0)
+ /* since we did not have the definitive oid, we may have
+ * incorrect status and need to skip this item.
+ */
+ if (delta->old_file.mode == delta->new_file.mode &&
+ !git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid))
+ {
+ delta->status = GIT_DELTA_UNMODIFIED;
+
+ if ((ctxt->opts->flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
goto cleanup;
- delta->new_file.flags |= GIT_DIFF_FILE_VALID_OID;
-
- /* since we did not have the definitive oid, we may have
- * incorrect status and need to skip this item.
- */
- if (delta->old_file.mode == delta->new_file.mode &&
- !git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid))
- {
- delta->status = GIT_DELTA_UNMODIFIED;
- if ((diff->opts.flags & GIT_DIFF_INCLUDE_UNMODIFIED) == 0)
- goto cleanup;
- }
}
}
+ }
+
+ /* if we have not already decided whether file is binary,
+ * check the first 4K for nul bytes to decide...
+ */
+ if (!error && delta->binary == -1)
+ error = diff_delta_is_binary_by_content(ctxt);
+
+cleanup:
+ ctxt->loaded = !error;
+
+ /* flag if we would want to diff the contents of these files */
+ if (ctxt->loaded)
+ ctxt->diffable =
+ (delta->binary != 1 &&
+ delta->status != GIT_DELTA_UNMODIFIED &&
+ (ctxt->old_data.len || ctxt->new_data.len) &&
+ git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid));
+
+ return error;
+}
+
+static int diff_delta_cb(void *priv, mmbuffer_t *bufs, int len)
+{
+ diff_delta_context *ctxt = priv;
+
+ if (len == 1) {
+ if ((ctxt->cb_error = parse_hunk_header(&ctxt->range, bufs[0].ptr)) < 0)
+ return ctxt->cb_error;
+
+ if (ctxt->per_hunk != NULL &&
+ ctxt->per_hunk(ctxt->cb_data, ctxt->delta, &ctxt->range,
+ bufs[0].ptr, bufs[0].size))
+ ctxt->cb_error = GIT_EUSER;
+ }
- /* if we have not already decided whether file is binary,
- * check the first 4K for nul bytes to decide...
+ if (len == 2 || len == 3) {
+ /* expect " "/"-"/"+", then data */
+ char origin =
+ (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_ADDITION :
+ (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_DELETION :
+ GIT_DIFF_LINE_CONTEXT;
+
+ if (ctxt->per_line != NULL &&
+ ctxt->per_line(ctxt->cb_data, ctxt->delta, &ctxt->range, origin,
+ bufs[1].ptr, bufs[1].size))
+ ctxt->cb_error = GIT_EUSER;
+ }
+
+ if (len == 3 && !ctxt->cb_error) {
+ /* This should only happen if we are adding a line that does not
+ * have a newline at the end and the old code did. In that case,
+ * we have a ADD with a DEL_EOFNL as a pair.
*/
- if (delta->binary == -1) {
- error = file_is_binary_by_content(
- delta, &old_data, &new_data);
- if (error < 0)
+ char origin =
+ (*bufs[0].ptr == '+') ? GIT_DIFF_LINE_DEL_EOFNL :
+ (*bufs[0].ptr == '-') ? GIT_DIFF_LINE_ADD_EOFNL :
+ GIT_DIFF_LINE_CONTEXT;
+
+ if (ctxt->per_line != NULL &&
+ ctxt->per_line(ctxt->cb_data, ctxt->delta, &ctxt->range, origin,
+ bufs[2].ptr, bufs[2].size))
+ ctxt->cb_error = GIT_EUSER;
+ }
+
+ return ctxt->cb_error;
+}
+
+static int diff_delta_exec(
+ diff_delta_context *ctxt,
+ void *cb_data,
+ git_diff_hunk_fn per_hunk,
+ git_diff_data_fn per_line)
+{
+ int error = 0;
+ xdemitcb_t xdiff_callback;
+ mmfile_t old_xdiff_data, new_xdiff_data;
+
+ if (ctxt->diffed || !ctxt->delta)
+ return 0;
+
+ if (!ctxt->loaded && (error = diff_delta_load(ctxt)) < 0)
+ goto cleanup;
+
+ if (!ctxt->diffable)
+ return 0;
+
+ ctxt->cb_data = cb_data;
+ ctxt->per_hunk = per_hunk;
+ ctxt->per_line = per_line;
+ ctxt->cb_error = 0;
+
+ memset(&xdiff_callback, 0, sizeof(xdiff_callback));
+ xdiff_callback.outf = diff_delta_cb;
+ xdiff_callback.priv = ctxt;
+
+ old_xdiff_data.ptr = ctxt->old_data.data;
+ old_xdiff_data.size = ctxt->old_data.len;
+ new_xdiff_data.ptr = ctxt->new_data.data;
+ new_xdiff_data.size = ctxt->new_data.len;
+
+ xdl_diff(&old_xdiff_data, &new_xdiff_data,
+ &ctxt->xdiff_params, &ctxt->xdiff_config, &xdiff_callback);
+
+ error = ctxt->cb_error;
+
+cleanup:
+ ctxt->diffed = !error;
+
+ return error;
+}
+
+int git_diff_foreach(
+ git_diff_list *diff,
+ void *data,
+ git_diff_file_fn file_cb,
+ git_diff_hunk_fn hunk_cb,
+ git_diff_data_fn line_cb)
+{
+ int error = 0;
+ diff_delta_context ctxt;
+ size_t idx;
+
+ diff_delta_init_context_from_diff_list(&ctxt, diff);
+
+ git_vector_foreach(&diff->deltas, idx, ctxt.delta) {
+ if (diff_delta_is_ambiguous(ctxt.delta))
+ if ((error = diff_delta_load(&ctxt)) < 0)
goto cleanup;
- }
- /* TODO: if ignore_whitespace is set, then we *must* do text
- * diffs to tell if a file has really been changed.
- */
+ if (diff_delta_should_skip(ctxt.opts, ctxt.delta))
+ continue;
+
+ if ((error = diff_delta_load(&ctxt)) < 0)
+ goto cleanup;
if (file_cb != NULL &&
- file_cb(data, delta, (float)info.index / diff->deltas.length))
+ file_cb(data, ctxt.delta, (float)idx / diff->deltas.length) != 0)
{
error = GIT_EUSER;
goto cleanup;
}
- /* don't do hunk and line diffs if file is binary */
- if (delta->binary == 1)
- goto cleanup;
-
- /* nothing to do if we did not get data */
- if (!old_data.len && !new_data.len)
- goto cleanup;
-
- /* nothing to do if only diff was a mode change */
- if (!git_oid_cmp(&delta->old_file.oid, &delta->new_file.oid))
- goto cleanup;
-
- assert(hunk_cb || line_cb);
-
- info.delta = delta;
- old_xdiff_data.ptr = old_data.data;
- old_xdiff_data.size = old_data.len;
- new_xdiff_data.ptr = new_data.data;
- new_xdiff_data.size = new_data.len;
-
- xdl_diff(&old_xdiff_data, &new_xdiff_data,
- &xdiff_params, &xdiff_config, &xdiff_callback);
- error = info.error;
+ error = diff_delta_exec(&ctxt, data, hunk_cb, line_cb);
cleanup:
- release_content(&delta->old_file, &old_data, old_blob);
- release_content(&delta->new_file, &new_data, new_blob);
+ diff_delta_unload(&ctxt);
if (error < 0)
break;
}
+ if (error == GIT_EUSER)
+ giterr_clear();
+
return error;
}
-
typedef struct {
git_diff_list *diff;
git_diff_data_fn print_cb;
@@ -531,7 +685,10 @@ static int print_compact(void *data, git_diff_delta *delta, float progress)
if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR,
git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ {
+ giterr_clear();
return GIT_EUSER;
+ }
return 0;
}
@@ -628,7 +785,10 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress)
return -1;
if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_FILE_HDR, git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ {
+ giterr_clear();
return GIT_EUSER;
+ }
if (delta->binary != 1)
return 0;
@@ -642,7 +802,10 @@ static int print_patch_file(void *data, git_diff_delta *delta, float progress)
if (pi->print_cb(pi->cb_data, delta, NULL, GIT_DIFF_LINE_BINARY,
git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ {
+ giterr_clear();
return GIT_EUSER;
+ }
return 0;
}
@@ -662,7 +825,10 @@ static int print_patch_hunk(
if (pi->print_cb(pi->cb_data, d, r, GIT_DIFF_LINE_HUNK_HDR,
git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ {
+ giterr_clear();
return GIT_EUSER;
+ }
return 0;
}
@@ -691,7 +857,10 @@ static int print_patch_line(
if (pi->print_cb(pi->cb_data, delta, range, line_origin,
git_buf_cstr(pi->buf), git_buf_len(pi->buf)))
+ {
+ giterr_clear();
return GIT_EUSER;
+ }
return 0;
}
@@ -726,17 +895,36 @@ int git_diff_entrycount(git_diff_list *diff, int delta_t)
assert(diff);
- if (delta_t < 0)
- return diff->deltas.length;
-
git_vector_foreach(&diff->deltas, i, delta) {
- if (delta->status == (git_delta_t)delta_t)
+ if (diff_delta_should_skip(&diff->opts, delta))
+ continue;
+
+ if (delta_t < 0 || delta->status == (git_delta_t)delta_t)
count++;
}
+ /* It is possible that this has overcounted the number of diffs because
+ * there may be entries that are marked as MODIFIED due to differences
+ * in stat() output that will turn out to be the same once we calculate
+ * the actual SHA of the data on disk.
+ */
+
return count;
}
+static void set_data_from_blob(
+ git_blob *blob, git_map *map, git_diff_file *file)
+{
+ if (blob) {
+ map->data = (char *)git_blob_rawcontent(blob);
+ file->size = map->len = git_blob_rawsize(blob);
+ git_oid_cpy(&file->oid, git_object_id((const git_object *)blob));
+ } else {
+ map->data = "";
+ file->size = map->len = 0;
+ }
+}
+
int git_diff_blobs(
git_blob *old_blob,
git_blob *new_blob,
@@ -746,17 +934,11 @@ int git_diff_blobs(
git_diff_hunk_fn hunk_cb,
git_diff_data_fn line_cb)
{
- diff_output_info info;
+ int error;
+ diff_delta_context ctxt;
git_diff_delta delta;
- mmfile_t old_data, new_data;
- git_map old_map, new_map;
- xpparam_t xdiff_params;
- xdemitconf_t xdiff_config;
- xdemitcb_t xdiff_callback;
git_blob *new, *old;
- memset(&delta, 0, sizeof(delta));
-
new = new_blob;
old = old_blob;
@@ -766,25 +948,16 @@ int git_diff_blobs(
new = swap;
}
- if (old) {
- old_data.ptr = (char *)git_blob_rawcontent(old);
- old_data.size = git_blob_rawsize(old);
- git_oid_cpy(&delta.old_file.oid, git_object_id((const git_object *)old));
- } else {
- old_data.ptr = "";
- old_data.size = 0;
- }
-
- if (new) {
- new_data.ptr = (char *)git_blob_rawcontent(new);
- new_data.size = git_blob_rawsize(new);
- git_oid_cpy(&delta.new_file.oid, git_object_id((const git_object *)new));
- } else {
- new_data.ptr = "";
- new_data.size = 0;
- }
+ diff_delta_init_context(
+ &ctxt, NULL, options, GIT_ITERATOR_TREE, GIT_ITERATOR_TREE);
/* populate a "fake" delta record */
+
+ memset(&delta, 0, sizeof(delta));
+
+ set_data_from_blob(old, &ctxt.old_data, &delta.old_file);
+ set_data_from_blob(new, &ctxt.new_data, &delta.new_file);
+
delta.status = new ?
(old ? GIT_DELTA_MODIFIED : GIT_DELTA_ADDED) :
(old ? GIT_DELTA_DELETED : GIT_DELTA_UNTRACKED);
@@ -792,39 +965,369 @@ int git_diff_blobs(
if (git_oid_cmp(&delta.new_file.oid, &delta.old_file.oid) == 0)
delta.status = GIT_DELTA_UNMODIFIED;
- delta.old_file.size = old_data.size;
- delta.new_file.size = new_data.size;
+ ctxt.delta = &delta;
+
+ if ((error = diff_delta_prep(&ctxt)) < 0)
+ goto cleanup;
+
+ if (delta.binary == -1 &&
+ (error = diff_delta_is_binary_by_content(&ctxt)) < 0)
+ goto cleanup;
+
+ ctxt.loaded = 1;
+ ctxt.diffable = (delta.binary != 1 && delta.status != GIT_DELTA_UNMODIFIED);
+
+ /* do diffs */
+
+ if (file_cb != NULL && file_cb(cb_data, &delta, 1)) {
+ error = GIT_EUSER;
+ goto cleanup;
+ }
+
+ error = diff_delta_exec(&ctxt, cb_data, hunk_cb, line_cb);
- fill_map_from_mmfile(&old_map, &old_data);
- fill_map_from_mmfile(&new_map, &new_data);
+cleanup:
+ if (error == GIT_EUSER)
+ giterr_clear();
+
+ diff_delta_unload(&ctxt);
+
+ return error;
+}
+
+typedef struct diffiter_line diffiter_line;
+struct diffiter_line {
+ diffiter_line *next;
+ char origin;
+ const char *ptr;
+ size_t len;
+};
+
+typedef struct diffiter_hunk diffiter_hunk;
+struct diffiter_hunk {
+ diffiter_hunk *next;
+ git_diff_range range;
+ diffiter_line *line_head;
+ size_t line_count;
+};
+
+struct git_diff_iterator {
+ git_diff_list *diff;
+ diff_delta_context ctxt;
+ size_t file_index;
+ size_t next_index;
+ size_t file_count;
+ git_pool hunks;
+ size_t hunk_count;
+ diffiter_hunk *hunk_head;
+ diffiter_hunk *hunk_curr;
+ char hunk_header[128];
+ git_pool lines;
+ diffiter_line *line_curr;
+};
+
+typedef struct {
+ git_diff_iterator *iter;
+ diffiter_hunk *last_hunk;
+ diffiter_line *last_line;
+} diffiter_cb_info;
- if (file_is_binary_by_content(&delta, &old_map, &new_map) < 0)
+static int diffiter_hunk_cb(
+ void *cb_data,
+ git_diff_delta *delta,
+ git_diff_range *range,
+ const char *header,
+ size_t header_len)
+{
+ diffiter_cb_info *info = cb_data;
+ git_diff_iterator *iter = info->iter;
+ diffiter_hunk *hunk;
+
+ GIT_UNUSED(delta);
+ GIT_UNUSED(header);
+ GIT_UNUSED(header_len);
+
+ if ((hunk = git_pool_mallocz(&iter->hunks, 1)) == NULL) {
+ iter->ctxt.cb_error = -1;
return -1;
+ }
- if (file_cb != NULL && file_cb(cb_data, &delta, 1))
- return GIT_EUSER;
+ if (info->last_hunk)
+ info->last_hunk->next = hunk;
+ info->last_hunk = hunk;
- /* don't do hunk and line diffs if the two blobs are identical */
- if (delta.status == GIT_DELTA_UNMODIFIED)
- return 0;
+ memcpy(&hunk->range, range, sizeof(hunk->range));
- /* don't do hunk and line diffs if file is binary */
- if (delta.binary == 1)
+ iter->hunk_count++;
+
+ if (iter->hunk_head == NULL)
+ iter->hunk_curr = iter->hunk_head = hunk;
+
+ return 0;
+}
+
+static int diffiter_line_cb(
+ void *cb_data,
+ git_diff_delta *delta,
+ git_diff_range *range,
+ char line_origin,
+ const char *content,
+ size_t content_len)
+{
+ diffiter_cb_info *info = cb_data;
+ git_diff_iterator *iter = info->iter;
+ diffiter_line *line;
+
+ GIT_UNUSED(delta);
+ GIT_UNUSED(range);
+
+ if ((line = git_pool_mallocz(&iter->lines, 1)) == NULL) {
+ iter->ctxt.cb_error = -1;
+ return -1;
+ }
+
+ if (info->last_line)
+ info->last_line->next = line;
+ info->last_line = line;
+
+ line->origin = line_origin;
+ line->ptr = content;
+ line->len = content_len;
+
+ info->last_hunk->line_count++;
+
+ if (info->last_hunk->line_head == NULL)
+ info->last_hunk->line_head = line;
+
+ return 0;
+}
+
+static int diffiter_do_diff_file(git_diff_iterator *iter)
+{
+ int error;
+ diffiter_cb_info info;
+
+ if (iter->ctxt.diffed || !iter->ctxt.delta)
return 0;
memset(&info, 0, sizeof(info));
- info.diff = NULL;
- info.delta = &delta;
- info.cb_data = cb_data;
- info.hunk_cb = hunk_cb;
- info.line_cb = line_cb;
+ info.iter = iter;
- setup_xdiff_options(options, &xdiff_config, &xdiff_params);
- memset(&xdiff_callback, 0, sizeof(xdiff_callback));
- xdiff_callback.outf = diff_output_cb;
- xdiff_callback.priv = &info;
+ error = diff_delta_exec(
+ &iter->ctxt, &info, diffiter_hunk_cb, diffiter_line_cb);
- xdl_diff(&old_data, &new_data, &xdiff_params, &xdiff_config, &xdiff_callback);
+ if (error == GIT_EUSER)
+ error = iter->ctxt.cb_error;
+
+ return error;
+}
+
+static void diffiter_do_unload_file(git_diff_iterator *iter)
+{
+ if (iter->ctxt.loaded) {
+ diff_delta_unload(&iter->ctxt);
- return info.error;
+ git_pool_clear(&iter->lines);
+ git_pool_clear(&iter->hunks);
+ }
+
+ iter->ctxt.delta = NULL;
+ iter->hunk_head = NULL;
+ iter->hunk_count = 0;
+}
+
+int git_diff_iterator_new(
+ git_diff_iterator **iterator_ptr,
+ git_diff_list *diff)
+{
+ size_t i;
+ git_diff_delta *delta;
+ git_diff_iterator *iter;
+
+ assert(diff && iterator_ptr);
+
+ *iterator_ptr = NULL;
+
+ iter = git__malloc(sizeof(git_diff_iterator));
+ GITERR_CHECK_ALLOC(iter);
+
+ memset(iter, 0, sizeof(*iter));
+
+ iter->diff = diff;
+ GIT_REFCOUNT_INC(iter->diff);
+
+ diff_delta_init_context_from_diff_list(&iter->ctxt, diff);
+
+ if (git_pool_init(&iter->hunks, sizeof(diffiter_hunk), 0) < 0 ||
+ git_pool_init(&iter->lines, sizeof(diffiter_line), 0) < 0)
+ goto fail;
+
+ git_vector_foreach(&diff->deltas, i, delta) {
+ if (diff_delta_should_skip(iter->ctxt.opts, delta))
+ continue;
+ iter->file_count++;
+ }
+
+ *iterator_ptr = iter;
+
+ return 0;
+
+fail:
+ git_diff_iterator_free(iter);
+
+ return -1;
+}
+
+void git_diff_iterator_free(git_diff_iterator *iter)
+{
+ diffiter_do_unload_file(iter);
+ git_diff_list_free(iter->diff); /* decrement ref count */
+ git__free(iter);
+}
+
+int git_diff_iterator_num_files(git_diff_iterator *iter)
+{
+ return (int)iter->file_count;
+}
+
+int git_diff_iterator_num_hunks_in_file(git_diff_iterator *iter)
+{
+ int error = diffiter_do_diff_file(iter);
+ return (error != 0) ? error : (int)iter->hunk_count;
+}
+
+int git_diff_iterator_num_lines_in_hunk(git_diff_iterator *iter)
+{
+ int error = diffiter_do_diff_file(iter);
+ if (!error && iter->hunk_curr)
+ error = iter->hunk_curr->line_count;
+ return error;
+}
+
+int git_diff_iterator_next_file(
+ git_diff_delta **delta_ptr,
+ git_diff_iterator *iter)
+{
+ int error = 0;
+
+ assert(iter);
+
+ iter->file_index = iter->next_index;
+
+ diffiter_do_unload_file(iter);
+
+ while (!error) {
+ iter->ctxt.delta = git_vector_get(&iter->diff->deltas, iter->file_index);
+ if (!iter->ctxt.delta) {
+ error = GIT_ITEROVER;
+ break;
+ }
+
+ if (diff_delta_is_ambiguous(iter->ctxt.delta) &&
+ (error = diff_delta_load(&iter->ctxt)) < 0)
+ break;
+
+ if (!diff_delta_should_skip(iter->ctxt.opts, iter->ctxt.delta))
+ break;
+
+ iter->file_index++;
+ }
+
+ if (!error) {
+ iter->next_index = iter->file_index + 1;
+
+ error = diff_delta_prep(&iter->ctxt);
+ }
+
+ if (iter->ctxt.delta == NULL) {
+ iter->hunk_curr = NULL;
+ iter->line_curr = NULL;
+ }
+
+ if (delta_ptr != NULL)
+ *delta_ptr = !error ? iter->ctxt.delta : NULL;
+
+ return error;
+}
+
+int git_diff_iterator_next_hunk(
+ git_diff_range **range_ptr,
+ const char **header,
+ size_t *header_len,
+ git_diff_iterator *iter)
+{
+ int error = diffiter_do_diff_file(iter);
+ git_diff_range *range;
+
+ if (error)
+ return error;
+
+ if (iter->hunk_curr == NULL) {
+ if (range_ptr) *range_ptr = NULL;
+ if (header) *header = NULL;
+ if (header_len) *header_len = 0;
+ iter->line_curr = NULL;
+ return GIT_ITEROVER;
+ }
+
+ range = &iter->hunk_curr->range;
+
+ if (range_ptr)
+ *range_ptr = range;
+
+ if (header) {
+ int out = format_hunk_header(
+ iter->hunk_header, sizeof(iter->hunk_header), range);
+
+ /* TODO: append function name to header */
+
+ *(iter->hunk_header + out++) = '\n';
+
+ *header = iter->hunk_header;
+
+ if (header_len)
+ *header_len = (size_t)out;
+ }
+
+ iter->line_curr = iter->hunk_curr->line_head;
+ iter->hunk_curr = iter->hunk_curr->next;
+
+ return error;
+}
+
+int git_diff_iterator_next_line(
+ char *line_origin, /**< GIT_DIFF_LINE_... value from above */
+ const char **content_ptr,
+ size_t *content_len,
+ git_diff_iterator *iter)
+{
+ int error = diffiter_do_diff_file(iter);
+
+ if (error)
+ return error;
+
+ /* if the user has not called next_hunk yet, call it implicitly (OK?) */
+ if (iter->hunk_curr == iter->hunk_head) {
+ error = git_diff_iterator_next_hunk(NULL, NULL, NULL, iter);
+ if (error)
+ return error;
+ }
+
+ if (iter->line_curr == NULL) {
+ if (line_origin) *line_origin = GIT_DIFF_LINE_CONTEXT;
+ if (content_ptr) *content_ptr = NULL;
+ if (content_len) *content_len = 0;
+ return GIT_ITEROVER;
+ }
+
+ if (line_origin)
+ *line_origin = iter->line_curr->origin;
+ if (content_ptr)
+ *content_ptr = iter->line_curr->ptr;
+ if (content_len)
+ *content_len = iter->line_curr->len;
+
+ iter->line_curr = iter->line_curr->next;
+
+ return error;
}
diff --git a/src/fetch.c b/src/fetch.c
index 278ba3c5..98e1f0b1 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -221,7 +221,7 @@ int git_fetch_negotiate(git_remote *remote)
}
}
- if (error < 0 && error != GIT_REVWALKOVER)
+ if (error < 0 && error != GIT_ITEROVER)
goto on_error;
/* Tell the other end that we're done negotiating */
diff --git a/src/fileops.c b/src/fileops.c
index 76ef8c91..95eacb5f 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -54,11 +54,10 @@ int git_futils_creat_locked(const char *path, const mode_t mode)
int fd;
#ifdef GIT_WIN32
- wchar_t* buf;
+ wchar_t buf[GIT_WIN_PATH];
- buf = gitwin_to_utf16(path);
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
fd = _wopen(buf, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
- git__free(buf);
#else
fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
#endif
@@ -382,16 +381,16 @@ static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ)
static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename)
{
- int error = 0;
- size_t len;
+ size_t len, alloc_len;
wchar_t *file_utf16 = NULL;
- char *file_utf8 = NULL;
+ char file_utf8[GIT_PATH_MAX];
if (!root || !filename || (len = strlen(filename)) == 0)
return GIT_ENOTFOUND;
/* allocate space for wchar_t path to file */
- file_utf16 = git__calloc(root->len + len + 2, sizeof(wchar_t));
+ alloc_len = root->len + len + 2;
+ file_utf16 = git__calloc(alloc_len, sizeof(wchar_t));
GITERR_CHECK_ALLOC(file_utf16);
/* append root + '\\' + filename as wchar_t */
@@ -400,29 +399,20 @@ static int win32_find_file(git_buf *path, const struct win32_path *root, const c
if (*filename == '/' || *filename == '\\')
filename++;
- if (gitwin_append_utf16(file_utf16 + root->len - 1, filename, len + 1) !=
- (int)len + 1) {
- error = -1;
- goto cleanup;
- }
+ git__utf8_to_16(file_utf16 + root->len - 1, alloc_len, filename);
/* check access */
if (_waccess(file_utf16, F_OK) < 0) {
- error = GIT_ENOTFOUND;
- goto cleanup;
+ git__free(file_utf16);
+ return GIT_ENOTFOUND;
}
- /* convert to utf8 */
- if ((file_utf8 = gitwin_from_utf16(file_utf16)) == NULL)
- error = -1;
- else {
- git_path_mkposix(file_utf8);
- git_buf_attach(path, file_utf8, 0);
- }
+ git__utf16_to_8(file_utf8, file_utf16);
+ git_path_mkposix(file_utf8);
+ git_buf_sets(path, file_utf8);
-cleanup:
git__free(file_utf16);
- return error;
+ return 0;
}
#endif
diff --git a/src/netops.c b/src/netops.c
index 49a0308b..df502e61 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -55,8 +55,44 @@ static void net_set_error(const char *str)
static int ssl_set_error(gitno_ssl *ssl, int error)
{
int err;
+ unsigned long e;
+
err = SSL_get_error(ssl->ssl, error);
- giterr_set(GITERR_NET, "SSL error: %s", ERR_error_string(err, NULL));
+
+ assert(err != SSL_ERROR_WANT_READ);
+ assert(err != SSL_ERROR_WANT_WRITE);
+
+ switch (err) {
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ giterr_set(GITERR_NET, "SSL error: connection failure\n");
+ break;
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ giterr_set(GITERR_NET, "SSL error: x509 error\n");
+ break;
+ case SSL_ERROR_SYSCALL:
+ e = ERR_get_error();
+ if (e > 0) {
+ giterr_set(GITERR_NET, "SSL error: %s",
+ ERR_error_string(e, NULL));
+ break;
+ } else if (error < 0) {
+ giterr_set(GITERR_OS, "SSL error: syscall failure");
+ break;
+ }
+ giterr_set(GITERR_NET, "SSL error: received early EOF");
+ break;
+ case SSL_ERROR_SSL:
+ e = ERR_get_error();
+ giterr_set(GITERR_NET, "SSL error: %s",
+ ERR_error_string(e, NULL));
+ break;
+ case SSL_ERROR_NONE:
+ case SSL_ERROR_ZERO_RETURN:
+ default:
+ giterr_set(GITERR_NET, "SSL error: unknown error");
+ break;
+ }
return -1;
}
#endif
@@ -238,6 +274,10 @@ static int verify_server_cert(git_transport *t, const char *host)
void *addr;
int i = -1,j;
+ if (SSL_get_verify_result(t->ssl.ssl) != X509_V_OK) {
+ giterr_set(GITERR_SSL, "The SSL certificate is invalid");
+ return -1;
+ }
/* Try to parse the host as an IP address to see if it is */
if (inet_pton(AF_INET, host, &addr4)) {
@@ -286,7 +326,7 @@ static int verify_server_cert(git_transport *t, const char *host)
GENERAL_NAMES_free(alts);
if (matched == 0)
- goto on_error;
+ goto cert_fail;
if (matched == 1)
return 0;
@@ -354,7 +394,7 @@ static int ssl_setup(git_transport *t, const char *host)
return ssl_set_error(&t->ssl, 0);
SSL_CTX_set_mode(t->ssl.ctx, SSL_MODE_AUTO_RETRY);
- SSL_CTX_set_verify(t->ssl.ctx, SSL_VERIFY_PEER, NULL);
+ SSL_CTX_set_verify(t->ssl.ctx, SSL_VERIFY_NONE, NULL);
if (!SSL_CTX_set_default_verify_paths(t->ssl.ctx))
return ssl_set_error(&t->ssl, 0);
@@ -438,7 +478,7 @@ static int send_ssl(gitno_ssl *ssl, const char *msg, size_t len)
while (off < len) {
ret = SSL_write(ssl->ssl, msg + off, len - off);
- if (ret <= 0)
+ if (ret <= 0 && ret != SSL_ERROR_WANT_WRITE)
return ssl_set_error(ssl, ret);
off += ret;
diff --git a/src/object.c b/src/object.c
index 22777404..5130d97a 100644
--- a/src/object.c
+++ b/src/object.c
@@ -334,6 +334,12 @@ int git_object__resolve_to_type(git_object **obj, git_otype type)
return error;
}
+static int peel_error(int error, const char* msg)
+{
+ giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
+ return error;
+}
+
static int dereference_object(git_object **dereferenced, git_object *obj)
{
git_otype type = git_object_type(obj);
@@ -341,48 +347,36 @@ static int dereference_object(git_object **dereferenced, git_object *obj)
switch (type) {
case GIT_OBJ_COMMIT:
return git_commit_tree((git_tree **)dereferenced, (git_commit*)obj);
- break;
case GIT_OBJ_TAG:
return git_tag_target(dereferenced, (git_tag*)obj);
- break;
+
+ case GIT_OBJ_BLOB:
+ return peel_error(GIT_ERROR, "cannot dereference blob");
+
+ case GIT_OBJ_TREE:
+ return peel_error(GIT_ERROR, "cannot dereference tree");
default:
- return GIT_ENOTFOUND;
- break;
+ return peel_error(GIT_ENOTFOUND, "unexpected object type encountered");
}
}
-static int peel_error(int error, const char* msg)
-{
- giterr_set(GITERR_INVALID, "The given object cannot be peeled - %s", msg);
- return error;
-}
-
int git_object_peel(
- git_object **peeled,
- git_object *object,
- git_otype target_type)
+ git_object **peeled,
+ git_object *object,
+ git_otype target_type)
{
git_object *source, *deref = NULL;
- assert(object);
+ assert(object && peeled);
if (git_object_type(object) == target_type)
return git_object__dup(peeled, object);
- if (target_type == GIT_OBJ_BLOB
- || target_type == GIT_OBJ_ANY)
- return peel_error(GIT_EAMBIGUOUS, "Ambiguous target type");
-
- if (git_object_type(object) == GIT_OBJ_BLOB)
- return peel_error(GIT_ERROR, "A blob cannot be dereferenced");
-
source = object;
- while (true) {
- if (dereference_object(&deref, source) < 0)
- goto cleanup;
+ while (!dereference_object(&deref, source)) {
if (source != object)
git_object_free(source);
@@ -392,13 +386,20 @@ int git_object_peel(
return 0;
}
+ if (target_type == GIT_OBJ_ANY &&
+ git_object_type(deref) != git_object_type(object))
+ {
+ *peeled = deref;
+ return 0;
+ }
+
source = deref;
deref = NULL;
}
-cleanup:
if (source != object)
git_object_free(source);
+
git_object_free(deref);
return -1;
}
diff --git a/src/odb_pack.c b/src/odb_pack.c
index 8fc6e68e..6e3d3eef 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -435,7 +435,7 @@ static int pack_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *o
return error;
git_vector_foreach(&backend->packs, i, p) {
- if ((error = git_pack_foreach_entry(p, cb, &data)) < 0)
+ if ((error = git_pack_foreach_entry(p, cb, data)) < 0)
return error;
}
diff --git a/src/path.c b/src/path.c
index 15188850..09556bd3 100644
--- a/src/path.c
+++ b/src/path.c
@@ -432,14 +432,14 @@ bool git_path_is_empty_dir(const char *path)
{
git_buf pathbuf = GIT_BUF_INIT;
HANDLE hFind = INVALID_HANDLE_VALUE;
- wchar_t *wbuf;
+ wchar_t wbuf[GIT_WIN_PATH];
WIN32_FIND_DATAW ffd;
bool retval = true;
if (!git_path_isdir(path)) return false;
git_buf_printf(&pathbuf, "%s\\*", path);
- wbuf = gitwin_to_utf16(git_buf_cstr(&pathbuf));
+ git__utf8_to_16(wbuf, GIT_WIN_PATH, git_buf_cstr(&pathbuf));
hFind = FindFirstFileW(wbuf, &ffd);
if (INVALID_HANDLE_VALUE == hFind) {
@@ -455,7 +455,6 @@ bool git_path_is_empty_dir(const char *path)
FindClose(hFind);
git_buf_free(&pathbuf);
- git__free(wbuf);
return retval;
}
diff --git a/src/pool.h b/src/pool.h
index 05d33924..dee6ecda 100644
--- a/src/pool.h
+++ b/src/pool.h
@@ -76,6 +76,17 @@ extern void git_pool_swap(git_pool *a, git_pool *b);
extern void *git_pool_malloc(git_pool *pool, uint32_t items);
/**
+ * Allocate space and zero it out.
+ */
+GIT_INLINE(void *) git_pool_mallocz(git_pool *pool, uint32_t items)
+{
+ void *ptr = git_pool_malloc(pool, items);
+ if (ptr)
+ memset(ptr, 0, (size_t)items * (size_t)pool->item_size);
+ return ptr;
+}
+
+/**
* Allocate space and duplicate string data into it.
*
* This is allowed only for pools with item_size == sizeof(char)
diff --git a/src/refs.c b/src/refs.c
index cf55a6fd..211a5870 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -68,11 +68,6 @@ static int reference_path_available(git_repository *repo,
static int reference_delete(git_reference *ref);
static int reference_lookup(git_reference *ref);
-/* name normalization */
-static int normalize_name(char *buffer_out, size_t out_size,
- const char *name, int is_oid_ref);
-
-
void git_reference_free(git_reference *reference)
{
if (reference == NULL)
@@ -1099,9 +1094,12 @@ int git_reference_lookup_resolved(
scan->name = git__calloc(GIT_REFNAME_MAX + 1, sizeof(char));
GITERR_CHECK_ALLOC(scan->name);
- if ((result = normalize_name(scan->name, GIT_REFNAME_MAX, name, 0)) < 0) {
- git_reference_free(scan);
- return result;
+ if ((result = git_reference__normalize_name(
+ scan->name,
+ GIT_REFNAME_MAX,
+ name)) < 0) {
+ git_reference_free(scan);
+ return result;
}
scan->target.symbolic = git__strdup(scan->name);
@@ -1198,8 +1196,11 @@ int git_reference_create_symbolic(
char normalized[GIT_REFNAME_MAX];
git_reference *ref = NULL;
- if (normalize_name(normalized, sizeof(normalized), name, 0) < 0)
- return -1;
+ if (git_reference__normalize_name(
+ normalized,
+ sizeof(normalized),
+ name) < 0)
+ return -1;
if (reference_can_write(repo, normalized, NULL, force) < 0)
return -1;
@@ -1234,8 +1235,11 @@ int git_reference_create_oid(
git_reference *ref = NULL;
char normalized[GIT_REFNAME_MAX];
- if (normalize_name(normalized, sizeof(normalized), name, 1) < 0)
- return -1;
+ if (git_reference__normalize_name_oid(
+ normalized,
+ sizeof(normalized),
+ name) < 0)
+ return -1;
if (reference_can_write(repo, normalized, NULL, force) < 0)
return -1;
@@ -1314,8 +1318,11 @@ int git_reference_set_target(git_reference *ref, const char *target)
return -1;
}
- if (normalize_name(normalized, sizeof(normalized), target, 0))
- return -1;
+ if (git_reference__normalize_name(
+ normalized,
+ sizeof(normalized),
+ target))
+ return -1;
git__free(ref->target.symbolic);
ref->target.symbolic = git__strdup(normalized);
@@ -1327,15 +1334,23 @@ int git_reference_set_target(git_reference *ref, const char *target)
int git_reference_rename(git_reference *ref, const char *new_name, int force)
{
int result;
+ unsigned int normalization_flags;
git_buf aux_path = GIT_BUF_INIT;
char normalized[GIT_REFNAME_MAX];
const char *head_target = NULL;
git_reference *head = NULL;
- if (normalize_name(normalized, sizeof(normalized),
- new_name, ref->flags & GIT_REF_OID) < 0)
- return -1;
+ normalization_flags = ref->flags & GIT_REF_SYMBOLIC ?
+ GIT_REF_FORMAT_ALLOW_ONELEVEL
+ : GIT_REF_FORMAT_NORMAL;
+
+ if (git_reference_normalize_name(
+ normalized,
+ sizeof(normalized),
+ new_name,
+ normalization_flags) < 0)
+ return -1;
if (reference_can_write(ref->owner, normalized, ref->name, force) < 0)
return -1;
@@ -1565,11 +1580,11 @@ static int is_valid_ref_char(char ch)
}
}
-static int normalize_name(
+int git_reference_normalize_name(
char *buffer_out,
- size_t out_size,
+ size_t buffer_size,
const char *name,
- int is_oid_ref)
+ unsigned int flags)
{
const char *name_end, *buffer_out_start;
const char *current;
@@ -1577,12 +1592,17 @@ static int normalize_name(
assert(name && buffer_out);
+ if (flags & GIT_REF_FORMAT_REFSPEC_PATTERN) {
+ giterr_set(GITERR_INVALID, "Unimplemented");
+ return -1;
+ }
+
buffer_out_start = buffer_out;
current = name;
name_end = name + strlen(name);
/* Terminating null byte */
- out_size--;
+ buffer_size--;
/* A refname can not be empty */
if (name_end == name)
@@ -1592,7 +1612,7 @@ static int normalize_name(
if (*(name_end - 1) == '.' || *(name_end - 1) == '/')
goto invalid_name;
- while (current < name_end && out_size) {
+ while (current < name_end && buffer_size > 0) {
if (!is_valid_ref_char(*current))
goto invalid_name;
@@ -1614,20 +1634,30 @@ static int normalize_name(
}
}
- if (*current == '/')
- contains_a_slash = 1;
+ if (*current == '/') {
+ if (buffer_out > buffer_out_start)
+ contains_a_slash = 1;
+ else {
+ current++;
+ continue;
+ }
+ }
*buffer_out++ = *current++;
- out_size--;
+ buffer_size--;
}
- if (!out_size)
- goto invalid_name;
+ if (current < name_end) {
+ giterr_set(
+ GITERR_REFERENCE,
+ "The provided buffer is too short to hold the normalization of '%s'", name);
+ return GIT_EBUFS;
+ }
/* Object id refname have to contain at least one slash, except
* for HEAD in a detached state or MERGE_HEAD if we're in the
* middle of a merge */
- if (is_oid_ref &&
+ if (!(flags & GIT_REF_FORMAT_ALLOW_ONELEVEL) &&
!contains_a_slash &&
strcmp(name, GIT_HEAD_FILE) != 0 &&
strcmp(name, GIT_MERGE_HEAD_FILE) != 0 &&
@@ -1640,18 +1670,12 @@ static int normalize_name(
*buffer_out = '\0';
- /*
- * For object id references, name has to start with refs/. Again,
- * we need to allow HEAD to be in a detached state.
- */
- if (is_oid_ref && !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) ||
- strcmp(buffer_out_start, GIT_HEAD_FILE)))
- goto invalid_name;
-
return 0;
invalid_name:
- giterr_set(GITERR_REFERENCE, "The given reference name is not valid");
+ giterr_set(
+ GITERR_REFERENCE,
+ "The given reference name '%s' is not valid", name);
return -1;
}
@@ -1660,7 +1684,11 @@ int git_reference__normalize_name(
size_t out_size,
const char *name)
{
- return normalize_name(buffer_out, out_size, name, 0);
+ return git_reference_normalize_name(
+ buffer_out,
+ out_size,
+ name,
+ GIT_REF_FORMAT_ALLOW_ONELEVEL);
}
int git_reference__normalize_name_oid(
@@ -1668,7 +1696,11 @@ int git_reference__normalize_name_oid(
size_t out_size,
const char *name)
{
- return normalize_name(buffer_out, out_size, name, 1);
+ return git_reference_normalize_name(
+ buffer_out,
+ out_size,
+ name,
+ GIT_REF_FORMAT_NORMAL);
}
#define GIT_REF_TYPEMASK (GIT_REF_OID | GIT_REF_SYMBOLIC)
@@ -1804,6 +1836,11 @@ int git_reference_has_log(
int git_reference_is_branch(git_reference *ref)
{
assert(ref);
-
return git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) == 0;
}
+
+int git_reference_is_remote(git_reference *ref)
+{
+ assert(ref);
+ return git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) == 0;
+}
diff --git a/src/repository.c b/src/repository.c
index c12df25c..b9d180da 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -777,8 +777,8 @@ static int repo_init_config(
SET_REPO_CONFIG(string, "core.worktree", work_dir);
}
else if ((opts->flags & GIT_REPOSITORY_INIT__IS_REINIT) != 0) {
- if ((error = git_config_delete(config, "core.worktree")) < 0)
- goto cleanup;
+ if (git_config_delete(config, "core.worktree") < 0)
+ giterr_clear();
}
} else {
if (!are_symlinks_supported(repo_dir))
diff --git a/src/reset.c b/src/reset.c
index 1379f644..f9e16f7c 100644
--- a/src/reset.c
+++ b/src/reset.c
@@ -20,10 +20,9 @@ static int reset_error_invalid(const char *msg)
int git_reset(
git_repository *repo,
- const git_object *target,
+ git_object *target,
git_reset_type reset_type)
{
- git_otype target_type = GIT_OBJ_BAD;
git_object *commit = NULL;
git_index *index = NULL;
git_tree *tree = NULL;
@@ -38,26 +37,9 @@ int git_reset(
if (reset_type == GIT_RESET_MIXED && git_repository_is_bare(repo))
return reset_error_invalid("Mixed reset is not allowed in a bare repository.");
- target_type = git_object_type(target);
-
- switch (target_type)
- {
- case GIT_OBJ_TAG:
- if (git_tag_peel(&commit, (git_tag *)target) < 0)
- goto cleanup;
-
- if (git_object_type(commit) != GIT_OBJ_COMMIT) {
- reset_error_invalid("The given target does not resolve to a commit.");
- goto cleanup;
- }
- break;
-
- case GIT_OBJ_COMMIT:
- commit = (git_object *)target;
- break;
-
- default:
- return reset_error_invalid("Only git_tag and git_commit objects are valid targets.");
+ if (git_object_peel(&commit, target, GIT_OBJ_COMMIT) < 0) {
+ reset_error_invalid("The given target does not resolve to a commit");
+ goto cleanup;
}
//TODO: Check for unmerged entries
@@ -93,9 +75,7 @@ int git_reset(
error = 0;
cleanup:
- if (target_type == GIT_OBJ_TAG)
- git_object_free(commit);
-
+ git_object_free(commit);
git_index_free(index);
git_tree_free(tree);
diff --git a/src/revparse.c b/src/revparse.c
index 3855c29f..17266b94 100644
--- a/src/revparse.c
+++ b/src/revparse.c
@@ -493,7 +493,7 @@ static int walk_and_search(git_object **out, git_revwalk *walk, regex_t *regex)
git_object_free(obj);
}
- if (error < 0 && error == GIT_REVWALKOVER)
+ if (error < 0 && error == GIT_ITEROVER)
error = GIT_ENOTFOUND;
return error;
diff --git a/src/revwalk.c b/src/revwalk.c
index 9dff283f..1a092771 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -264,12 +264,7 @@ static int commit_parse(git_revwalk *walk, commit_object *commit)
if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < 0)
return error;
-
- if (obj->raw.type != GIT_OBJ_COMMIT) {
- git_odb_object_free(obj);
- giterr_set(GITERR_INVALID, "Failed to parse commit. Object is no commit object");
- return -1;
- }
+ assert(obj->raw.type == GIT_OBJ_COMMIT);
error = commit_quick_parse(walk, commit, &obj->raw);
git_odb_object_free(obj);
@@ -454,6 +449,7 @@ int git_merge_base(git_oid *out, git_repository *repo, git_oid *one, git_oid *tw
if (!result) {
git_revwalk_free(walk);
+ giterr_clear();
return GIT_ENOTFOUND;
}
@@ -515,8 +511,21 @@ static int process_commit_parents(git_revwalk *walk, commit_object *commit)
static int push_commit(git_revwalk *walk, const git_oid *oid, int uninteresting)
{
+ git_object *obj;
+ git_otype type;
commit_object *commit;
+ if (git_object_lookup(&obj, walk->repo, oid, GIT_OBJ_ANY) < 0)
+ return -1;
+
+ type = git_object_type(obj);
+ git_object_free(obj);
+
+ if (type != GIT_OBJ_COMMIT) {
+ giterr_set(GITERR_INVALID, "Object is no commit object");
+ return -1;
+ }
+
commit = commit_lookup(walk, oid);
if (commit == NULL)
return -1; /* error already reported by failed lookup */
@@ -674,7 +683,8 @@ static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk)
}
}
- return GIT_REVWALKOVER;
+ giterr_clear();
+ return GIT_ITEROVER;
}
static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)
@@ -692,7 +702,8 @@ static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk)
}
}
- return GIT_REVWALKOVER;
+ giterr_clear();
+ return GIT_ITEROVER;
}
static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
@@ -702,8 +713,10 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
for (;;) {
next = commit_list_pop(&walk->iterator_topo);
- if (next == NULL)
- return GIT_REVWALKOVER;
+ if (next == NULL) {
+ giterr_clear();
+ return GIT_ITEROVER;
+ }
if (next->in_degree > 0) {
next->topo_delay = 1;
@@ -728,7 +741,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk)
static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk)
{
*object_out = commit_list_pop(&walk->iterator_reverse);
- return *object_out ? 0 : GIT_REVWALKOVER;
+ return *object_out ? 0 : GIT_ITEROVER;
}
@@ -743,8 +756,10 @@ static int prepare_walk(git_revwalk *walk)
* If walk->one is NULL, there were no positive references,
* so we know that the walk is already over.
*/
- if (walk->one == NULL)
- return GIT_REVWALKOVER;
+ if (walk->one == NULL) {
+ giterr_clear();
+ return GIT_ITEROVER;
+ }
/* first figure out what the merge bases are */
if (merge_bases_many(&bases, walk, walk->one, &walk->twos) < 0)
@@ -772,7 +787,7 @@ static int prepare_walk(git_revwalk *walk)
return -1;
}
- if (error != GIT_REVWALKOVER)
+ if (error != GIT_ITEROVER)
return error;
walk->get_next = &revwalk_next_toposort;
@@ -784,7 +799,7 @@ static int prepare_walk(git_revwalk *walk)
if (commit_list_insert(next, &walk->iterator_reverse) == NULL)
return -1;
- if (error != GIT_REVWALKOVER)
+ if (error != GIT_ITEROVER)
return error;
walk->get_next = &revwalk_next_reverse;
@@ -883,9 +898,10 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk)
error = walk->get_next(&next, walk);
- if (error == GIT_REVWALKOVER) {
+ if (error == GIT_ITEROVER) {
git_revwalk_reset(walk);
- return GIT_REVWALKOVER;
+ giterr_clear();
+ return GIT_ITEROVER;
}
if (!error)
diff --git a/src/signature.c b/src/signature.c
index 1f788356..0159488a 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -125,24 +125,26 @@ int git_signature_now(git_signature **sig_out, const char *name, const char *ema
{
time_t now;
time_t offset;
- struct tm *utc_tm, *local_tm;
+ struct tm *utc_tm;
git_signature *sig;
- struct tm _utc, _local;
+ struct tm _utc;
*sig_out = NULL;
+ /*
+ * Get the current time as seconds since the epoch and
+ * transform that into a tm struct containing the time at
+ * UTC. Give that to mktime which considers it a local time
+ * (tm_isdst = -1 asks it to take DST into account) and gives
+ * us that time as seconds since the epoch. The difference
+ * between its return value and 'now' is our offset to UTC.
+ */
time(&now);
-
utc_tm = p_gmtime_r(&now, &_utc);
- local_tm = p_localtime_r(&now, &_local);
-
- offset = mktime(local_tm) - mktime(utc_tm);
+ utc_tm->tm_isdst = -1;
+ offset = (time_t)difftime(now, mktime(utc_tm));
offset /= 60;
- /* mktime takes care of setting tm_isdst correctly */
- if (local_tm->tm_isdst)
- offset += 60;
-
if (git_signature_new(&sig, name, email, now, (int)offset) < 0)
return -1;
diff --git a/src/status.c b/src/status.c
index 3d3d15d7..0a5fbdcb 100644
--- a/src/status.c
+++ b/src/status.c
@@ -151,6 +151,9 @@ cleanup:
git_diff_list_free(idx2head);
git_diff_list_free(wd2idx);
+ if (err == GIT_EUSER)
+ giterr_clear();
+
return err;
}
diff --git a/src/submodule.c b/src/submodule.c
index a9de9ee6..66f1f84b 100644
--- a/src/submodule.c
+++ b/src/submodule.c
@@ -163,6 +163,7 @@ int git_submodule_foreach(
}
if (callback(sm, sm->name, payload)) {
+ giterr_clear();
error = GIT_EUSER;
break;
}
diff --git a/src/tag.c b/src/tag.c
index 463619f6..6495d470 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -445,20 +445,5 @@ int git_tag_list(git_strarray *tag_names, git_repository *repo)
int git_tag_peel(git_object **tag_target, git_tag *tag)
{
- int error;
- git_object *target;
-
- assert(tag_target && tag);
-
- if (git_tag_target(&target, tag) < 0)
- return -1;
-
- if (git_object_type(target) == GIT_OBJ_TAG) {
- error = git_tag_peel(tag_target, (git_tag *)target);
- git_object_free(target);
- return error;
- }
-
- *tag_target = target;
- return 0;
+ return git_object_peel(tag_target, (git_object *)tag, GIT_OBJ_ANY);
}
diff --git a/src/unix/map.c b/src/unix/map.c
index 9dcae584..ee7888c1 100644
--- a/src/unix/map.c
+++ b/src/unix/map.c
@@ -31,6 +31,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
mflag = MAP_SHARED;
else if ((flags & GIT_MAP_TYPE) == GIT_MAP_PRIVATE)
mflag = MAP_PRIVATE;
+ else
+ mflag = MAP_SHARED;
out->data = mmap(NULL, len, mprot, mflag, fd, offset);
diff --git a/src/win32/dir.c b/src/win32/dir.c
index bc3d40fa..5cb1082b 100644
--- a/src/win32/dir.c
+++ b/src/win32/dir.c
@@ -7,7 +7,6 @@
#define GIT__WIN32_NO_WRAP_DIR
#include "dir.h"
#include "utf-conv.h"
-#include "git2/windows.h"
static int init_filter(char *filter, size_t n, const char *dir)
{
@@ -26,8 +25,8 @@ static int init_filter(char *filter, size_t n, const char *dir)
git__DIR *git__opendir(const char *dir)
{
- char filter[4096];
- wchar_t* filter_w = NULL;
+ char filter[GIT_WIN_PATH];
+ wchar_t filter_w[GIT_WIN_PATH];
git__DIR *new = NULL;
if (!dir || !init_filter(filter, sizeof(filter), dir))
@@ -41,12 +40,8 @@ git__DIR *git__opendir(const char *dir)
if (!new->dir)
goto fail;
- filter_w = gitwin_to_utf16(filter);
- if (!filter_w)
- goto fail;
-
+ git__utf8_to_16(filter_w, GIT_WIN_PATH, filter);
new->h = FindFirstFileW(filter_w, &new->f);
- git__free(filter_w);
if (new->h == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Could not open directory '%s'", dir);
@@ -85,16 +80,9 @@ int git__readdir_ext(
if (wcslen(d->f.cFileName) >= sizeof(entry->d_name))
return -1;
+ git__utf16_to_8(entry->d_name, d->f.cFileName);
entry->d_ino = 0;
- if (WideCharToMultiByte(
- gitwin_get_codepage(), 0, d->f.cFileName, -1,
- entry->d_name, GIT_PATH_MAX, NULL, NULL) == 0)
- {
- giterr_set(GITERR_OS, "Could not convert filename to UTF-8");
- return -1;
- }
-
*result = entry;
if (is_dir != NULL)
@@ -113,8 +101,8 @@ struct git__dirent *git__readdir(git__DIR *d)
void git__rewinddir(git__DIR *d)
{
- char filter[4096];
- wchar_t* filter_w;
+ char filter[GIT_WIN_PATH];
+ wchar_t filter_w[GIT_WIN_PATH];
if (!d)
return;
@@ -125,12 +113,11 @@ void git__rewinddir(git__DIR *d)
d->first = 0;
}
- if (!init_filter(filter, sizeof(filter), d->dir) ||
- (filter_w = gitwin_to_utf16(filter)) == NULL)
+ if (!init_filter(filter, sizeof(filter), d->dir))
return;
+ git__utf8_to_16(filter_w, GIT_WIN_PATH, filter);
d->h = FindFirstFileW(filter_w, &d->f);
- git__free(filter_w);
if (d->h == INVALID_HANDLE_VALUE)
giterr_set(GITERR_OS, "Could not open directory '%s'", d->dir);
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 14caae41..da46cf51 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -21,13 +21,10 @@ GIT_INLINE(int) p_link(const char *old, const char *new)
GIT_INLINE(int) p_mkdir(const char *path, mode_t mode)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret = _wmkdir(buf);
-
+ wchar_t buf[GIT_WIN_PATH];
GIT_UNUSED(mode);
-
- git__free(buf);
- return ret;
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wmkdir(buf);
}
extern int p_unlink(const char *path);
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index aa34ad3a..649fe9b9 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -15,16 +15,10 @@
int p_unlink(const char *path)
{
- int ret = 0;
- wchar_t* buf;
-
- if ((buf = gitwin_to_utf16(path)) != NULL) {
- _wchmod(buf, 0666);
- ret = _wunlink(buf);
- git__free(buf);
- }
-
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ _wchmod(buf, 0666);
+ return _wunlink(buf);
}
int p_fsync(int fd)
@@ -61,10 +55,10 @@ GIT_INLINE(time_t) filetime_to_time_t(const FILETIME *ft)
static int do_lstat(const char *file_name, struct stat *buf)
{
WIN32_FILE_ATTRIBUTE_DATA fdata;
+ wchar_t fbuf[GIT_WIN_PATH];
DWORD last_error;
- wchar_t* fbuf = gitwin_to_utf16(file_name);
- if (!fbuf)
- return -1;
+
+ git__utf8_to_16(fbuf, GIT_WIN_PATH, file_name);
if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
int fMode = S_IREAD;
@@ -90,8 +84,6 @@ static int do_lstat(const char *file_name, struct stat *buf)
buf->st_atime = filetime_to_time_t(&(fdata.ftLastAccessTime));
buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
-
- git__free(fbuf);
return 0;
}
@@ -101,7 +93,6 @@ static int do_lstat(const char *file_name, struct stat *buf)
else if (last_error == ERROR_PATH_NOT_FOUND)
errno = ENOTDIR;
- git__free(fbuf);
return -1;
}
@@ -143,7 +134,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
static fpath_func pGetFinalPath = NULL;
HANDLE hFile;
DWORD dwRet;
- wchar_t* link_w;
+ wchar_t link_w[GIT_WIN_PATH];
wchar_t* target_w;
int error = 0;
@@ -166,8 +157,7 @@ int p_readlink(const char *link, char *target, size_t target_len)
}
}
- link_w = gitwin_to_utf16(link);
- GITERR_CHECK_ALLOC(link_w);
+ git__utf8_to_16(link_w, GIT_WIN_PATH, link);
hFile = CreateFileW(link_w, // file to open
GENERIC_READ, // open for reading
@@ -177,8 +167,6 @@ int p_readlink(const char *link, char *target, size_t target_len)
FILE_FLAG_BACKUP_SEMANTICS, // normal file
NULL); // no attr. template
- git__free(link_w);
-
if (hFile == INVALID_HANDLE_VALUE) {
giterr_set(GITERR_OS, "Cannot open '%s' for reading", link);
return -1;
@@ -235,16 +223,12 @@ int p_symlink(const char *old, const char *new)
int p_open(const char *path, int flags, ...)
{
- int fd;
- wchar_t* buf;
+ wchar_t buf[GIT_WIN_PATH];
mode_t mode = 0;
- buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
- if (flags & O_CREAT)
- {
+ if (flags & O_CREAT) {
va_list arg_list;
va_start(arg_list, flags);
@@ -252,27 +236,20 @@ int p_open(const char *path, int flags, ...)
va_end(arg_list);
}
- fd = _wopen(buf, flags | _O_BINARY, mode);
-
- git__free(buf);
- return fd;
+ return _wopen(buf, flags | _O_BINARY, mode);
}
int p_creat(const char *path, mode_t mode)
{
- int fd;
- wchar_t* buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
- fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
- git__free(buf);
- return fd;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
}
int p_getcwd(char *buffer_out, size_t size)
{
int ret;
- wchar_t* buf;
+ wchar_t *buf;
if ((size_t)((int)size) != size)
return -1;
@@ -296,64 +273,43 @@ int p_stat(const char* path, struct stat* buf)
int p_chdir(const char* path)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wchdir(buf);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wchdir(buf);
}
int p_chmod(const char* path, mode_t mode)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wchmod(buf, mode);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wchmod(buf, mode);
}
int p_rmdir(const char* path)
{
- wchar_t* buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
- ret = _wrmdir(buf);
- git__free(buf);
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _wrmdir(buf);
}
int p_hide_directory__w32(const char *path)
{
- int res;
- wchar_t* buf = gitwin_to_utf16(path);
- if (!buf)
- return -1;
-
- res = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN);
- git__free(buf);
-
- return (res != 0) ? 0 : -1; /* MSDN states a "non zero" value indicates a success */
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return (SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0) ? 0 : -1;
}
char *p_realpath(const char *orig_path, char *buffer)
{
int ret, buffer_sz = 0;
- wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
- wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
-
- if (!orig_path_w || !buffer_w)
- return NULL;
+ wchar_t orig_path_w[GIT_WIN_PATH];
+ wchar_t buffer_w[GIT_WIN_PATH];
- ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
- git__free(orig_path_w);
+ git__utf8_to_16(orig_path_w, GIT_WIN_PATH, orig_path);
+ ret = GetFullPathNameW(orig_path_w, GIT_WIN_PATH, buffer_w, NULL);
/* According to MSDN, a return value equals to zero means a failure. */
- if (ret == 0 || ret > GIT_PATH_MAX) {
+ if (ret == 0 || ret > GIT_WIN_PATH) {
buffer = NULL;
goto done;
}
@@ -376,8 +332,7 @@ char *p_realpath(const char *orig_path, char *buffer)
}
}
- if (!git_path_exists(buffer))
- {
+ if (!git_path_exists(buffer)) {
if (buffer_sz > 0)
git__free(buffer);
@@ -386,9 +341,9 @@ char *p_realpath(const char *orig_path, char *buffer)
}
done:
- git__free(buffer_w);
if (buffer)
git_path_mkposix(buffer);
+
return buffer;
}
@@ -443,32 +398,19 @@ int p_setenv(const char* name, const char* value, int overwrite)
int p_access(const char* path, mode_t mode)
{
- wchar_t *buf = gitwin_to_utf16(path);
- int ret;
- if (!buf)
- return -1;
-
- ret = _waccess(buf, mode);
- git__free(buf);
-
- return ret;
+ wchar_t buf[GIT_WIN_PATH];
+ git__utf8_to_16(buf, GIT_WIN_PATH, path);
+ return _waccess(buf, mode);
}
int p_rename(const char *from, const char *to)
{
- wchar_t *wfrom = gitwin_to_utf16(from);
- wchar_t *wto = gitwin_to_utf16(to);
- int ret;
-
- if (!wfrom || !wto)
- return -1;
-
- ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
-
- git__free(wfrom);
- git__free(wto);
+ wchar_t wfrom[GIT_WIN_PATH];
+ wchar_t wto[GIT_WIN_PATH];
- return ret;
+ git__utf8_to_16(wfrom, GIT_WIN_PATH, from);
+ git__utf8_to_16(wto, GIT_WIN_PATH, to);
+ return MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? 0 : -1;
}
int p_recv(GIT_SOCKET socket, void *buffer, size_t length, int flags)
diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c
index 0a705c0a..88a84141 100644
--- a/src/win32/utf-conv.c
+++ b/src/win32/utf-conv.c
@@ -7,86 +7,75 @@
#include "common.h"
#include "utf-conv.h"
-#include "git2/windows.h"
-/*
- * Default codepage value
- */
-static int _active_codepage = CP_UTF8;
-
-void gitwin_set_codepage(unsigned int codepage)
-{
- _active_codepage = codepage;
-}
-
-unsigned int gitwin_get_codepage(void)
-{
- return _active_codepage;
-}
-
-void gitwin_set_utf8(void)
-{
- _active_codepage = CP_UTF8;
-}
+#define U16_LEAD(c) (wchar_t)(((c)>>10)+0xd7c0)
+#define U16_TRAIL(c) (wchar_t)(((c)&0x3ff)|0xdc00)
-wchar_t* gitwin_to_utf16(const char* str)
+#if 0
+void git__utf8_to_16(wchar_t *dest, size_t length, const char *src)
{
- wchar_t* ret;
- int cb;
-
- if (!str)
- return NULL;
-
- cb = MultiByteToWideChar(_active_codepage, 0, str, -1, NULL, 0);
- if (cb == 0)
- return (wchar_t *)git__calloc(1, sizeof(wchar_t));
-
- ret = (wchar_t *)git__malloc(cb * sizeof(wchar_t));
- if (!ret)
- return NULL;
-
- if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, (int)cb) == 0) {
- giterr_set(GITERR_OS, "Could not convert string to UTF-16");
- git__free(ret);
- ret = NULL;
+ wchar_t *pDest = dest;
+ uint32_t ch;
+ const uint8_t* pSrc = (uint8_t*) src;
+
+ assert(dest && src && length);
+
+ length--;
+
+ while(*pSrc && length > 0) {
+ ch = *pSrc++;
+ length--;
+
+ if(ch < 0xc0) {
+ /*
+ * ASCII, or a trail byte in lead position which is treated like
+ * a single-byte sequence for better character boundary
+ * resynchronization after illegal sequences.
+ */
+ *pDest++ = (wchar_t)ch;
+ continue;
+ } else if(ch < 0xe0) { /* U+0080..U+07FF */
+ if (pSrc[0]) {
+ /* 0x3080 = (0xc0 << 6) + 0x80 */
+ *pDest++ = (wchar_t)((ch << 6) + *pSrc++ - 0x3080);
+ continue;
+ }
+ } else if(ch < 0xf0) { /* U+0800..U+FFFF */
+ if (pSrc[0] && pSrc[1]) {
+ /* no need for (ch & 0xf) because the upper bits are truncated after <<12 in the cast to (UChar) */
+ /* 0x2080 = (0x80 << 6) + 0x80 */
+ ch = (ch << 12) + (*pSrc++ << 6);
+ *pDest++ = (wchar_t)(ch + *pSrc++ - 0x2080);
+ continue;
+ }
+ } else /* f0..f4 */ { /* U+10000..U+10FFFF */
+ if (length >= 1 && pSrc[0] && pSrc[1] && pSrc[2]) {
+ /* 0x3c82080 = (0xf0 << 18) + (0x80 << 12) + (0x80 << 6) + 0x80 */
+ ch = (ch << 18) + (*pSrc++ << 12);
+ ch += *pSrc++ << 6;
+ ch += *pSrc++ - 0x3c82080;
+ *(pDest++) = U16_LEAD(ch);
+ *(pDest++) = U16_TRAIL(ch);
+ length--; /* two bytes for this character */
+ continue;
+ }
+ }
+
+ /* truncated character at the end */
+ *pDest++ = 0xfffd;
+ break;
}
- return ret;
+ *pDest++ = 0x0;
}
+#endif
-int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len)
+void git__utf8_to_16(wchar_t *dest, size_t length, const char *src)
{
- int result = MultiByteToWideChar(
- _active_codepage, 0, str, -1, buffer, (int)len);
- if (result == 0)
- giterr_set(GITERR_OS, "Could not convert string to UTF-16");
- return result;
+ MultiByteToWideChar(CP_UTF8, 0, src, -1, dest, length);
}
-char* gitwin_from_utf16(const wchar_t* str)
+void git__utf16_to_8(char *out, const wchar_t *input)
{
- char* ret;
- int cb;
-
- if (!str)
- return NULL;
-
- cb = WideCharToMultiByte(_active_codepage, 0, str, -1, NULL, 0, NULL, NULL);
- if (cb == 0)
- return (char *)git__calloc(1, sizeof(char));
-
- ret = (char*)git__malloc(cb);
- if (!ret)
- return NULL;
-
- if (WideCharToMultiByte(
- _active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0)
- {
- giterr_set(GITERR_OS, "Could not convert string to UTF-8");
- git__free(ret);
- ret = NULL;
- }
-
- return ret;
-
+ WideCharToMultiByte(CP_UTF8, 0, input, -1, out, GIT_WIN_PATH, NULL, NULL);
}
diff --git a/src/win32/utf-conv.h b/src/win32/utf-conv.h
index ae9f29f6..3bd1549b 100644
--- a/src/win32/utf-conv.h
+++ b/src/win32/utf-conv.h
@@ -10,9 +10,10 @@
#ifndef INCLUDE_git_utfconv_h__
#define INCLUDE_git_utfconv_h__
-wchar_t* gitwin_to_utf16(const char* str);
-int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len);
-char* gitwin_from_utf16(const wchar_t* str);
+#define GIT_WIN_PATH (260 + 1)
+
+void git__utf8_to_16(wchar_t *dest, size_t length, const char *src);
+void git__utf16_to_8(char *dest, const wchar_t *src);
#endif
diff --git a/tests-clar/clar_helpers.c b/tests-clar/clar_helpers.c
index c9147943..8d6a7024 100644
--- a/tests-clar/clar_helpers.c
+++ b/tests-clar/clar_helpers.c
@@ -9,6 +9,7 @@ void clar_on_init(void)
void clar_on_shutdown(void)
{
git_threads_shutdown();
+ giterr_clear();
}
void cl_git_mkfile(const char *filename, const char *content)
@@ -55,22 +56,23 @@ void cl_git_rewritefile(const char *filename, const char *new_content)
char *cl_getenv(const char *name)
{
- wchar_t *name_utf16 = gitwin_to_utf16(name);
- DWORD value_len, alloc_len;
+ wchar_t name_utf16[GIT_WIN_PATH];
+ DWORD alloc_len;
wchar_t *value_utf16;
char *value_utf8;
- cl_assert(name_utf16);
+ git__utf8_to_16(name_utf16, GIT_WIN_PATH, name);
alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0);
if (alloc_len <= 0)
return NULL;
+ alloc_len = GIT_WIN_PATH;
cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t)));
- value_len = GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len);
- cl_assert_equal_i(value_len, alloc_len - 1);
+ GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len);
- cl_assert(value_utf8 = gitwin_from_utf16(value_utf16));
+ cl_assert(value_utf8 = git__malloc(alloc_len));
+ git__utf16_to_8(value_utf8, value_utf16);
git__free(value_utf16);
@@ -79,17 +81,16 @@ char *cl_getenv(const char *name)
int cl_setenv(const char *name, const char *value)
{
- wchar_t *name_utf16 = gitwin_to_utf16(name);
- wchar_t *value_utf16 = value ? gitwin_to_utf16(value) : NULL;
+ wchar_t name_utf16[GIT_WIN_PATH];
+ wchar_t value_utf16[GIT_WIN_PATH];
- cl_assert(name_utf16);
- cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16));
+ git__utf8_to_16(name_utf16, GIT_WIN_PATH, name);
- git__free(name_utf16);
- git__free(value_utf16);
+ if (value != NULL)
+ git__utf8_to_16(value_utf16, GIT_WIN_PATH, value);
+ cl_assert(SetEnvironmentVariableW(name_utf16, value ? value_utf16 : NULL));
return 0;
-
}
#else
diff --git a/tests-clar/diff/blob.c b/tests-clar/diff/blob.c
index 5d3ab8d5..d5cf41e9 100644
--- a/tests-clar/diff/blob.c
+++ b/tests-clar/diff/blob.c
@@ -58,59 +58,59 @@ void test_diff_blob__can_compare_text_blobs(void)
cl_git_pass(git_diff_blobs(
a, b, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_mods == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_mods);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 1);
- cl_assert(expected.lines == 6);
- cl_assert(expected.line_ctxt == 1);
- cl_assert(expected.line_adds == 5);
- cl_assert(expected.line_dels == 0);
+ cl_assert_equal_i(1, expected.hunks);
+ cl_assert_equal_i(6, expected.lines);
+ cl_assert_equal_i(1, expected.line_ctxt);
+ cl_assert_equal_i(5, expected.line_adds);
+ cl_assert_equal_i(0, expected.line_dels);
/* diff on tests/resources/attr/root_test2 */
memset(&expected, 0, sizeof(expected));
cl_git_pass(git_diff_blobs(
b, c, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_mods == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_mods);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 1);
- cl_assert(expected.lines == 15);
- cl_assert(expected.line_ctxt == 3);
- cl_assert(expected.line_adds == 9);
- cl_assert(expected.line_dels == 3);
+ cl_assert_equal_i(1, expected.hunks);
+ cl_assert_equal_i(15, expected.lines);
+ cl_assert_equal_i(3, expected.line_ctxt);
+ cl_assert_equal_i(9, expected.line_adds);
+ cl_assert_equal_i(3, expected.line_dels);
/* diff on tests/resources/attr/root_test3 */
memset(&expected, 0, sizeof(expected));
cl_git_pass(git_diff_blobs(
a, c, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_mods == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_mods);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 1);
- cl_assert(expected.lines == 13);
- cl_assert(expected.line_ctxt == 0);
- cl_assert(expected.line_adds == 12);
- cl_assert(expected.line_dels == 1);
+ cl_assert_equal_i(1, expected.hunks);
+ cl_assert_equal_i(13, expected.lines);
+ cl_assert_equal_i(0, expected.line_ctxt);
+ cl_assert_equal_i(12, expected.line_adds);
+ cl_assert_equal_i(1, expected.line_dels);
memset(&expected, 0, sizeof(expected));
cl_git_pass(git_diff_blobs(
c, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_mods == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_mods);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 2);
- cl_assert(expected.lines == 14);
- cl_assert(expected.line_ctxt == 4);
- cl_assert(expected.line_adds == 6);
- cl_assert(expected.line_dels == 4);
+ cl_assert_equal_i(2, expected.hunks);
+ cl_assert_equal_i(14, expected.lines);
+ cl_assert_equal_i(4, expected.line_ctxt);
+ cl_assert_equal_i(6, expected.line_adds);
+ cl_assert_equal_i(4, expected.line_dels);
git_blob_free(a);
git_blob_free(b);
@@ -124,14 +124,14 @@ void test_diff_blob__can_compare_against_null_blobs(void)
cl_git_pass(git_diff_blobs(
d, e, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_dels == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_dels);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 1);
- cl_assert(expected.hunk_old_lines == 14);
- cl_assert(expected.lines == 14);
- cl_assert(expected.line_dels == 14);
+ cl_assert_equal_i(1, expected.hunks);
+ cl_assert_equal_i(14, expected.hunk_old_lines);
+ cl_assert_equal_i(14, expected.lines);
+ cl_assert_equal_i(14, expected.line_dels);
opts.flags |= GIT_DIFF_REVERSE;
memset(&expected, 0, sizeof(expected));
@@ -139,14 +139,14 @@ void test_diff_blob__can_compare_against_null_blobs(void)
cl_git_pass(git_diff_blobs(
d, e, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.files == 1);
- cl_assert(expected.file_adds == 1);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_adds);
cl_assert(expected.at_least_one_of_them_is_binary == false);
- cl_assert(expected.hunks == 1);
- cl_assert(expected.hunk_new_lines == 14);
- cl_assert(expected.lines == 14);
- cl_assert(expected.line_adds == 14);
+ cl_assert_equal_i(1, expected.hunks);
+ cl_assert_equal_i(14, expected.hunk_new_lines);
+ cl_assert_equal_i(14, expected.lines);
+ cl_assert_equal_i(14, expected.line_adds);
opts.flags ^= GIT_DIFF_REVERSE;
memset(&expected, 0, sizeof(expected));
@@ -156,10 +156,10 @@ void test_diff_blob__can_compare_against_null_blobs(void)
cl_assert(expected.at_least_one_of_them_is_binary == true);
- cl_assert(expected.files == 1);
- cl_assert(expected.file_dels == 1);
- cl_assert(expected.hunks == 0);
- cl_assert(expected.lines == 0);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_dels);
+ cl_assert_equal_i(0, expected.hunks);
+ cl_assert_equal_i(0, expected.lines);
memset(&expected, 0, sizeof(expected));
@@ -168,18 +168,18 @@ void test_diff_blob__can_compare_against_null_blobs(void)
cl_assert(expected.at_least_one_of_them_is_binary == true);
- cl_assert(expected.files == 1);
- cl_assert(expected.file_adds == 1);
- cl_assert(expected.hunks == 0);
- cl_assert(expected.lines == 0);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_adds);
+ cl_assert_equal_i(0, expected.hunks);
+ cl_assert_equal_i(0, expected.lines);
}
static void assert_identical_blobs_comparison(diff_expects expected)
{
- cl_assert(expected.files == 1);
- cl_assert(expected.file_unmodified == 1);
- cl_assert(expected.hunks == 0);
- cl_assert(expected.lines == 0);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_unmodified);
+ cl_assert_equal_i(0, expected.hunks);
+ cl_assert_equal_i(0, expected.lines);
}
void test_diff_blob__can_compare_identical_blobs(void)
@@ -209,10 +209,10 @@ static void assert_binary_blobs_comparison(diff_expects expected)
{
cl_assert(expected.at_least_one_of_them_is_binary == true);
- cl_assert(expected.files == 1);
- cl_assert(expected.file_mods == 1);
- cl_assert(expected.hunks == 0);
- cl_assert(expected.lines == 0);
+ cl_assert_equal_i(1, expected.files);
+ cl_assert_equal_i(1, expected.file_mods);
+ cl_assert_equal_i(0, expected.hunks);
+ cl_assert_equal_i(0, expected.lines);
}
void test_diff_blob__can_compare_two_binary_blobs(void)
@@ -292,7 +292,7 @@ void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
cl_git_pass(git_diff_blobs(
old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.hunks == 2);
+ cl_assert_equal_i(2, expected.hunks);
/* Test with inter-hunk-context explicitly set to 0 */
opts.interhunk_lines = 0;
@@ -300,7 +300,7 @@ void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
cl_git_pass(git_diff_blobs(
old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.hunks == 2);
+ cl_assert_equal_i(2, expected.hunks);
/* Test with inter-hunk-context explicitly set to 1 */
opts.interhunk_lines = 1;
@@ -308,7 +308,7 @@ void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void)
cl_git_pass(git_diff_blobs(
old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(expected.hunks == 1);
+ cl_assert_equal_i(1, expected.hunks);
git_blob_free(old_d);
}
diff --git a/tests-clar/diff/diff_helpers.c b/tests-clar/diff/diff_helpers.c
index 7b391262..59e01802 100644
--- a/tests-clar/diff/diff_helpers.c
+++ b/tests-clar/diff/diff_helpers.c
@@ -103,3 +103,74 @@ int diff_line_fn(
}
return 0;
}
+
+int diff_foreach_via_iterator(
+ git_diff_list *diff,
+ void *data,
+ git_diff_file_fn file_cb,
+ git_diff_hunk_fn hunk_cb,
+ git_diff_data_fn line_cb)
+{
+ int error, curr, total;
+ git_diff_iterator *iter;
+ git_diff_delta *delta;
+
+ if ((error = git_diff_iterator_new(&iter, diff)) < 0)
+ return error;
+
+ curr = 0;
+ total = git_diff_iterator_num_files(iter);
+
+ while (!(error = git_diff_iterator_next_file(&delta, iter))) {
+ git_diff_range *range;
+ const char *hdr;
+ size_t hdr_len;
+
+ /* call file_cb for this file */
+ if (file_cb != NULL && file_cb(data, delta, (float)curr / total) != 0)
+ goto abort;
+
+ if (!hunk_cb && !line_cb)
+ continue;
+
+ while (!(error = git_diff_iterator_next_hunk(
+ &range, &hdr, &hdr_len, iter))) {
+ char origin;
+ const char *line;
+ size_t line_len;
+
+ if (hunk_cb && hunk_cb(data, delta, range, hdr, hdr_len) != 0)
+ goto abort;
+
+ if (!line_cb)
+ continue;
+
+ while (!(error = git_diff_iterator_next_line(
+ &origin, &line, &line_len, iter))) {
+
+ if (line_cb(data, delta, range, origin, line, line_len) != 0)
+ goto abort;
+ }
+
+ if (error && error != GIT_ITEROVER)
+ goto done;
+ }
+
+ if (error && error != GIT_ITEROVER)
+ goto done;
+ }
+
+done:
+ git_diff_iterator_free(iter);
+
+ if (error == GIT_ITEROVER)
+ error = 0;
+
+ return error;
+
+abort:
+ git_diff_iterator_free(iter);
+ giterr_clear();
+
+ return GIT_EUSER;
+}
diff --git a/tests-clar/diff/diff_helpers.h b/tests-clar/diff/diff_helpers.h
index 0aaa6c11..79e14092 100644
--- a/tests-clar/diff/diff_helpers.h
+++ b/tests-clar/diff/diff_helpers.h
@@ -45,3 +45,9 @@ extern int diff_line_fn(
const char *content,
size_t content_len);
+extern int diff_foreach_via_iterator(
+ git_diff_list *diff,
+ void *data,
+ git_diff_file_fn file_cb,
+ git_diff_hunk_fn hunk_cb,
+ git_diff_data_fn line_cb);
diff --git a/tests-clar/diff/diffiter.c b/tests-clar/diff/diffiter.c
new file mode 100644
index 00000000..56c25474
--- /dev/null
+++ b/tests-clar/diff/diffiter.c
@@ -0,0 +1,116 @@
+#include "clar_libgit2.h"
+#include "diff_helpers.h"
+
+void test_diff_diffiter__initialize(void)
+{
+}
+
+void test_diff_diffiter__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+void test_diff_diffiter__create(void)
+{
+ git_repository *repo = cl_git_sandbox_init("attr");
+ git_diff_list *diff;
+ git_diff_iterator *iter;
+
+ cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff));
+ cl_git_pass(git_diff_iterator_new(&iter, diff));
+ git_diff_iterator_free(iter);
+ git_diff_list_free(diff);
+}
+
+void test_diff_diffiter__iterate_files(void)
+{
+ git_repository *repo = cl_git_sandbox_init("attr");
+ git_diff_list *diff;
+ git_diff_iterator *iter;
+ git_diff_delta *delta;
+ int error, count = 0;
+
+ cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff));
+ cl_git_pass(git_diff_iterator_new(&iter, diff));
+
+ while ((error = git_diff_iterator_next_file(&delta, iter)) != GIT_ITEROVER) {
+ cl_assert_equal_i(0, error);
+ cl_assert(delta != NULL);
+ count++;
+ }
+
+ cl_assert_equal_i(GIT_ITEROVER, error);
+ cl_assert(delta == NULL);
+ cl_assert_equal_i(6, count);
+
+ git_diff_iterator_free(iter);
+ git_diff_list_free(diff);
+}
+
+void test_diff_diffiter__iterate_files_2(void)
+{
+ git_repository *repo = cl_git_sandbox_init("status");
+ git_diff_list *diff;
+ git_diff_iterator *iter;
+ git_diff_delta *delta;
+ int error, count = 0;
+
+ cl_git_pass(git_diff_workdir_to_index(repo, NULL, &diff));
+ cl_git_pass(git_diff_iterator_new(&iter, diff));
+
+ while ((error = git_diff_iterator_next_file(&delta, iter)) != GIT_ITEROVER) {
+ cl_assert_equal_i(0, error);
+ cl_assert(delta != NULL);
+ count++;
+ }
+
+ cl_assert_equal_i(GIT_ITEROVER, error);
+ cl_assert(delta == NULL);
+ cl_assert_equal_i(8, count);
+
+ git_diff_iterator_free(iter);
+ git_diff_list_free(diff);
+}
+
+void test_diff_diffiter__iterate_files_and_hunks(void)
+{
+ git_repository *repo = cl_git_sandbox_init("status");
+ git_diff_options opts = {0};
+ git_diff_list *diff = NULL;
+ git_diff_iterator *iter;
+ git_diff_delta *delta;
+ git_diff_range *range;
+ const char *header;
+ size_t header_len;
+ int error, file_count = 0, hunk_count = 0;
+
+ opts.context_lines = 3;
+ opts.interhunk_lines = 1;
+ opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
+
+ cl_git_pass(git_diff_workdir_to_index(repo, &opts, &diff));
+
+ cl_git_pass(git_diff_iterator_new(&iter, diff));
+
+ while ((error = git_diff_iterator_next_file(&delta, iter)) != GIT_ITEROVER) {
+ cl_assert_equal_i(0, error);
+ cl_assert(delta);
+
+ file_count++;
+
+ while ((error = git_diff_iterator_next_hunk(
+ &range, &header, &header_len, iter)) != GIT_ITEROVER) {
+ cl_assert_equal_i(0, error);
+ cl_assert(range);
+ hunk_count++;
+ }
+ }
+
+ cl_assert_equal_i(GIT_ITEROVER, error);
+ cl_assert(delta == NULL);
+ cl_assert_equal_i(13, file_count);
+ cl_assert_equal_i(8, hunk_count);
+
+ git_diff_iterator_free(iter);
+ git_diff_list_free(diff);
+}
diff --git a/tests-clar/diff/index.c b/tests-clar/diff/index.c
index 89e65e3b..2c6e89c4 100644
--- a/tests-clar/diff/index.c
+++ b/tests-clar/diff/index.c
@@ -44,17 +44,17 @@ void test_diff_index__0(void)
* - git diff -U1 --cached 26a125ee1bf
* - mv .git .gitted
*/
- cl_assert(exp.files == 8);
- cl_assert(exp.file_adds == 3);
- cl_assert(exp.file_dels == 2);
- cl_assert(exp.file_mods == 3);
+ cl_assert_equal_i(8, exp.files);
+ cl_assert_equal_i(3, exp.file_adds);
+ cl_assert_equal_i(2, exp.file_dels);
+ cl_assert_equal_i(3, exp.file_mods);
- cl_assert(exp.hunks == 8);
+ cl_assert_equal_i(8, exp.hunks);
- cl_assert(exp.lines == 11);
- cl_assert(exp.line_ctxt == 3);
- cl_assert(exp.line_adds == 6);
- cl_assert(exp.line_dels == 2);
+ cl_assert_equal_i(11, exp.lines);
+ cl_assert_equal_i(3, exp.line_ctxt);
+ cl_assert_equal_i(6, exp.line_adds);
+ cl_assert_equal_i(2, exp.line_dels);
git_diff_list_free(diff);
diff = NULL;
@@ -72,17 +72,17 @@ void test_diff_index__0(void)
* - git diff -U1 --cached 0017bd4ab1ec3
* - mv .git .gitted
*/
- cl_assert(exp.files == 12);
- cl_assert(exp.file_adds == 7);
- cl_assert(exp.file_dels == 2);
- cl_assert(exp.file_mods == 3);
+ cl_assert_equal_i(12, exp.files);
+ cl_assert_equal_i(7, exp.file_adds);
+ cl_assert_equal_i(2, exp.file_dels);
+ cl_assert_equal_i(3, exp.file_mods);
- cl_assert(exp.hunks == 12);
+ cl_assert_equal_i(12, exp.hunks);
- cl_assert(exp.lines == 16);
- cl_assert(exp.line_ctxt == 3);
- cl_assert(exp.line_adds == 11);
- cl_assert(exp.line_dels == 2);
+ cl_assert_equal_i(16, exp.lines);
+ cl_assert_equal_i(3, exp.line_ctxt);
+ cl_assert_equal_i(11, exp.line_adds);
+ cl_assert_equal_i(2, exp.line_dels);
git_diff_list_free(diff);
diff = NULL;
@@ -132,7 +132,7 @@ void test_diff_index__1(void)
git_diff_foreach(diff, &exp, diff_stop_after_2_files, NULL, NULL)
);
- cl_assert(exp.files == 2);
+ cl_assert_equal_i(2, exp.files);
git_diff_list_free(diff);
diff = NULL;
diff --git a/tests-clar/diff/tree.c b/tests-clar/diff/tree.c
index be9eb6c1..3003374a 100644
--- a/tests-clar/diff/tree.c
+++ b/tests-clar/diff/tree.c
@@ -39,17 +39,17 @@ void test_diff_tree__0(void)
cl_git_pass(git_diff_foreach(
diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(exp.files == 5);
- cl_assert(exp.file_adds == 2);
- cl_assert(exp.file_dels == 1);
- cl_assert(exp.file_mods == 2);
+ cl_assert_equal_i(5, exp.files);
+ cl_assert_equal_i(2, exp.file_adds);
+ cl_assert_equal_i(1, exp.file_dels);
+ cl_assert_equal_i(2, exp.file_mods);
- cl_assert(exp.hunks == 5);
+ cl_assert_equal_i(5, exp.hunks);
- cl_assert(exp.lines == 7 + 24 + 1 + 6 + 6);
- cl_assert(exp.line_ctxt == 1);
- cl_assert(exp.line_adds == 24 + 1 + 5 + 5);
- cl_assert(exp.line_dels == 7 + 1);
+ cl_assert_equal_i(7 + 24 + 1 + 6 + 6, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(24 + 1 + 5 + 5, exp.line_adds);
+ cl_assert_equal_i(7 + 1, exp.line_dels);
git_diff_list_free(diff);
diff = NULL;
@@ -61,17 +61,17 @@ void test_diff_tree__0(void)
cl_git_pass(git_diff_foreach(
diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(exp.files == 2);
- cl_assert(exp.file_adds == 0);
- cl_assert(exp.file_dels == 0);
- cl_assert(exp.file_mods == 2);
+ cl_assert_equal_i(2, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(2, exp.file_mods);
- cl_assert(exp.hunks == 2);
+ cl_assert_equal_i(2, exp.hunks);
- cl_assert(exp.lines == 8 + 15);
- cl_assert(exp.line_ctxt == 1);
- cl_assert(exp.line_adds == 1);
- cl_assert(exp.line_dels == 7 + 14);
+ cl_assert_equal_i(8 + 15, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(1, exp.line_adds);
+ cl_assert_equal_i(7 + 14, exp.line_dels);
git_diff_list_free(diff);
@@ -192,17 +192,17 @@ void test_diff_tree__bare(void)
cl_git_pass(git_diff_foreach(
diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(exp.files == 3);
- cl_assert(exp.file_adds == 2);
- cl_assert(exp.file_dels == 0);
- cl_assert(exp.file_mods == 1);
+ cl_assert_equal_i(3, exp.files);
+ cl_assert_equal_i(2, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
- cl_assert(exp.hunks == 3);
+ cl_assert_equal_i(3, exp.hunks);
- cl_assert(exp.lines == 4);
- cl_assert(exp.line_ctxt == 0);
- cl_assert(exp.line_adds == 3);
- cl_assert(exp.line_dels == 1);
+ cl_assert_equal_i(4, exp.lines);
+ cl_assert_equal_i(0, exp.line_ctxt);
+ cl_assert_equal_i(3, exp.line_adds);
+ cl_assert_equal_i(1, exp.line_dels);
git_diff_list_free(diff);
git_tree_free(a);
@@ -242,17 +242,17 @@ void test_diff_tree__merge(void)
cl_git_pass(git_diff_foreach(
diff1, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert(exp.files == 6);
- cl_assert(exp.file_adds == 2);
- cl_assert(exp.file_dels == 1);
- cl_assert(exp.file_mods == 3);
+ cl_assert_equal_i(6, exp.files);
+ cl_assert_equal_i(2, exp.file_adds);
+ cl_assert_equal_i(1, exp.file_dels);
+ cl_assert_equal_i(3, exp.file_mods);
- cl_assert(exp.hunks == 6);
+ cl_assert_equal_i(6, exp.hunks);
- cl_assert(exp.lines == 59);
- cl_assert(exp.line_ctxt == 1);
- cl_assert(exp.line_adds == 36);
- cl_assert(exp.line_dels == 22);
+ cl_assert_equal_i(59, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(36, exp.line_adds);
+ cl_assert_equal_i(22, exp.line_dels);
git_diff_list_free(diff1);
}
diff --git a/tests-clar/diff/workdir.c b/tests-clar/diff/workdir.c
index 801439e3..eac7eb87 100644
--- a/tests-clar/diff/workdir.c
+++ b/tests-clar/diff/workdir.c
@@ -17,6 +17,7 @@ void test_diff_workdir__to_index(void)
git_diff_options opts = {0};
git_diff_list *diff = NULL;
diff_expects exp;
+ int use_iterator;
g_repo = cl_git_sandbox_init("status");
@@ -24,33 +25,39 @@ void test_diff_workdir__to_index(void)
opts.interhunk_lines = 1;
opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
- memset(&exp, 0, sizeof(exp));
-
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
-
- /* to generate these values:
- * - cd to tests/resources/status,
- * - mv .gitted .git
- * - git diff --name-status
- * - git diff
- * - mv .git .gitted
- */
- cl_assert_equal_i(13, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(4, exp.file_dels);
- cl_assert_equal_i(4, exp.file_mods);
- cl_assert_equal_i(1, exp.file_ignored);
- cl_assert_equal_i(4, exp.file_untracked);
-
- cl_assert_equal_i(8, exp.hunks);
-
- cl_assert_equal_i(14, exp.lines);
- cl_assert_equal_i(5, exp.line_ctxt);
- cl_assert_equal_i(4, exp.line_adds);
- cl_assert_equal_i(5, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ /* to generate these values:
+ * - cd to tests/resources/status,
+ * - mv .gitted .git
+ * - git diff --name-status
+ * - git diff
+ * - mv .git .gitted
+ */
+ cl_assert_equal_i(13, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(4, exp.file_dels);
+ cl_assert_equal_i(4, exp.file_mods);
+ cl_assert_equal_i(1, exp.file_ignored);
+ cl_assert_equal_i(4, exp.file_untracked);
+
+ cl_assert_equal_i(8, exp.hunks);
+
+ cl_assert_equal_i(14, exp.lines);
+ cl_assert_equal_i(5, exp.line_ctxt);
+ cl_assert_equal_i(4, exp.line_adds);
+ cl_assert_equal_i(5, exp.line_dels);
+ }
git_diff_list_free(diff);
}
@@ -65,6 +72,7 @@ void test_diff_workdir__to_tree(void)
git_diff_list *diff = NULL;
git_diff_list *diff2 = NULL;
diff_expects exp;
+ int use_iterator;
g_repo = cl_git_sandbox_init("status");
@@ -75,8 +83,6 @@ void test_diff_workdir__to_tree(void)
opts.interhunk_lines = 1;
opts.flags |= GIT_DIFF_INCLUDE_IGNORED | GIT_DIFF_INCLUDE_UNTRACKED;
- memset(&exp, 0, sizeof(exp));
-
/* You can't really generate the equivalent of git_diff_workdir_to_tree()
* using C git. It really wants to interpose the index into the diff.
*
@@ -89,15 +95,23 @@ void test_diff_workdir__to_tree(void)
*/
cl_git_pass(git_diff_workdir_to_tree(g_repo, &opts, a, &diff));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
- cl_assert_equal_i(14, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(4, exp.file_dels);
- cl_assert_equal_i(4, exp.file_mods);
- cl_assert_equal_i(1, exp.file_ignored);
- cl_assert_equal_i(5, exp.file_untracked);
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(14, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(4, exp.file_dels);
+ cl_assert_equal_i(4, exp.file_mods);
+ cl_assert_equal_i(1, exp.file_ignored);
+ cl_assert_equal_i(5, exp.file_untracked);
+ }
/* Since there is no git diff equivalent, let's just assume that the
* text diffs produced by git_diff_foreach are accurate here. We will
@@ -117,22 +131,30 @@ void test_diff_workdir__to_tree(void)
cl_git_pass(git_diff_merge(diff, diff2));
git_diff_list_free(diff2);
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(15, exp.files);
- cl_assert_equal_i(2, exp.file_adds);
- cl_assert_equal_i(5, exp.file_dels);
- cl_assert_equal_i(4, exp.file_mods);
- cl_assert_equal_i(1, exp.file_ignored);
- cl_assert_equal_i(3, exp.file_untracked);
+ cl_assert_equal_i(15, exp.files);
+ cl_assert_equal_i(2, exp.file_adds);
+ cl_assert_equal_i(5, exp.file_dels);
+ cl_assert_equal_i(4, exp.file_mods);
+ cl_assert_equal_i(1, exp.file_ignored);
+ cl_assert_equal_i(3, exp.file_untracked);
- cl_assert_equal_i(11, exp.hunks);
+ cl_assert_equal_i(11, exp.hunks);
- cl_assert_equal_i(17, exp.lines);
- cl_assert_equal_i(4, exp.line_ctxt);
- cl_assert_equal_i(8, exp.line_adds);
- cl_assert_equal_i(5, exp.line_dels);
+ cl_assert_equal_i(17, exp.lines);
+ cl_assert_equal_i(4, exp.line_ctxt);
+ cl_assert_equal_i(8, exp.line_adds);
+ cl_assert_equal_i(5, exp.line_dels);
+ }
git_diff_list_free(diff);
diff = NULL;
@@ -146,22 +168,30 @@ void test_diff_workdir__to_tree(void)
cl_git_pass(git_diff_merge(diff, diff2));
git_diff_list_free(diff2);
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
- cl_assert_equal_i(16, exp.files);
- cl_assert_equal_i(5, exp.file_adds);
- cl_assert_equal_i(4, exp.file_dels);
- cl_assert_equal_i(3, exp.file_mods);
- cl_assert_equal_i(1, exp.file_ignored);
- cl_assert_equal_i(3, exp.file_untracked);
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(12, exp.hunks);
+ cl_assert_equal_i(16, exp.files);
+ cl_assert_equal_i(5, exp.file_adds);
+ cl_assert_equal_i(4, exp.file_dels);
+ cl_assert_equal_i(3, exp.file_mods);
+ cl_assert_equal_i(1, exp.file_ignored);
+ cl_assert_equal_i(3, exp.file_untracked);
- cl_assert_equal_i(19, exp.lines);
- cl_assert_equal_i(3, exp.line_ctxt);
- cl_assert_equal_i(12, exp.line_adds);
- cl_assert_equal_i(4, exp.line_dels);
+ cl_assert_equal_i(12, exp.hunks);
+
+ cl_assert_equal_i(19, exp.lines);
+ cl_assert_equal_i(3, exp.line_ctxt);
+ cl_assert_equal_i(12, exp.line_adds);
+ cl_assert_equal_i(4, exp.line_dels);
+ }
git_diff_list_free(diff);
@@ -175,6 +205,7 @@ void test_diff_workdir__to_index_with_pathspec(void)
git_diff_list *diff = NULL;
diff_expects exp;
char *pathspec = NULL;
+ int use_iterator;
g_repo = cl_git_sandbox_init("status");
@@ -184,62 +215,93 @@ void test_diff_workdir__to_index_with_pathspec(void)
opts.pathspec.strings = &pathspec;
opts.pathspec.count = 1;
- memset(&exp, 0, sizeof(exp));
-
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
- cl_assert_equal_i(13, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(4, exp.file_dels);
- cl_assert_equal_i(4, exp.file_mods);
- cl_assert_equal_i(1, exp.file_ignored);
- cl_assert_equal_i(4, exp.file_untracked);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, NULL, NULL));
+ else
+ cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
+
+ cl_assert_equal_i(13, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(4, exp.file_dels);
+ cl_assert_equal_i(4, exp.file_mods);
+ cl_assert_equal_i(1, exp.file_ignored);
+ cl_assert_equal_i(4, exp.file_untracked);
+ }
git_diff_list_free(diff);
- memset(&exp, 0, sizeof(exp));
pathspec = "modified_file";
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(0, exp.file_ignored);
- cl_assert_equal_i(0, exp.file_untracked);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, NULL, NULL));
+ else
+ cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(0, exp.file_ignored);
+ cl_assert_equal_i(0, exp.file_untracked);
+ }
git_diff_list_free(diff);
- memset(&exp, 0, sizeof(exp));
pathspec = "subdir";
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
- cl_assert_equal_i(3, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(1, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(0, exp.file_ignored);
- cl_assert_equal_i(1, exp.file_untracked);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, NULL, NULL));
+ else
+ cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
+
+ cl_assert_equal_i(3, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(1, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(0, exp.file_ignored);
+ cl_assert_equal_i(1, exp.file_untracked);
+ }
git_diff_list_free(diff);
- memset(&exp, 0, sizeof(exp));
pathspec = "*_deleted";
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
- cl_assert_equal_i(2, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(2, exp.file_dels);
- cl_assert_equal_i(0, exp.file_mods);
- cl_assert_equal_i(0, exp.file_ignored);
- cl_assert_equal_i(0, exp.file_untracked);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, NULL, NULL));
+ else
+ cl_git_pass(git_diff_foreach(diff, &exp, diff_file_fn, NULL, NULL));
+
+ cl_assert_equal_i(2, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(2, exp.file_dels);
+ cl_assert_equal_i(0, exp.file_mods);
+ cl_assert_equal_i(0, exp.file_ignored);
+ cl_assert_equal_i(0, exp.file_untracked);
+ }
git_diff_list_free(diff);
}
@@ -249,6 +311,7 @@ void test_diff_workdir__filemode_changes(void)
git_config *cfg;
git_diff_list *diff = NULL;
diff_expects exp;
+ int use_iterator;
if (!cl_is_chmod_supported())
return;
@@ -262,13 +325,20 @@ void test_diff_workdir__filemode_changes(void)
cl_git_pass(git_diff_workdir_to_index(g_repo, NULL, &diff));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
- cl_assert_equal_i(0, exp.files);
- cl_assert_equal_i(0, exp.file_mods);
- cl_assert_equal_i(0, exp.hunks);
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(0, exp.files);
+ cl_assert_equal_i(0, exp.file_mods);
+ cl_assert_equal_i(0, exp.hunks);
+ }
git_diff_list_free(diff);
@@ -278,13 +348,20 @@ void test_diff_workdir__filemode_changes(void)
cl_git_pass(git_diff_workdir_to_index(g_repo, NULL, &diff));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(0, exp.hunks);
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(0, exp.hunks);
+ }
git_diff_list_free(diff);
@@ -347,6 +424,7 @@ void test_diff_workdir__head_index_and_workdir_all_differ(void)
diff_expects exp;
char *pathspec = "staged_changes_modified_file";
git_tree *tree;
+ int use_iterator;
/* For this file,
* - head->index diff has 1 line of context, 1 line of diff
@@ -366,46 +444,70 @@ void test_diff_workdir__head_index_and_workdir_all_differ(void)
cl_git_pass(git_diff_index_to_tree(g_repo, &opts, tree, &diff_i2t));
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff_w2i));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(1, exp.hunks);
- cl_assert_equal_i(2, exp.lines);
- cl_assert_equal_i(1, exp.line_ctxt);
- cl_assert_equal_i(1, exp.line_adds);
- cl_assert_equal_i(0, exp.line_dels);
-
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff_w2i, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(1, exp.hunks);
- cl_assert_equal_i(3, exp.lines);
- cl_assert_equal_i(2, exp.line_ctxt);
- cl_assert_equal_i(1, exp.line_adds);
- cl_assert_equal_i(0, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(1, exp.hunks);
+ cl_assert_equal_i(2, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(1, exp.line_adds);
+ cl_assert_equal_i(0, exp.line_dels);
+ }
+
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff_w2i, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff_w2i, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(1, exp.hunks);
+ cl_assert_equal_i(3, exp.lines);
+ cl_assert_equal_i(2, exp.line_ctxt);
+ cl_assert_equal_i(1, exp.line_adds);
+ cl_assert_equal_i(0, exp.line_dels);
+ }
cl_git_pass(git_diff_merge(diff_i2t, diff_w2i));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(1, exp.hunks);
- cl_assert_equal_i(3, exp.lines);
- cl_assert_equal_i(1, exp.line_ctxt);
- cl_assert_equal_i(2, exp.line_adds);
- cl_assert_equal_i(0, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff_i2t, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(1, exp.hunks);
+ cl_assert_equal_i(3, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(2, exp.line_adds);
+ cl_assert_equal_i(0, exp.line_dels);
+ }
git_diff_list_free(diff_i2t);
git_diff_list_free(diff_w2i);
@@ -419,6 +521,7 @@ void test_diff_workdir__eof_newline_changes(void)
git_diff_list *diff = NULL;
diff_expects exp;
char *pathspec = "current_file";
+ int use_iterator;
g_repo = cl_git_sandbox_init("status");
@@ -427,18 +530,26 @@ void test_diff_workdir__eof_newline_changes(void)
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(0, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(0, exp.file_mods);
- cl_assert_equal_i(0, exp.hunks);
- cl_assert_equal_i(0, exp.lines);
- cl_assert_equal_i(0, exp.line_ctxt);
- cl_assert_equal_i(0, exp.line_adds);
- cl_assert_equal_i(0, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(0, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(0, exp.file_mods);
+ cl_assert_equal_i(0, exp.hunks);
+ cl_assert_equal_i(0, exp.lines);
+ cl_assert_equal_i(0, exp.line_ctxt);
+ cl_assert_equal_i(0, exp.line_adds);
+ cl_assert_equal_i(0, exp.line_dels);
+ }
git_diff_list_free(diff);
@@ -446,18 +557,26 @@ void test_diff_workdir__eof_newline_changes(void)
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(1, exp.hunks);
- cl_assert_equal_i(2, exp.lines);
- cl_assert_equal_i(1, exp.line_ctxt);
- cl_assert_equal_i(1, exp.line_adds);
- cl_assert_equal_i(0, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(1, exp.hunks);
+ cl_assert_equal_i(2, exp.lines);
+ cl_assert_equal_i(1, exp.line_ctxt);
+ cl_assert_equal_i(1, exp.line_adds);
+ cl_assert_equal_i(0, exp.line_dels);
+ }
git_diff_list_free(diff);
@@ -465,18 +584,26 @@ void test_diff_workdir__eof_newline_changes(void)
cl_git_pass(git_diff_workdir_to_index(g_repo, &opts, &diff));
- memset(&exp, 0, sizeof(exp));
- cl_git_pass(git_diff_foreach(
- diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
- cl_assert_equal_i(1, exp.files);
- cl_assert_equal_i(0, exp.file_adds);
- cl_assert_equal_i(0, exp.file_dels);
- cl_assert_equal_i(1, exp.file_mods);
- cl_assert_equal_i(1, exp.hunks);
- cl_assert_equal_i(3, exp.lines);
- cl_assert_equal_i(0, exp.line_ctxt);
- cl_assert_equal_i(1, exp.line_adds);
- cl_assert_equal_i(2, exp.line_dels);
+ for (use_iterator = 0; use_iterator <= 1; use_iterator++) {
+ memset(&exp, 0, sizeof(exp));
+
+ if (use_iterator)
+ cl_git_pass(diff_foreach_via_iterator(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+ else
+ cl_git_pass(git_diff_foreach(
+ diff, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
+
+ cl_assert_equal_i(1, exp.files);
+ cl_assert_equal_i(0, exp.file_adds);
+ cl_assert_equal_i(0, exp.file_dels);
+ cl_assert_equal_i(1, exp.file_mods);
+ cl_assert_equal_i(1, exp.hunks);
+ cl_assert_equal_i(3, exp.lines);
+ cl_assert_equal_i(0, exp.line_ctxt);
+ cl_assert_equal_i(1, exp.line_adds);
+ cl_assert_equal_i(2, exp.line_dels);
+ }
git_diff_list_free(diff);
}
diff --git a/tests-clar/object/peel.c b/tests-clar/object/peel.c
index f6d2a776..f4ea1eb0 100644
--- a/tests-clar/object/peel.c
+++ b/tests-clar/object/peel.c
@@ -65,7 +65,7 @@ void test_object_peel__can_peel_a_commit(void)
void test_object_peel__cannot_peel_a_tree(void)
{
- assert_peel_error(GIT_EAMBIGUOUS, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
+ assert_peel_error(GIT_ERROR, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_BLOB);
}
void test_object_peel__cannot_peel_a_blob(void)
@@ -73,7 +73,17 @@ void test_object_peel__cannot_peel_a_blob(void)
assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_COMMIT);
}
-void test_object_peel__cannot_target_any_object(void)
+void test_object_peel__target_any_object_for_type_change(void)
{
- assert_peel_error(GIT_EAMBIGUOUS, "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
+ /* tag to commit */
+ assert_peel("e90810b8df3e80c413d903f631643c716887138d", "7b4384978d2493e851f9cca7858815fac9b10980", GIT_OBJ_ANY);
+
+ /* commit to tree */
+ assert_peel("53fc32d17276939fc79ed05badaef2db09990016", "e90810b8df3e80c413d903f631643c716887138d", GIT_OBJ_ANY);
+
+ /* fail to peel tree */
+ assert_peel_error(GIT_ERROR, "53fc32d17276939fc79ed05badaef2db09990016", GIT_OBJ_ANY);
+
+ /* fail to peel blob */
+ assert_peel_error(GIT_ERROR, "0266163a49e280c4f5ed1e08facd36a2bd716bcf", GIT_OBJ_ANY);
}
diff --git a/tests-clar/refs/branches/delete.c b/tests-clar/refs/branches/delete.c
index 699655f2..b261240c 100644
--- a/tests-clar/refs/branches/delete.c
+++ b/tests-clar/refs/branches/delete.c
@@ -23,37 +23,37 @@ void test_refs_branches_delete__cleanup(void)
cl_fixture_cleanup("testrepo.git");
}
-void test_refs_branches_delete__can_not_delete_a_non_existing_branch(void)
-{
- cl_git_fail(git_branch_delete(repo, "i-am-not-a-local-branch", GIT_BRANCH_LOCAL));
- cl_git_fail(git_branch_delete(repo, "neither/a-remote-one", GIT_BRANCH_REMOTE));
-}
-
void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void)
{
git_reference *head;
+ git_reference *branch;
/* Ensure HEAD targets the local master branch */
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
cl_assert(strcmp("refs/heads/master", git_reference_target(head)) == 0);
git_reference_free(head);
- cl_git_fail(git_branch_delete(repo, "master", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
+ cl_git_fail(git_branch_delete(branch));
+ git_reference_free(branch);
}
void test_refs_branches_delete__can_not_delete_a_branch_if_HEAD_is_missing(void)
{
git_reference *head;
+ git_reference *branch = NULL;
cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE));
git_reference_delete(head);
- cl_git_fail(git_branch_delete(repo, "br2", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
+ cl_git_fail(git_branch_delete(branch));
+ git_reference_free(branch);
}
void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(void)
{
- git_reference *master, *head;
+ git_reference *master, *head, *branch;
/* Detach HEAD and make it target the commit that "master" points to */
cl_git_pass(git_reference_lookup(&master, repo, "refs/heads/master"));
@@ -61,30 +61,21 @@ void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD(
git_reference_free(head);
git_reference_free(master);
- cl_git_pass(git_branch_delete(repo, "master", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_lookup(&branch, repo, "master", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_delete(branch));
}
void test_refs_branches_delete__can_delete_a_local_branch(void)
{
- cl_git_pass(git_branch_delete(repo, "br2", GIT_BRANCH_LOCAL));
+ git_reference *branch;
+ cl_git_pass(git_branch_lookup(&branch, repo, "br2", GIT_BRANCH_LOCAL));
+ cl_git_pass(git_branch_delete(branch));
}
void test_refs_branches_delete__can_delete_a_remote_branch(void)
{
- cl_git_pass(git_branch_delete(repo, "nulltoken/master", GIT_BRANCH_REMOTE));
+ git_reference *branch;
+ cl_git_pass(git_branch_lookup(&branch, repo, "nulltoken/master", GIT_BRANCH_REMOTE));
+ cl_git_pass(git_branch_delete(branch));
}
-static void assert_non_exisitng_branch_removal(const char *branch_name, git_branch_t branch_type)
-{
- int error;
- error = git_branch_delete(repo, branch_name, branch_type);
-
- cl_git_fail(error);
- cl_assert_equal_i(GIT_ENOTFOUND, error);
-}
-
-void test_refs_branches_delete__deleting_a_non_existing_branch_returns_ENOTFOUND(void)
-{
- assert_non_exisitng_branch_removal("i-do-not-locally-exist", GIT_BRANCH_LOCAL);
- assert_non_exisitng_branch_removal("neither/remotely", GIT_BRANCH_REMOTE);
-}
diff --git a/tests-clar/refs/normalize.c b/tests-clar/refs/normalize.c
index 135d0a9b..4e80e4b0 100644
--- a/tests-clar/refs/normalize.c
+++ b/tests-clar/refs/normalize.c
@@ -4,70 +4,111 @@
#include "git2/reflog.h"
#include "reflog.h"
-
// Helpers
-static void ensure_refname_normalized(int is_oid_ref,
+static void ensure_refname_normalized(unsigned int flags,
const char *input_refname,
const char *expected_refname)
{
char buffer_out[GIT_REFNAME_MAX];
- if (is_oid_ref)
- cl_git_pass(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
- else
- cl_git_pass(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+ cl_git_pass(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
- if (expected_refname)
- cl_assert(0 == strcmp(buffer_out, expected_refname));
+ cl_assert_equal_i(0, strcmp(buffer_out, expected_refname));
}
-static void ensure_refname_invalid(int is_oid_ref, const char *input_refname)
+static void ensure_refname_invalid(unsigned int flags, const char *input_refname)
{
char buffer_out[GIT_REFNAME_MAX];
- if (is_oid_ref)
- cl_git_fail(git_reference__normalize_name_oid(buffer_out, sizeof(buffer_out), input_refname));
- else
- cl_git_fail(git_reference__normalize_name(buffer_out, sizeof(buffer_out), input_refname));
+ cl_git_fail(git_reference_normalize_name(buffer_out, sizeof(buffer_out), input_refname, flags));
}
-#define OID_REF 1
-#define SYM_REF 0
-
+void test_refs_normalize__can_normalize_a_direct_reference_name(void)
+{
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/dummy/a", "refs/dummy/a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/stash", "refs/stash");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/tags/a", "refs/tags/a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a/b", "refs/heads/a/b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a./b", "refs/heads/a./b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "/refs///heads///a", "refs/heads/a");
+}
+void test_refs_normalize__can_normalize_some_specific_one_level_direct_reference_names(void)
+{
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "HEAD", "HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "MERGE_HEAD", "MERGE_HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "FETCH_HEAD", "FETCH_HEAD");
+}
-void test_refs_normalize__direct(void)
+void test_refs_normalize__cannot_normalize_any_direct_reference_name(void)
{
- // normalize a direct (OID) reference name
- ensure_refname_invalid(OID_REF, "a");
- ensure_refname_invalid(OID_REF, "");
- ensure_refname_invalid(OID_REF, "refs/heads/a/");
- ensure_refname_invalid(OID_REF, "refs/heads/a.");
- ensure_refname_invalid(OID_REF, "refs/heads/a.lock");
- ensure_refname_normalized(OID_REF, "refs/dummy/a", NULL);
- ensure_refname_normalized(OID_REF, "refs/stash", NULL);
- ensure_refname_normalized(OID_REF, "refs/tags/a", "refs/tags/a");
- ensure_refname_normalized(OID_REF, "refs/heads/a/b", "refs/heads/a/b");
- ensure_refname_normalized(OID_REF, "refs/heads/a./b", "refs/heads/a./b");
- ensure_refname_invalid(OID_REF, "refs/heads/foo?bar");
- ensure_refname_invalid(OID_REF, "refs/heads\foo");
- ensure_refname_normalized(OID_REF, "refs/heads/v@ation", "refs/heads/v@ation");
- ensure_refname_normalized(OID_REF, "refs///heads///a", "refs/heads/a");
- ensure_refname_invalid(OID_REF, "refs/heads/.a/b");
- ensure_refname_invalid(OID_REF, "refs/heads/foo/../bar");
- ensure_refname_invalid(OID_REF, "refs/heads/foo..bar");
- ensure_refname_invalid(OID_REF, "refs/heads/./foo");
- ensure_refname_invalid(OID_REF, "refs/heads/v@{ation");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "/a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "//a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/a.lock");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo?bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads\foo");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@ation", "refs/heads/v@ation");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_NORMAL, "refs///heads///a", "refs/heads/a");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/.a/b");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo/../bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/foo..bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/./foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "refs/heads/v@{ation");
}
void test_refs_normalize__symbolic(void)
{
- // normalize a symbolic reference name
- ensure_refname_normalized(SYM_REF, "a", "a");
- ensure_refname_normalized(SYM_REF, "a/b", "a/b");
- ensure_refname_normalized(SYM_REF, "refs///heads///a", "refs/heads/a");
- ensure_refname_invalid(SYM_REF, "");
- ensure_refname_invalid(SYM_REF, "heads\foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads\foo");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "///");
+
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "a", "a");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "a/b", "a/b");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs///heads///a", "refs/heads/a");
+
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "HEAD", "HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "MERGE_HEAD", "MERGE_HEAD");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "FETCH_HEAD", "FETCH_HEAD");
}
/* Ported from JGit, BSD licence.
@@ -77,31 +118,42 @@ void test_refs_normalize__jgit_suite(void)
// tests borrowed from JGit
/* EmptyString */
- ensure_refname_invalid(SYM_REF, "");
- ensure_refname_invalid(SYM_REF, "/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "/");
/* MustHaveTwoComponents */
- ensure_refname_invalid(OID_REF, "master");
- ensure_refname_normalized(SYM_REF, "heads/master", "heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_NORMAL, "master");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "heads/master", "heads/master");
/* ValidHead */
- ensure_refname_normalized(SYM_REF, "refs/heads/master", "refs/heads/master");
- ensure_refname_normalized(SYM_REF, "refs/heads/pu", "refs/heads/pu");
- ensure_refname_normalized(SYM_REF, "refs/heads/z", "refs/heads/z");
- ensure_refname_normalized(SYM_REF, "refs/heads/FoO", "refs/heads/FoO");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master", "refs/heads/master");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/pu", "refs/heads/pu");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/z", "refs/heads/z");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/FoO", "refs/heads/FoO");
/* ValidTag */
- ensure_refname_normalized(SYM_REF, "refs/tags/v1.0", "refs/tags/v1.0");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/tags/v1.0", "refs/tags/v1.0");
/* NoLockSuffix */
- ensure_refname_invalid(SYM_REF, "refs/heads/master.lock");
+ ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master.lock");
/* NoDirectorySuffix */
- ensure_refname_invalid(SYM_REF, "refs/heads/master/");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master/");
/* NoSpace */
- ensure_refname_invalid(SYM_REF, "refs/heads/i haz space");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/i haz space");
/* NoAsciiControlCharacters */
{
@@ -112,89 +164,153 @@ void test_refs_normalize__jgit_suite(void)
strncpy(buffer + 15, (const char *)&c, 1);
strncpy(buffer + 16, "er", 2);
buffer[18 - 1] = '\0';
- ensure_refname_invalid(SYM_REF, buffer);
+ ensure_refname_invalid(GIT_REF_FORMAT_ALLOW_ONELEVEL, buffer);
}
}
/* NoBareDot */
- ensure_refname_invalid(SYM_REF, "refs/heads/.");
- ensure_refname_invalid(SYM_REF, "refs/heads/..");
- ensure_refname_invalid(SYM_REF, "refs/heads/./master");
- ensure_refname_invalid(SYM_REF, "refs/heads/../master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/./master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/../master");
/* NoLeadingOrTrailingDot */
- ensure_refname_invalid(SYM_REF, ".");
- ensure_refname_invalid(SYM_REF, "refs/heads/.bar");
- ensure_refname_invalid(SYM_REF, "refs/heads/..bar");
- ensure_refname_invalid(SYM_REF, "refs/heads/bar.");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, ".");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/.bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/..bar");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/bar.");
/* ContainsDot */
- ensure_refname_normalized(SYM_REF, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
- ensure_refname_invalid(SYM_REF, "refs/heads/master..pu");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master..pu");
/* NoMagicRefCharacters */
- ensure_refname_invalid(SYM_REF, "refs/heads/master^");
- ensure_refname_invalid(SYM_REF, "refs/heads/^master");
- ensure_refname_invalid(SYM_REF, "^refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master~");
- ensure_refname_invalid(SYM_REF, "refs/heads/~master");
- ensure_refname_invalid(SYM_REF, "~refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master:");
- ensure_refname_invalid(SYM_REF, "refs/heads/:master");
- ensure_refname_invalid(SYM_REF, ":refs/heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master^");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/^master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "^refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master~");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/~master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "~refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master:");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/:master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, ":refs/heads/master");
/* ShellGlob */
- ensure_refname_invalid(SYM_REF, "refs/heads/master?");
- ensure_refname_invalid(SYM_REF, "refs/heads/?master");
- ensure_refname_invalid(SYM_REF, "?refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master[");
- ensure_refname_invalid(SYM_REF, "refs/heads/[master");
- ensure_refname_invalid(SYM_REF, "[refs/heads/master");
-
- ensure_refname_invalid(SYM_REF, "refs/heads/master*");
- ensure_refname_invalid(SYM_REF, "refs/heads/*master");
- ensure_refname_invalid(SYM_REF, "*refs/heads/master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master?");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/?master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "?refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master[");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/[master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "[refs/heads/master");
+
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master*");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/*master");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "*refs/heads/master");
/* ValidSpecialCharacters */
- ensure_refname_normalized(SYM_REF, "refs/heads/!", "refs/heads/!");
- ensure_refname_normalized(SYM_REF, "refs/heads/\"", "refs/heads/\"");
- ensure_refname_normalized(SYM_REF, "refs/heads/#", "refs/heads/#");
- ensure_refname_normalized(SYM_REF, "refs/heads/$", "refs/heads/$");
- ensure_refname_normalized(SYM_REF, "refs/heads/%", "refs/heads/%");
- ensure_refname_normalized(SYM_REF, "refs/heads/&", "refs/heads/&");
- ensure_refname_normalized(SYM_REF, "refs/heads/'", "refs/heads/'");
- ensure_refname_normalized(SYM_REF, "refs/heads/(", "refs/heads/(");
- ensure_refname_normalized(SYM_REF, "refs/heads/)", "refs/heads/)");
- ensure_refname_normalized(SYM_REF, "refs/heads/+", "refs/heads/+");
- ensure_refname_normalized(SYM_REF, "refs/heads/,", "refs/heads/,");
- ensure_refname_normalized(SYM_REF, "refs/heads/-", "refs/heads/-");
- ensure_refname_normalized(SYM_REF, "refs/heads/;", "refs/heads/;");
- ensure_refname_normalized(SYM_REF, "refs/heads/<", "refs/heads/<");
- ensure_refname_normalized(SYM_REF, "refs/heads/=", "refs/heads/=");
- ensure_refname_normalized(SYM_REF, "refs/heads/>", "refs/heads/>");
- ensure_refname_normalized(SYM_REF, "refs/heads/@", "refs/heads/@");
- ensure_refname_normalized(SYM_REF, "refs/heads/]", "refs/heads/]");
- ensure_refname_normalized(SYM_REF, "refs/heads/_", "refs/heads/_");
- ensure_refname_normalized(SYM_REF, "refs/heads/`", "refs/heads/`");
- ensure_refname_normalized(SYM_REF, "refs/heads/{", "refs/heads/{");
- ensure_refname_normalized(SYM_REF, "refs/heads/|", "refs/heads/|");
- ensure_refname_normalized(SYM_REF, "refs/heads/}", "refs/heads/}");
+ ensure_refname_normalized
+ (GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/!", "refs/heads/!");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\"", "refs/heads/\"");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/#", "refs/heads/#");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/$", "refs/heads/$");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/%", "refs/heads/%");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/&", "refs/heads/&");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/'", "refs/heads/'");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/(", "refs/heads/(");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/)", "refs/heads/)");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/+", "refs/heads/+");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/,", "refs/heads/,");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/-", "refs/heads/-");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/;", "refs/heads/;");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/<", "refs/heads/<");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/=", "refs/heads/=");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/>", "refs/heads/>");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/@", "refs/heads/@");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/]", "refs/heads/]");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/_", "refs/heads/_");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/`", "refs/heads/`");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/{", "refs/heads/{");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/|", "refs/heads/|");
+ ensure_refname_normalized(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/}", "refs/heads/}");
// This is valid on UNIX, but not on Windows
// hence we make in invalid due to non-portability
//
- ensure_refname_invalid(SYM_REF, "refs/heads/\\");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\\");
/* UnicodeNames */
/*
* Currently this fails.
- * ensure_refname_normalized(SYM_REF, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
+ * ensure_refname_normalized(GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m");
*/
/* RefLogQueryIsValidRef */
- ensure_refname_invalid(SYM_REF, "refs/heads/master@{1}");
- ensure_refname_invalid(SYM_REF, "refs/heads/master@{1.hour.ago}");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1}");
+ ensure_refname_invalid(
+ GIT_REF_FORMAT_ALLOW_ONELEVEL, "refs/heads/master@{1.hour.ago}");
+}
+
+void test_refs_normalize__buffer_has_to_be_big_enough_to_hold_the_normalized_version(void)
+{
+ char buffer_out[21];
+
+ cl_git_pass(git_reference_normalize_name(
+ buffer_out, 21, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
+ cl_git_fail(git_reference_normalize_name(
+ buffer_out, 20, "//refs//heads/long///name", GIT_REF_FORMAT_NORMAL));
}
diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c
index 67a9917d..f76e8bc3 100644
--- a/tests-clar/repo/init.c
+++ b/tests-clar/repo/init.c
@@ -378,3 +378,18 @@ void test_repo_init__extended_with_template(void)
cleanup_repository("templated.git");
}
+
+void test_repo_init__can_reinit_an_initialized_repository(void)
+{
+ git_repository *reinit;
+
+ cl_git_pass(git_futils_mkdir("extended", NULL, 0775, 0));
+ cl_git_pass(git_repository_init(&_repo, "extended", false));
+
+ cl_git_pass(git_repository_init(&reinit, "extended", false));
+
+ cl_assert_equal_s(git_repository_path(_repo), git_repository_path(reinit));
+
+ git_repository_free(reinit);
+ cleanup_repository("extended");
+}
diff --git a/tests-clar/resources/attr/.gitted/index b/tests-clar/resources/attr/.gitted/index
index 943e2243..439ffb15 100644
--- a/tests-clar/resources/attr/.gitted/index
+++ b/tests-clar/resources/attr/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/issue_592/.gitted/index b/tests-clar/resources/issue_592/.gitted/index
index eaeb5d76..be7a29d9 100644
--- a/tests-clar/resources/issue_592/.gitted/index
+++ b/tests-clar/resources/issue_592/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/status/.gitted/index b/tests-clar/resources/status/.gitted/index
index 9a383ec0..2af99a18 100644
--- a/tests-clar/resources/status/.gitted/index
+++ b/tests-clar/resources/status/.gitted/index
Binary files differ
diff --git a/tests-clar/resources/submod2/gitmodules b/tests-clar/resources/submod2/gitmodules
index 7b150b18..4c31108e 100644
--- a/tests-clar/resources/submod2/gitmodules
+++ b/tests-clar/resources/submod2/gitmodules
@@ -19,3 +19,6 @@
[submodule "sm_added_and_uncommited"]
path = sm_added_and_uncommited
url = ../submod2_target
+[submodule "sm_gitmodules_only"]
+ path = sm_gitmodules_only
+ url = ../submod2_target
diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c
index 6f3c1c06..126ca7d9 100644
--- a/tests-clar/revwalk/basic.c
+++ b/tests-clar/revwalk/basic.c
@@ -179,3 +179,11 @@ void test_revwalk_basic__push_head_hide_ref_nobase(void)
/* git log HEAD --oneline --not refs/heads/packed | wc -l => 7 */
cl_assert(i == 7);
}
+
+void test_revwalk_basic__disallow_non_commit(void)
+{
+ git_oid oid;
+
+ cl_git_pass(git_oid_fromstr(&oid, "521d87c1ec3aef9824daf6d96cc0ae3710766d91"));
+ cl_git_fail(git_revwalk_push(_walk, &oid));
+}
diff --git a/tests-clar/submodule/lookup.c b/tests-clar/submodule/lookup.c
index 669338f1..94eb19b5 100644
--- a/tests-clar/submodule/lookup.c
+++ b/tests-clar/submodule/lookup.c
@@ -34,6 +34,10 @@ void test_submodule_lookup__simple_lookup(void)
cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_added_and_uncommited"));
cl_assert(sm);
+ /* lookup pending change in .gitmodules that is neither in HEAD nor index */
+ cl_git_pass(git_submodule_lookup(&sm, g_repo, "sm_gitmodules_only"));
+ cl_assert(sm);
+
/* lookup git repo subdir that is not added as submodule */
cl_assert(git_submodule_lookup(&sm, g_repo, "not_submodule") == GIT_EEXISTS);
@@ -106,5 +110,5 @@ void test_submodule_lookup__foreach(void)
sm_lookup_data data;
memset(&data, 0, sizeof(data));
cl_git_pass(git_submodule_foreach(g_repo, sm_lookup_cb, &data));
- cl_assert_equal_i(7, data.count);
+ cl_assert_equal_i(8, data.count);
}