diff options
| -rw-r--r-- | .travis.yml | 3 | ||||
| -rw-r--r-- | CHANGELOG.md | 23 | ||||
| -rw-r--r-- | include/git2/clone.h | 146 | ||||
| -rw-r--r-- | include/git2/remote.h | 15 | ||||
| -rw-r--r-- | include/git2/revert.h | 2 | ||||
| -rw-r--r-- | src/checkout.c | 139 | ||||
| -rw-r--r-- | src/cherrypick.c | 11 | ||||
| -rw-r--r-- | src/clone.c | 56 | ||||
| -rw-r--r-- | src/crlf.c | 3 | ||||
| -rw-r--r-- | src/indexer.c | 5 | ||||
| -rw-r--r-- | src/merge.c | 173 | ||||
| -rw-r--r-- | src/merge.h | 2 | ||||
| -rw-r--r-- | src/mwindow.c | 27 | ||||
| -rw-r--r-- | src/mwindow.h | 2 | ||||
| -rw-r--r-- | src/pack.c | 6 | ||||
| -rw-r--r-- | src/pool.c | 2 | ||||
| -rw-r--r-- | src/refs.h | 2 | ||||
| -rw-r--r-- | src/remote.c | 26 | ||||
| -rw-r--r-- | src/remote.h | 2 | ||||
| -rw-r--r-- | src/revert.c | 10 | ||||
| -rw-r--r-- | src/transport.c | 5 | ||||
| -rw-r--r-- | src/transports/smart_protocol.c | 4 | ||||
| -rw-r--r-- | src/transports/ssh.c | 13 | ||||
| -rw-r--r-- | src/tree.c | 2 | ||||
| -rw-r--r-- | tests/checkout/conflict.c | 2 | ||||
| -rw-r--r-- | tests/checkout/crlf.c | 9 | ||||
| -rw-r--r-- | tests/clone/local.c | 28 | ||||
| -rw-r--r-- | tests/clone/nonetwork.c | 36 | ||||
| -rw-r--r-- | tests/clone/transport.c | 50 | ||||
| -rw-r--r-- | tests/core/pool.c | 10 | ||||
| -rw-r--r-- | tests/merge/workdir/dirty.c | 2 | ||||
| -rw-r--r-- | tests/network/fetchlocal.c | 35 | ||||
| -rw-r--r-- | tests/network/remote/remotes.c | 30 | ||||
| -rw-r--r-- | tests/online/clone.c | 62 |
34 files changed, 520 insertions, 423 deletions
diff --git a/.travis.yml b/.travis.yml index bab02bb44..362b88224 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,10 +46,11 @@ after_success: - if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install valgrind; fi - if [ "$TRAVIS_OS_NAME" = "linux" ]; then valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline; fi -# Only watch the development branch +# Only watch the development and master branches branches: only: - development + - master # Notify development list when needed notifications: diff --git a/CHANGELOG.md b/CHANGELOG.md index 61fc1cfdb..f4714993a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,3 +9,26 @@ v0.21 + 1 * Use a map for the treebuilder, making insertion O(1) * LF -> CRLF filter refuses to handle mixed-EOL files + +* LF -> CRLF filter now runs when * text = auto (with Git for Windows 1.9.4) + +* The git_remote_set_transport function now sets a transport factory function, + rather than a pre-existing transport instance. + +* The git_clone_options struct no longer provides the ignore_cert_errors or + remote_name members for remote customization. + + Instead, the git_clone_options struct has two new members, remote_cb and + remote_cb_payload, which allow the caller to completely override the remote + creation process. If needed, the caller can use this callback to give their + remote a name other than the default (origin) or disable cert checking. + + The remote_callbacks member has been preserved for convenience, although it + is not used when a remote creation callback is supplied. + +* The git_clone_options struct now provides repository_cb and + repository_cb_payload to allow the user to create a repository with + custom options. + +* git_clone_into and git_clone_local_into have been removed from the + public API in favour of git_clone callbacks diff --git a/include/git2/clone.h b/include/git2/clone.h index 05b7522ce..fa2e25b60 100644 --- a/include/git2/clone.h +++ b/include/git2/clone.h @@ -12,6 +12,7 @@ #include "indexer.h" #include "checkout.h" #include "remote.h" +#include "transport.h" /** @@ -52,6 +53,47 @@ typedef enum { } git_clone_local_t; /** + * The signature of a function matching git_remote_create, with an additional + * void* as a callback payload. + * + * Callers of git_clone may provide a function matching this signature to override + * the remote creation and customization process during a clone operation. + * + * @param out the resulting remote + * @param repo the repository in which to create the remote + * @param name the remote's name + * @param url the remote's url + * @param payload an opaque payload + * @return 0, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code + */ +typedef int (*git_remote_create_cb)( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload); + +/** + * The signature of a function matchin git_repository_init, with an + * aditional void * as callback payload. + * + * Callers of git_clone my provide a function matching this signature + * to override the repository creation and customization process + * during a clone operation. + * + * @param out the resulting repository + * @param path path in which to create the repository + * @param bare whether the repository is bare. This is the value from the clone options + * @param payload payload specified by the options + * @return 0, or a negative value to indicate error + */ +typedef int (*git_repository_create_cb)( + git_repository **out, + const char *path, + int bare, + void *payload); + +/** * Clone options structure * * Use the GIT_CLONE_OPTIONS_INIT to get the default settings, like this: @@ -72,7 +114,11 @@ typedef struct git_clone_options { git_checkout_options checkout_opts; /** - * Callbacks to use for reporting fetch progress. + * Callbacks to use for reporting fetch progress, and for acquiring + * credentials in the event they are needed. This parameter is ignored if + * the remote_cb parameter is set; if you provide a remote creation + * callback, then you have the opportunity to configure remote callbacks in + * provided function. */ git_remote_callbacks remote_callbacks; @@ -83,23 +129,11 @@ typedef struct git_clone_options { int bare; /** - * Set to 1 if errors validating the remote host's certificate - * should be ignored. - */ - int ignore_cert_errors; - - /** * Whether to use a fetch or copy the object database. */ git_clone_local_t local; /** - * The name to be given to the remote that will be - * created. The default is "origin". - */ - const char *remote_name; - - /** * The name of the branch to checkout. NULL means use the * remote's default branch. */ @@ -110,6 +144,33 @@ typedef struct git_clone_options { * use the default signature using the config. */ git_signature *signature; + + /** + * A callback used to create the new repository into which to + * clone. If NULL, the 'bare' field will be used to determine + * whether to create a bare repository. + */ + git_repository_create_cb repository_cb; + + /** + * An opaque payload to pass to the git_repository creation callback. + * This parameter is ignored unless repository_cb is non-NULL. + */ + void *repository_cb_payload; + + /** + * A callback used to create the git_remote, prior to its being + * used to perform the clone operation. See the documentation for + * git_remote_create_cb for details. This parameter may be NULL, + * indicating that git_clone should provide default behavior. + */ + git_remote_create_cb remote_cb; + + /** + * An opaque payload to pass to the git_remote creation callback. + * This parameter is ignored unless remote_cb is non-NULL. + */ + void *remote_cb_payload; } git_clone_options; #define GIT_CLONE_OPTIONS_VERSION 1 @@ -130,9 +191,9 @@ GIT_EXTERN(int) git_clone_init_options( /** * Clone a remote repository. * - * This version handles the simple case. If you'd like to create the - * repository or remote with non-default settings, you can create and - * configure them and then use `git_clone_into()`. + * By default this creates its repository and initial remote to match + * git's defaults. You can use the options in the callback to + * customize how these are created. * * @param out pointer that will receive the resulting repository object * @param url the remote repository to clone @@ -149,59 +210,6 @@ GIT_EXTERN(int) git_clone( const char *local_path, const git_clone_options *options); -/** - * Clone into a repository - * - * After creating the repository and remote and configuring them for - * paths and callbacks respectively, you can call this function to - * perform the clone operation and optionally checkout files. - * - * @param repo the repository to use - * @param remote the remote repository to clone from - * @param co_opts options to use during checkout - * @param branch the branch to checkout after the clone, pass NULL for the - * remote's default branch - * @param signature The identity used when updating the reflog. - * @return 0 on success, any non-zero return value from a callback - * function, or a negative value to indicate an error (use - * `giterr_last` for a detailed error message) - */ -GIT_EXTERN(int) git_clone_into( - git_repository *repo, - git_remote *remote, - const git_checkout_options *co_opts, - const char *branch, - const git_signature *signature); - -/** - * Perform a local clone into a repository - * - * A "local clone" bypasses any git-aware protocols and simply copies - * over the object database from the source repository. It is often - * faster than a git-aware clone, but no verification of the data is - * performed, and can copy over too much data. - * - * @param repo the repository to use - * @param remote the remote repository to clone from - * @param co_opts options to use during checkout - * @param branch the branch to checkout after the clone, pass NULL for the - * remote's default branch - * @param link wether to use hardlinks instead of copying - * objects. This is only possible if both repositories are on the same - * filesystem. - * @param signature the identity used when updating the reflog - * @return 0 on success, any non-zero return value from a callback - * function, or a negative value to indicate an error (use - * `giterr_last` for a detailed error message) - */ -GIT_EXTERN(int) git_clone_local_into( - git_repository *repo, - git_remote *remote, - const git_checkout_options *co_opts, - const char *branch, - int link, - const git_signature *signature); - /** @} */ GIT_END_DECL #endif diff --git a/include/git2/remote.h b/include/git2/remote.h index c72c9c8cc..c8b6ac97a 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -419,20 +419,19 @@ GIT_EXTERN(int) git_remote_list(git_strarray *out, git_repository *repo); GIT_EXTERN(void) git_remote_check_cert(git_remote *remote, int check); /** - * Sets a custom transport for the remote. The caller can use this function - * to bypass the automatic discovery of a transport by URL scheme (i.e. - * http://, https://, git://) and supply their own transport to be used - * instead. After providing the transport to a remote using this function, - * the transport object belongs exclusively to that remote, and the remote will - * free it when it is freed with git_remote_free. + * Sets a custom transport factory for the remote. The caller can use this + * function to override the transport used for this remote when performing + * network operations. * * @param remote the remote to configure - * @param transport the transport object for the remote to use + * @param transport_cb the function to use to create a transport + * @param payload opaque parameter passed to transport_cb * @return 0 or an error code */ GIT_EXTERN(int) git_remote_set_transport( git_remote *remote, - git_transport *transport); + git_transport_cb transport_cb, + void *payload); /** * Argument to the completion callback which tells it which operation diff --git a/include/git2/revert.h b/include/git2/revert.h index fc1767c93..ab9dd9af9 100644 --- a/include/git2/revert.h +++ b/include/git2/revert.h @@ -59,7 +59,7 @@ GIT_EXTERN(int) git_revert_init_options( * @param merge_options the merge options (or null for defaults) * @return zero on success, -1 on failure. */ -int git_revert_commit( +GIT_EXTERN(int) git_revert_commit( git_index **out, git_repository *repo, git_commit *revert_commit, diff --git a/src/checkout.c b/src/checkout.c index 20763fd35..adb3c81e0 100644 --- a/src/checkout.c +++ b/src/checkout.c @@ -46,6 +46,7 @@ enum { typedef struct { git_repository *repo; + git_iterator *target; git_diff *diff; git_checkout_options opts; bool opts_free_baseline; @@ -54,6 +55,8 @@ typedef struct { git_pool pool; git_vector removes; git_vector conflicts; + git_vector *reuc; + git_vector *names; git_buf path; size_t workdir_len; git_buf tmp; @@ -138,6 +141,7 @@ static int checkout_notify( static bool checkout_is_workdir_modified( checkout_data *data, const git_diff_file *baseitem, + const git_diff_file *newitem, const git_index_entry *wditem) { git_oid oid; @@ -169,13 +173,16 @@ static bool checkout_is_workdir_modified( /* Look at the cache to decide if the workdir is modified. If not, * we can simply compare the oid in the cache to the baseitem instead - * of hashing the file. + * of hashing the file. If so, we allow the checkout to proceed if the + * oid is identical (ie, the staged item is what we're trying to check + * out.) */ if ((ie = git_index_get_bypath(data->index, wditem->path, 0)) != NULL) { if (wditem->mtime.seconds == ie->mtime.seconds && wditem->mtime.nanoseconds == ie->mtime.nanoseconds && wditem->file_size == ie->file_size) - return (git_oid__cmp(&baseitem->id, &ie->id) != 0); + return (git_oid__cmp(&baseitem->id, &ie->id) != 0 && + git_oid_cmp(&newitem->id, &ie->id) != 0); } /* depending on where base is coming from, we may or may not know @@ -401,7 +408,7 @@ static int checkout_action_with_wd( switch (delta->status) { case GIT_DELTA_UNMODIFIED: /* case 14/15 or 33 */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) { + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) { GITERR_CHECK_ERROR( checkout_notify(data, GIT_CHECKOUT_NOTIFY_DIRTY, delta, wd) ); *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, NONE); @@ -414,13 +421,13 @@ static int checkout_action_with_wd( *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); break; case GIT_DELTA_DELETED: /* case 9 or 10 (or 26 but not really) */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, REMOVE, NONE); break; case GIT_DELTA_MODIFIED: /* case 16, 17, 18 (or 36 but not really) */ - if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, UPDATE_BLOB, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); @@ -443,7 +450,7 @@ static int checkout_action_with_wd( } else *action = CHECKOUT_ACTION_IF(FORCE, REMOVE, CONFLICT); } - else if (checkout_is_workdir_modified(data, &delta->old_file, wd)) + else if (checkout_is_workdir_modified(data, &delta->old_file, &delta->new_file, wd)) *action = CHECKOUT_ACTION_IF(FORCE, REMOVE_AND_UPDATE, CONFLICT); else *action = CHECKOUT_ACTION_IF(SAFE, REMOVE_AND_UPDATE, NONE); @@ -788,11 +795,16 @@ done: static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, git_vector *pathspec) { git_index_conflict_iterator *iterator = NULL; + git_index *index; const git_index_entry *ancestor, *ours, *theirs; checkout_conflictdata *conflict; int error = 0; - if ((error = git_index_conflict_iterator_new(&iterator, data->index)) < 0) + /* Only write conficts from sources that have them: indexes. */ + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + + if ((error = git_index_conflict_iterator_new(&iterator, index)) < 0) goto done; data->conflicts._cmp = checkout_conflictdata_cmp; @@ -819,6 +831,10 @@ static int checkout_conflicts_load(checkout_data *data, git_iterator *workdir, g git_vector_insert(&data->conflicts, conflict); } + /* Collect the REUC and NAME entries */ + data->reuc = &index->reuc; + data->names = &index->names; + if (error == GIT_ITEROVER) error = 0; @@ -957,16 +973,20 @@ done: static int checkout_conflicts_coalesce_renames( checkout_data *data) { + git_index *index; const git_index_name_entry *name_entry; checkout_conflictdata *ancestor_conflict, *our_conflict, *their_conflict; size_t i, names; int error = 0; + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + /* Juggle entries based on renames */ - names = git_index_name_entrycount(data->index); + names = git_index_name_entrycount(index); for (i = 0; i < names; i++) { - name_entry = git_index_name_get_byindex(data->index, i); + name_entry = git_index_name_get_byindex(index, i); if ((error = checkout_conflicts_load_byname_entry( &ancestor_conflict, &our_conflict, &their_conflict, @@ -1010,13 +1030,17 @@ done: static int checkout_conflicts_mark_directoryfile( checkout_data *data) { + git_index *index; checkout_conflictdata *conflict; const git_index_entry *entry; size_t i, j, len; const char *path; int prefixed, error = 0; - len = git_index_entrycount(data->index); + if ((index = git_iterator_get_index(data->target)) == NULL) + return 0; + + len = git_index_entrycount(index); /* Find d/f conflicts */ git_vector_foreach(&data->conflicts, i, conflict) { @@ -1027,7 +1051,7 @@ static int checkout_conflicts_mark_directoryfile( path = conflict->ours ? conflict->ours->path : conflict->theirs->path; - if ((error = git_index_find(&j, data->index, path)) < 0) { + if ((error = git_index_find(&j, index, path)) < 0) { if (error == GIT_ENOTFOUND) giterr_set(GITERR_INDEX, "Index inconsistency, could not find entry for expected conflict '%s'", path); @@ -1036,7 +1060,7 @@ static int checkout_conflicts_mark_directoryfile( } for (; j < len; j++) { - if ((entry = git_index_get_byindex(data->index, j)) == NULL) { + if ((entry = git_index_get_byindex(index, j)) == NULL) { giterr_set(GITERR_INDEX, "Index inconsistency, truncated index while loading expected conflict '%s'", path); error = -1; @@ -1802,6 +1826,24 @@ done: return error; } +static int checkout_conflict_update_index( + checkout_data *data, + checkout_conflictdata *conflict) +{ + int error = 0; + + if (conflict->ancestor) + error = git_index_add(data->index, conflict->ancestor); + + if (!error && conflict->ours) + error = git_index_add(data->index, conflict->ours); + + if (!error && conflict->theirs) + error = git_index_add(data->index, conflict->theirs); + + return error; +} + static int checkout_create_conflicts(checkout_data *data) { checkout_conflictdata *conflict; @@ -1864,6 +1906,12 @@ static int checkout_create_conflicts(checkout_data *data) else if (!error) error = checkout_write_merge(data, conflict); + /* Update the index extensions (REUC and NAME) if we're checking + * out a different index. (Otherwise just leave them there.) + */ + if (!error && (data->strategy & GIT_CHECKOUT_DONT_UPDATE_INDEX) == 0) + error = checkout_conflict_update_index(data, conflict); + if (error) break; @@ -1876,6 +1924,37 @@ static int checkout_create_conflicts(checkout_data *data) return error; } +static int checkout_extensions_update_index(checkout_data *data) +{ + const git_index_reuc_entry *reuc_entry; + const git_index_name_entry *name_entry; + size_t i; + int error = 0; + + if ((data->strategy & GIT_CHECKOUT_UPDATE_ONLY) != 0) + return 0; + + if (data->reuc) { + git_vector_foreach(data->reuc, i, reuc_entry) { + if ((error = git_index_reuc_add(data->index, reuc_entry->path, + reuc_entry->mode[0], &reuc_entry->oid[0], + reuc_entry->mode[1], &reuc_entry->oid[1], + reuc_entry->mode[2], &reuc_entry->oid[2])) < 0) + goto done; + } + } + + if (data->names) { + git_vector_foreach(data->names, i, name_entry) { + if ((error = git_index_name_add(data->index, name_entry->ancestor, + name_entry->ours, name_entry->theirs)) < 0) + goto done; + } + } + +done: + return error; +} static void checkout_data_clear(checkout_data *data) { @@ -1919,6 +1998,7 @@ static int checkout_data_init( return error; data->repo = repo; + data->target = target; GITERR_CHECK_VERSION( proposed, GIT_CHECKOUT_OPTIONS_VERSION, "git_checkout_options"); @@ -1943,15 +2023,15 @@ static int checkout_data_init( (error = git_config_refresh(cfg)) < 0) goto cleanup; - /* if we are checking out the index, don't reload, - * otherwise get index and force reload + /* Get the repository index and reload it (unless we're checking + * out the index; then it has the changes we're trying to check + * out and those should not be overwritten.) */ - if ((data->index = git_iterator_get_index(target)) != NULL) { - GIT_REFCOUNT_INC(data->index); - } else { - /* otherwise, grab and reload the index */ - if ((error = git_repository_index(&data->index, data->repo)) < 0 || - (error = git_index_read(data->index, true)) < 0) + if ((error = git_repository_index(&data->index, data->repo)) < 0) + goto cleanup; + + if (data->index != git_iterator_get_index(target)) { + if ((error = git_index_read(data->index, true)) < 0) goto cleanup; /* cannot checkout if unresolved conflicts exist */ @@ -1963,7 +2043,7 @@ static int checkout_data_init( goto cleanup; } - /* clean conflict data when doing a tree or commit checkout */ + /* clean conflict data in the current index */ git_index_name_clear(data->index); git_index_reuc_clear(data->index); } @@ -2132,6 +2212,10 @@ int git_checkout_iterator( (error = checkout_create_conflicts(&data)) < 0) goto cleanup; + if (data.index != git_iterator_get_index(target) && + (error = checkout_extensions_update_index(&data)) < 0) + goto cleanup; + assert(data.completed_steps == data.total_steps); cleanup: @@ -2154,7 +2238,7 @@ int git_checkout_index( git_index *index, const git_checkout_options *opts) { - int error; + int error, owned = 0; git_iterator *index_i; if (!index && !repo) { @@ -2162,10 +2246,16 @@ int git_checkout_index( "Must provide either repository or index to checkout"); return -1; } - if (index && repo && git_index_owner(index) != repo) { + + if (index && repo && + git_index_owner(index) && + git_index_owner(index) != repo) { giterr_set(GITERR_CHECKOUT, "Index to checkout does not match repository"); return -1; + } else if(index && repo && !git_index_owner(index)) { + GIT_REFCOUNT_OWN(index, repo); + owned = 1; } if (!repo) @@ -2178,6 +2268,9 @@ int git_checkout_index( if (!(error = git_iterator_for_index(&index_i, index, 0, NULL, NULL))) error = git_checkout_iterator(index_i, opts); + if (owned) + GIT_REFCOUNT_OWN(index, NULL); + git_iterator_free(index_i); git_index_free(index); diff --git a/src/cherrypick.c b/src/cherrypick.c index e02348a03..cdc0eaac2 100644 --- a/src/cherrypick.c +++ b/src/cherrypick.c @@ -171,7 +171,7 @@ int git_cherry_pick( char commit_oidstr[GIT_OID_HEXSZ + 1]; const char *commit_msg, *commit_summary; git_buf their_label = GIT_BUF_INIT; - git_index *index_new = NULL, *index_repo = NULL; + git_index *index_new = NULL; int error = 0; assert(repo && commit); @@ -196,12 +196,10 @@ int git_cherry_pick( (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJ_COMMIT)) < 0 || (error = git_cherry_pick_commit(&index_new, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 || - (error = git_merge__indexes(repo, index_new)) < 0 || - (error = git_repository_index(&index_repo, repo)) < 0 || - (error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 || - (error = git_checkout_index(repo, index_repo, &opts.checkout_opts)) < 0) + (error = git_merge__check_result(repo, index_new)) < 0 || + (error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 || + (error = git_checkout_index(repo, index_new, &opts.checkout_opts)) < 0) goto on_error; - goto done; on_error: @@ -209,7 +207,6 @@ on_error: done: git_index_free(index_new); - git_index_free(index_repo); git_commit_free(our_commit); git_reference_free(our_ref); git_buf_free(&their_label); diff --git a/src/clone.c b/src/clone.c index 6c4fb6727..8f0284ae6 100644 --- a/src/clone.c +++ b/src/clone.c @@ -24,6 +24,8 @@ #include "repository.h" #include "odb.h" +static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature); + static int create_branch( git_reference **branch, git_repository *repo, @@ -229,6 +231,29 @@ cleanup: return retcode; } +static int default_repository_create(git_repository **out, const char *path, int bare, void *payload) +{ + GIT_UNUSED(payload); + + return git_repository_init(out, path, bare); +} + +static int default_remote_create( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload) +{ + int error; + git_remote_callbacks *callbacks = payload; + + if ((error = git_remote_create(out, repo, name, url)) < 0) + return error; + + return git_remote_set_callbacks(*out, callbacks); +} + /* * submodules? */ @@ -241,8 +266,9 @@ static int create_and_configure_origin( { int error; git_remote *origin = NULL; - const char *name; char buf[GIT_PATH_MAX]; + git_remote_create_cb remote_create = options->remote_cb; + void *payload = options->remote_cb_payload; /* If the path exists and is a dir, the url should be the absolute path */ if (git_path_root(url) < 0 && git_path_exists(url) && git_path_isdir(url)) { @@ -252,14 +278,12 @@ static int create_and_configure_origin( url = buf; } - name = options->remote_name ? options->remote_name : "origin"; - if ((error = git_remote_create(&origin, repo, name, url)) < 0) - goto on_error; - - if (options->ignore_cert_errors) - git_remote_check_cert(origin, 0); + if (!remote_create) { + remote_create = default_remote_create; + payload = (void *)&options->remote_callbacks; + } - if ((error = git_remote_set_callbacks(origin, &options->remote_callbacks)) < 0) + if ((error = remote_create(&origin, repo, "origin", url, payload)) < 0) goto on_error; if ((error = git_remote_save(origin)) < 0) @@ -307,7 +331,7 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c return error; } -int git_clone_into(git_repository *repo, git_remote *_remote, const git_checkout_options *co_opts, const char *branch, const git_signature *signature) +static int clone_into(git_repository *repo, git_remote *_remote, const git_checkout_options *co_opts, const char *branch, const git_signature *signature) { int error; git_buf reflog_message = GIT_BUF_INIT; @@ -381,6 +405,7 @@ int git_clone( git_remote *origin; git_clone_options options = GIT_CLONE_OPTIONS_INIT; uint32_t rmdir_flags = GIT_RMDIR_REMOVE_FILES; + git_repository_create_cb repository_cb; assert(out && url && local_path); @@ -400,17 +425,22 @@ int git_clone( if (git_path_exists(local_path)) rmdir_flags |= GIT_RMDIR_SKIP_ROOT; - if ((error = git_repository_init(&repo, local_path, options.bare)) < 0) + if (options.repository_cb) + repository_cb = options.repository_cb; + else + repository_cb = default_repository_create; + + if ((error = repository_cb(&repo, local_path, options.bare, options.repository_cb_payload)) < 0) return error; if (!(error = create_and_configure_origin(&origin, repo, url, &options))) { if (git_clone__should_clone_local(url, options.local)) { int link = options.local != GIT_CLONE_LOCAL_NO_LINKS; - error = git_clone_local_into( + error = clone_local_into( repo, origin, &options.checkout_opts, options.checkout_branch, link, options.signature); } else { - error = git_clone_into( + error = clone_into( repo, origin, &options.checkout_opts, options.checkout_branch, options.signature); } @@ -470,7 +500,7 @@ static bool can_link(const char *src, const char *dst, int link) #endif } -int git_clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature) +static int clone_local_into(git_repository *repo, git_remote *remote, const git_checkout_options *co_opts, const char *branch, int link, const git_signature *signature) { int error, flags; git_repository *src; diff --git a/src/crlf.c b/src/crlf.c index 821e04eb2..93448760d 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -286,7 +286,8 @@ static int crlf_check( if (error < 0) return error; - if (ca.auto_crlf == GIT_AUTO_CRLF_FALSE) + if (ca.crlf_action == GIT_CRLF_GUESS && + ca.auto_crlf == GIT_AUTO_CRLF_FALSE) return GIT_PASSTHROUGH; if (ca.auto_crlf == GIT_AUTO_CRLF_INPUT && diff --git a/src/indexer.c b/src/indexer.c index eb8b23e92..8daff3dc4 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -435,6 +435,8 @@ static int write_at(git_indexer *idx, const void *data, git_off_t offset, size_t git_map map; int error; + assert(data && size); + /* the offset needs to be at the beginning of the a page boundary */ page_start = (offset / page_size) * page_size; page_offset = offset - page_start; @@ -453,6 +455,9 @@ static int append_to_pack(git_indexer *idx, const void *data, size_t size) { git_off_t current_size = idx->pack->mwf.size; + if (!size) + return 0; + /* add the extra space we need at the end */ if (p_ftruncate(idx->pack->mwf.fd, current_size + size) < 0) { giterr_system_set(errno); diff --git a/src/merge.c b/src/merge.c index a279d31d4..68c9f66e2 100644 --- a/src/merge.c +++ b/src/merge.c @@ -2226,64 +2226,6 @@ static int merge_normalize_checkout_opts( return error; } -static int merge_affected_paths(git_vector *paths, git_repository *repo, git_index *index_new) -{ - git_tree *head_tree = NULL; - git_iterator *iter_head = NULL, *iter_new = NULL; - git_diff *merged_list = NULL; - git_diff_options opts = GIT_DIFF_OPTIONS_INIT; - git_diff_delta *delta; - size_t i; - const git_index_entry *e; - char *path; - int error = 0; - - if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || - (error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || - (error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || - (error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0) - goto done; - - git_vector_foreach(&merged_list->deltas, i, delta) { - path = git__strdup(delta->new_file.path); - GITERR_CHECK_ALLOC(path); - - if ((error = git_vector_insert(paths, path)) < 0) - goto on_error; - } - - for (i = 0; i < git_index_entrycount(index_new); i++) { - e = git_index_get_byindex(index_new, i); - - if (git_index_entry_stage(e) != 0 && - (git_vector_last(paths) == NULL || - strcmp(git_vector_last(paths), e->path) != 0)) { - - path = git__strdup(e->path); - GITERR_CHECK_ALLOC(path); - - if ((error = git_vector_insert(paths, path)) < 0) - goto on_error; - } - } - - goto done; - -on_error: - git_vector_foreach(paths, i, path) - git__free(path); - - git_vector_clear(paths); - -done: - git_tree_free(head_tree); - git_iterator_free(iter_head); - git_iterator_free(iter_new); - git_diff_free(merged_list); - - return error; -} - static int merge_check_index(size_t *conflicts, git_repository *repo, git_index *index_new, git_vector *merged_paths) { git_tree *head_tree = NULL; @@ -2372,99 +2314,58 @@ done: return error; } -int git_merge__indexes(git_repository *repo, git_index *index_new) +int git_merge__check_result(git_repository *repo, git_index *index_new) { - git_index *index_repo = NULL; - int index_repo_caps = 0; + git_tree *head_tree = NULL; + git_iterator *iter_head = NULL, *iter_new = NULL; + git_diff *merged_list = NULL; + git_diff_options opts = GIT_DIFF_OPTIONS_INIT; + git_diff_delta *delta; git_vector paths = GIT_VECTOR_INIT; - size_t index_conflicts = 0, wd_conflicts = 0, conflicts, i; - char *path; + size_t i, index_conflicts = 0, wd_conflicts = 0, conflicts; const git_index_entry *e; - const git_index_name_entry *name; - const git_index_reuc_entry *reuc; int error = 0; - if ((error = git_repository_index(&index_repo, repo)) < 0) - goto done; - - /* Set the index to case sensitive to handle the merge */ - index_repo_caps = git_index_caps(index_repo); - - if ((error = git_index_set_caps(index_repo, (index_repo_caps & ~GIT_INDEXCAP_IGNORE_CASE))) < 0) - goto done; - - /* Make sure the index and workdir state do not prevent merging */ - if ((error = merge_affected_paths(&paths, repo, index_new)) < 0 || - (error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 || - (error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0) - goto done; - - if ((conflicts = index_conflicts + wd_conflicts) > 0) { - giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge", - conflicts, (conflicts != 1) ? "s" : ""); - error = GIT_EMERGECONFLICT; - + if ((error = git_repository_head_tree(&head_tree, repo)) < 0 || + (error = git_iterator_for_tree(&iter_head, head_tree, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_iterator_for_index(&iter_new, index_new, GIT_ITERATOR_DONT_IGNORE_CASE, NULL, NULL)) < 0 || + (error = git_diff__from_iterators(&merged_list, repo, iter_head, iter_new, &opts)) < 0) goto done; - } - /* Remove removed items from the index */ - git_vector_foreach(&paths, i, path) { - if (git_index_get_bypath(index_new, path, 0) == NULL) { - if ((error = git_index_remove(index_repo, path, 0)) < 0 && - error != GIT_ENOTFOUND) - goto done; - } - } - - /* Add updated items to the index */ - git_vector_foreach(&paths, i, path) { - if ((e = git_index_get_bypath(index_new, path, 0)) != NULL) { - if ((error = git_index_add(index_repo, e)) < 0) - goto done; - } + git_vector_foreach(&merged_list->deltas, i, delta) { + if ((error = git_vector_insert(&paths, (char *)delta->new_file.path)) < 0) + goto done; } - /* Add conflicts */ - git_index_conflict_cleanup(index_repo); - for (i = 0; i < git_index_entrycount(index_new); i++) { e = git_index_get_byindex(index_new, i); if (git_index_entry_stage(e) != 0 && - (error = git_index_add(index_repo, e)) < 0) - goto done; - } + (git_vector_last(&paths) == NULL || + strcmp(git_vector_last(&paths), e->path) != 0)) { - /* Add name entries */ - git_index_name_clear(index_repo); - - for (i = 0; i < git_index_name_entrycount(index_new); i++) { - name = git_index_name_get_byindex(index_new, i); - - if ((error = git_index_name_add(index_repo, - name->ancestor, name->ours, name->theirs)) < 0) - goto done; + if ((error = git_vector_insert(&paths, (char *)e->path)) < 0) + goto done; + } } - /* Add the reuc */ - git_index_reuc_clear(index_repo); - - for (i = 0; i < git_index_reuc_entrycount(index_new); i++) { - reuc = (git_index_reuc_entry *)git_index_reuc_get_byindex(index_new, i); + /* Make sure the index and workdir state do not prevent merging */ + if ((error = merge_check_index(&index_conflicts, repo, index_new, &paths)) < 0 || + (error = merge_check_workdir(&wd_conflicts, repo, index_new, &paths)) < 0) + goto done; - if ((error = git_index_reuc_add(index_repo, reuc->path, - reuc->mode[0], &reuc->oid[0], - reuc->mode[1], &reuc->oid[1], - reuc->mode[2], &reuc->oid[2])) < 0) - goto done; + if ((conflicts = index_conflicts + wd_conflicts) > 0) { + giterr_set(GITERR_MERGE, "%d uncommitted change%s would be overwritten by merge", + conflicts, (conflicts != 1) ? "s" : ""); + error = GIT_EMERGECONFLICT; } done: - if (index_repo != NULL) - git_index_set_caps(index_repo, index_repo_caps); - - git_index_free(index_repo); - git_vector_free_deep(&paths); + git_vector_free(&paths); + git_tree_free(head_tree); + git_iterator_free(iter_head); + git_iterator_free(iter_new); + git_diff_free(merged_list); return error; } @@ -2657,7 +2558,7 @@ int git_merge( git_checkout_options checkout_opts; git_merge_head *ancestor_head = NULL, *our_head = NULL; git_tree *ancestor_tree = NULL, *our_tree = NULL, **their_trees = NULL; - git_index *index_new = NULL, *index_repo = NULL; + git_index *index_new = NULL; size_t i; int error = 0; @@ -2697,10 +2598,9 @@ int git_merge( /* TODO: recursive, octopus, etc... */ if ((error = git_merge_trees(&index_new, repo, ancestor_tree, our_tree, their_trees[0], merge_opts)) < 0 || - (error = git_merge__indexes(repo, index_new)) < 0 || - (error = git_repository_index(&index_repo, repo)) < 0 || - (error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 || - (error = git_checkout_index(repo, index_repo, &checkout_opts)) < 0) + (error = git_merge__check_result(repo, index_new)) < 0 || + (error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 || + (error = git_checkout_index(repo, index_new, &checkout_opts)) < 0) goto on_error; goto done; @@ -2710,7 +2610,6 @@ on_error: done: git_index_free(index_new); - git_index_free(index_repo); git_tree_free(ancestor_tree); git_tree_free(our_tree); diff --git a/src/merge.h b/src/merge.h index 00f6197bf..cc17389ab 100644 --- a/src/merge.h +++ b/src/merge.h @@ -149,7 +149,7 @@ int git_merge__setup( const git_merge_head *heads[], size_t heads_len); -int git_merge__indexes(git_repository *repo, git_index *index_new); +int git_merge__check_result(git_repository *repo, git_index *index_new); int git_merge__append_conflicts_to_merge_msg(git_repository *repo, git_index *index); diff --git a/src/mwindow.c b/src/mwindow.c index 0d6535056..1d64d26a4 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -62,11 +62,14 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) if ((error = git_packfile__name(&packname, path)) < 0) return error; - if (git_mutex_lock(&git__mwindow_mutex) < 0) + if (git_mutex_lock(&git__mwindow_mutex) < 0) { + giterr_set(GITERR_OS, "failed to lock mwindow mutex"); return -1; + } if (git_mwindow_files_init() < 0) { git_mutex_unlock(&git__mwindow_mutex); + git__free(packname); return -1; } @@ -93,31 +96,29 @@ int git_mwindow_get_pack(struct git_pack_file **out, const char *path) git_strmap_insert(git__pack_cache, pack->pack_name, pack, error); git_mutex_unlock(&git__mwindow_mutex); - if (error < 0) + if (error < 0) { + git_packfile_free(pack); return -1; + } *out = pack; return 0; } -int git_mwindow_put_pack(struct git_pack_file *pack) +void git_mwindow_put_pack(struct git_pack_file *pack) { int count; git_strmap_iter pos; if (git_mutex_lock(&git__mwindow_mutex) < 0) - return -1; + return; - if (git_mwindow_files_init() < 0) { - git_mutex_unlock(&git__mwindow_mutex); - return -1; - } + /* put before get would be a corrupted state */ + assert(git__pack_cache); pos = git_strmap_lookup_index(git__pack_cache, pack->pack_name); - if (!git_strmap_valid_index(git__pack_cache, pos)) { - git_mutex_unlock(&git__mwindow_mutex); - return GIT_ENOTFOUND; - } + /* if we cannot find it, the state is corrupted */ + assert(git_strmap_valid_index(git__pack_cache, pos)); count = git_atomic_dec(&pack->refcount); if (count == 0) { @@ -126,7 +127,7 @@ int git_mwindow_put_pack(struct git_pack_file *pack) } git_mutex_unlock(&git__mwindow_mutex); - return 0; + return; } void git_mwindow_free_all(git_mwindow_file *mwf) diff --git a/src/mwindow.h b/src/mwindow.h index 57fabae70..63418e458 100644 --- a/src/mwindow.h +++ b/src/mwindow.h @@ -48,6 +48,6 @@ void git_mwindow_files_free(void); struct git_pack_file; /* just declaration to avoid cyclical includes */ int git_mwindow_get_pack(struct git_pack_file **out, const char *path); -int git_mwindow_put_pack(struct git_pack_file *pack); +void git_mwindow_put_pack(struct git_pack_file *pack); #endif diff --git a/src/pack.c b/src/pack.c index 767efb6c3..22dbd5647 100644 --- a/src/pack.c +++ b/src/pack.c @@ -968,10 +968,10 @@ void git_packfile_free(struct git_pack_file *p) cache_free(&p->bases); - git_mwindow_free_all_locked(&p->mwf); - - if (p->mwf.fd >= 0) + if (p->mwf.fd >= 0) { + git_mwindow_free_all_locked(&p->mwf); p_close(p->mwf.fd); + } pack_index_free(p); diff --git a/src/pool.c b/src/pool.c index 146f118b4..a516ff9eb 100644 --- a/src/pool.c +++ b/src/pool.c @@ -146,7 +146,7 @@ GIT_INLINE(void) pool_remove_page( void *git_pool_malloc(git_pool *pool, uint32_t items) { git_pool_page *scan = pool->open, *prev; - uint32_t size = items * pool->item_size; + uint32_t size = ((items * pool->item_size) + 7) & ~7; void *ptr = NULL; pool->has_string_alloc = 0; diff --git a/src/refs.h b/src/refs.h index f75a4bf7e..a46b219b6 100644 --- a/src/refs.h +++ b/src/refs.h @@ -63,7 +63,7 @@ struct git_reference { } target; git_oid peel; - char name[0]; + char name[GIT_FLEX_ARRAY]; }; git_reference *git_reference__set_name(git_reference *ref, const char *name); diff --git a/src/remote.c b/src/remote.c index 47b61b1b1..e9dafa0ea 100644 --- a/src/remote.c +++ b/src/remote.c @@ -267,9 +267,11 @@ int git_remote_dup(git_remote **dest, git_remote *source) if (source->pushurl != NULL) { remote->pushurl = git__strdup(source->pushurl); - GITERR_CHECK_ALLOC(remote->pushurl); + GITERR_CHECK_ALLOC(remote->pushurl); } + remote->transport_cb = source->transport_cb; + remote->transport_cb_payload = source->transport_cb_payload; remote->repo = source->repo; remote->download_tags = source->download_tags; remote->check_cert = source->check_cert; @@ -659,8 +661,14 @@ int git_remote_connect(git_remote *remote, git_direction direction) return -1; } - /* A transport could have been supplied in advance with - * git_remote_set_transport */ + /* If we don't have a transport object yet, and the caller specified a + * custom transport factory, use that */ + if (!t && remote->transport_cb && + (error = remote->transport_cb(&t, remote, remote->transport_cb_payload)) < 0) + return error; + + /* If we still don't have a transport, then use the global + * transport registrations which map URI schemes to transport factories */ if (!t && (error = git_transport_new(&t, remote, url)) < 0) return error; @@ -1262,18 +1270,20 @@ const git_remote_callbacks *git_remote_get_callbacks(git_remote *remote) return &remote->callbacks; } -int git_remote_set_transport(git_remote *remote, git_transport *transport) +int git_remote_set_transport( + git_remote *remote, + git_transport_cb transport_cb, + void *payload) { - assert(remote && transport); - - GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport"); + assert(remote); if (remote->transport) { giterr_set(GITERR_NET, "A transport is already bound to this remote"); return -1; } - remote->transport = transport; + remote->transport_cb = transport_cb; + remote->transport_cb_payload = payload; return 0; } diff --git a/src/remote.h b/src/remote.h index 4164a14b3..47c4f7221 100644 --- a/src/remote.h +++ b/src/remote.h @@ -22,6 +22,8 @@ struct git_remote { git_vector refs; git_vector refspecs; git_vector active_refspecs; + git_transport_cb transport_cb; + void *transport_cb_payload; git_transport *transport; git_repository *repo; git_remote_callbacks callbacks; diff --git a/src/revert.c b/src/revert.c index 9c587724b..36560a77c 100644 --- a/src/revert.c +++ b/src/revert.c @@ -174,7 +174,7 @@ int git_revert( char commit_oidstr[GIT_OID_HEXSZ + 1]; const char *commit_msg; git_buf their_label = GIT_BUF_INIT; - git_index *index_new = NULL, *index_repo = NULL; + git_index *index_new = NULL; int error; assert(repo && commit); @@ -199,10 +199,9 @@ int git_revert( (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJ_COMMIT)) < 0 || (error = git_revert_commit(&index_new, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 || - (error = git_merge__indexes(repo, index_new)) < 0 || - (error = git_repository_index(&index_repo, repo)) < 0 || - (error = git_merge__append_conflicts_to_merge_msg(repo, index_repo)) < 0 || - (error = git_checkout_index(repo, index_repo, &opts.checkout_opts)) < 0) + (error = git_merge__check_result(repo, index_new)) < 0 || + (error = git_merge__append_conflicts_to_merge_msg(repo, index_new)) < 0 || + (error = git_checkout_index(repo, index_new, &opts.checkout_opts)) < 0) goto on_error; goto done; @@ -212,7 +211,6 @@ on_error: done: git_index_free(index_new); - git_index_free(index_repo); git_commit_free(our_commit); git_reference_free(our_ref); git_buf_free(&their_label); diff --git a/src/transport.c b/src/transport.c index 2194b1864..fbcda5a53 100644 --- a/src/transport.c +++ b/src/transport.c @@ -133,10 +133,11 @@ int git_transport_new(git_transport **out, git_remote *owner, const char *url) return -1; } - error = fn(&transport, owner, param); - if (error < 0) + if ((error = fn(&transport, owner, param)) < 0) return error; + GITERR_CHECK_VERSION(transport, GIT_TRANSPORT_VERSION, "git_transport"); + *out = transport; return 0; diff --git a/src/transports/smart_protocol.c b/src/transports/smart_protocol.c index a52aacc60..82891165f 100644 --- a/src/transports/smart_protocol.c +++ b/src/transports/smart_protocol.c @@ -592,7 +592,9 @@ int git_smart__download_pack( } } else if (pkt->type == GIT_PKT_DATA) { git_pkt_data *p = (git_pkt_data *) pkt; - error = writepack->append(writepack, p->data, p->len, stats); + + if (p->len) + error = writepack->append(writepack, p->data, p->len, stats); } else if (pkt->type == GIT_PKT_FLUSH) { /* A flush indicates the end of the packfile */ git__free(pkt); diff --git a/src/transports/ssh.c b/src/transports/ssh.c index b403727c9..79a632bd5 100644 --- a/src/transports/ssh.c +++ b/src/transports/ssh.c @@ -132,11 +132,22 @@ static int ssh_stream_write( size_t len) { ssh_stream *s = (ssh_stream *)stream; + size_t off = 0; + ssize_t ret = 0; if (!s->sent_command && send_command(s) < 0) return -1; - if (libssh2_channel_write(s->channel, buffer, len) < LIBSSH2_ERROR_NONE) { + do { + ret = libssh2_channel_write(s->channel, buffer + off, len - off); + if (ret < 0) + break; + + off += ret; + + } while (off < len); + + if (ret < 0) { ssh_error(s->session, "SSH could not write data"); return -1; } diff --git a/src/tree.c b/src/tree.c index e0e2dbebf..28190d6da 100644 --- a/src/tree.c +++ b/src/tree.c @@ -466,6 +466,7 @@ static int append_entry( git_strmap_insert(bld->map, entry->filename, entry, error); if (error < 0) { + git_tree_entry_free(entry); giterr_set(GITERR_TREE, "failed to append entry %s to the tree builder", filename); return -1; } @@ -622,6 +623,7 @@ int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) GITERR_CHECK_ALLOC(bld); if (git_strmap_alloc(&bld->map) < 0) { + git__free(bld); return -1; } diff --git a/tests/checkout/conflict.c b/tests/checkout/conflict.c index cc41fdb3c..b8ae80576 100644 --- a/tests/checkout/conflict.c +++ b/tests/checkout/conflict.c @@ -169,7 +169,7 @@ static void ensure_workdir_mode(const char *path, int mode) git_buf_joinpath(&fullpath, git_repository_workdir(g_repo), path)); cl_git_pass(p_stat(git_buf_cstr(&fullpath), &st)); - cl_assert_equal_i(mode, st.st_mode); + cl_assert_equal_i((mode & S_IRWXU), (st.st_mode & S_IRWXU)); git_buf_free(&fullpath); #endif diff --git a/tests/checkout/crlf.c b/tests/checkout/crlf.c index 2c84a77f3..496f83d5d 100644 --- a/tests/checkout/crlf.c +++ b/tests/checkout/crlf.c @@ -279,8 +279,13 @@ void test_checkout_crlf__autocrlf_false_text_auto_attr(void) git_checkout_head(g_repo, &opts); - check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW); - check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW); + if (GIT_EOL_NATIVE == GIT_EOL_CRLF) { + check_file_contents("./crlf/all-lf", ALL_LF_TEXT_AS_CRLF); + check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_AS_CRLF); + } else { + check_file_contents("./crlf/all-lf", ALL_LF_TEXT_RAW); + check_file_contents("./crlf/all-crlf", ALL_CRLF_TEXT_RAW); + } } void test_checkout_crlf__autocrlf_true_text_auto_attr(void) diff --git a/tests/clone/local.c b/tests/clone/local.c index a4406c1cc..c8ebc143d 100644 --- a/tests/clone/local.c +++ b/tests/clone/local.c @@ -31,31 +31,24 @@ void test_clone_local__should_clone_local(void) void test_clone_local__hardlinks(void) { git_repository *repo; - git_remote *remote; - git_signature *sig; + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; git_buf buf = GIT_BUF_INIT; struct stat st; - /* * In this first clone, we just copy over, since the temp dir * will often be in a different filesystem, so we cannot * link. It also allows us to control the number of links */ - cl_git_pass(git_repository_init(&repo, "./clone.git", true)); - cl_git_pass(git_remote_create(&remote, repo, "origin", cl_fixture("testrepo.git"))); - cl_git_pass(git_signature_now(&sig, "foo", "bar")); - cl_git_pass(git_clone_local_into(repo, remote, NULL, NULL, false, sig)); - - git_remote_free(remote); + opts.bare = true; + opts.local = GIT_CLONE_LOCAL_NO_LINKS; + cl_git_pass(git_clone(&repo, cl_fixture("testrepo.git"), "./clone.git", &opts)); git_repository_free(repo); /* This second clone is in the same filesystem, so we can hardlink */ - cl_git_pass(git_repository_init(&repo, "./clone2.git", true)); - cl_git_pass(git_buf_puts(&buf, cl_git_path_url("clone.git"))); - cl_git_pass(git_remote_create(&remote, repo, "origin", buf.ptr)); - cl_git_pass(git_clone_local_into(repo, remote, NULL, NULL, true, sig)); + opts.local = GIT_CLONE_LOCAL; + cl_git_pass(git_clone(&repo, cl_git_path_url("clone.git"), "./clone2.git", &opts)); #ifndef GIT_WIN32 git_buf_clear(&buf); @@ -65,14 +58,11 @@ void test_clone_local__hardlinks(void) cl_assert_equal_i(2, st.st_nlink); #endif - git_remote_free(remote); git_repository_free(repo); git_buf_clear(&buf); - cl_git_pass(git_repository_init(&repo, "./clone3.git", true)); - cl_git_pass(git_buf_puts(&buf, cl_git_path_url("clone.git"))); - cl_git_pass(git_remote_create(&remote, repo, "origin", buf.ptr)); - cl_git_pass(git_clone_local_into(repo, remote, NULL, NULL, false, sig)); + opts.local = GIT_CLONE_LOCAL_NO_LINKS; + cl_git_pass(git_clone(&repo, cl_git_path_url("clone.git"), "./clone3.git", &opts)); git_buf_clear(&buf); cl_git_pass(git_buf_join_n(&buf, '/', 4, git_repository_path(repo), "objects", "08", "b041783f40edfe12bb406c9c9a8a040177c125")); @@ -80,7 +70,6 @@ void test_clone_local__hardlinks(void) cl_git_pass(p_stat(buf.ptr, &st)); cl_assert_equal_i(1, st.st_nlink); - git_remote_free(remote); git_repository_free(repo); /* this one should automatically use links */ @@ -95,7 +84,6 @@ void test_clone_local__hardlinks(void) #endif git_buf_free(&buf); - git_signature_free(sig); git_repository_free(repo); cl_git_pass(git_futils_rmdir_r("./clone.git", NULL, GIT_RMDIR_REMOVE_FILES)); diff --git a/tests/clone/nonetwork.c b/tests/clone/nonetwork.c index 131d7e428..e9853313e 100644 --- a/tests/clone/nonetwork.c +++ b/tests/clone/nonetwork.c @@ -110,12 +110,25 @@ void test_clone_nonetwork__fail_with_already_existing_but_non_empty_directory(vo cl_git_fail(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); } +int custom_origin_name_remote_create( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload) +{ + GIT_UNUSED(name); + GIT_UNUSED(payload); + + return git_remote_create(out, repo, "my_origin", url); +} + void test_clone_nonetwork__custom_origin_name(void) { - g_options.remote_name = "my_origin"; - cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); + g_options.remote_cb = custom_origin_name_remote_create; + cl_git_pass(git_clone(&g_repo, cl_git_fixture_url("testrepo.git"), "./foo", &g_options)); - cl_git_pass(git_remote_load(&g_remote, g_repo, "my_origin")); + cl_git_pass(git_remote_load(&g_remote, g_repo, "my_origin")); } void test_clone_nonetwork__defaults(void) @@ -266,23 +279,6 @@ void test_clone_nonetwork__clone_updates_reflog_properly(void) assert_correct_reflog("refs/heads/master"); } -void test_clone_nonetwork__clone_into_updates_reflog_properly(void) -{ - git_remote *remote; - git_signature *sig; - cl_git_pass(git_signature_now(&sig, "Me", "foo@example.com")); - - cl_git_pass(git_repository_init(&g_repo, "./foo", false)); - cl_git_pass(git_remote_create(&remote, g_repo, "origin", cl_git_fixture_url("testrepo.git"))); - cl_git_pass(git_clone_into(g_repo, remote, NULL, NULL, sig)); - - assert_correct_reflog("HEAD"); - assert_correct_reflog("refs/heads/master"); - - git_remote_free(remote); - git_signature_free(sig); -} - static void cleanup_repository(void *path) { if (g_repo) { diff --git a/tests/clone/transport.c b/tests/clone/transport.c new file mode 100644 index 000000000..27568f228 --- /dev/null +++ b/tests/clone/transport.c @@ -0,0 +1,50 @@ +#include "clar_libgit2.h" + +#include "git2/clone.h" +#include "git2/transport.h" +#include "fileops.h" + +static int custom_transport( + git_transport **out, + git_remote *owner, + void *payload) +{ + *((int*)payload) = 1; + + return git_transport_local(out, owner, payload); +} + +static int custom_transport_remote_create( + git_remote **out, + git_repository *repo, + const char *name, + const char *url, + void *payload) +{ + int error; + + if ((error = git_remote_create(out, repo, name, url)) < 0) + return error; + + if ((error = git_remote_set_transport(*out, custom_transport, payload)) < 0) + return error; + + return 0; +} + +void test_clone_transport__custom_transport(void) +{ + git_repository *repo; + git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT; + int custom_transport_used = 0; + + clone_opts.remote_cb = custom_transport_remote_create; + clone_opts.remote_cb_payload = &custom_transport_used; + + cl_git_pass(git_clone(&repo, cl_fixture("testrepo.git"), "./custom_transport.git", &clone_opts)); + git_repository_free(repo); + + cl_git_pass(git_futils_rmdir_r("./custom_transport.git", NULL, GIT_RMDIR_REMOVE_FILES)); + + cl_assert(custom_transport_used == 1); +} diff --git a/tests/core/pool.c b/tests/core/pool.c index 351d0c20f..a7ec8801b 100644 --- a/tests/core/pool.c +++ b/tests/core/pool.c @@ -38,19 +38,19 @@ void test_core_pool__1(void) cl_assert(git_pool_malloc(&p, i) != NULL); /* with fixed page size, allocation must end up with these values */ - cl_assert(git_pool__open_pages(&p) == 1); - cl_assert(git_pool__full_pages(&p) == 505); + cl_assert_equal_i(1, git_pool__open_pages(&p)); + cl_assert_equal_i(507, git_pool__full_pages(&p)); git_pool_clear(&p); - cl_git_pass(git_pool_init(&p, 1, 4100)); + cl_git_pass(git_pool_init(&p, 1, 4120)); for (i = 2010; i > 0; i--) cl_assert(git_pool_malloc(&p, i) != NULL); /* with fixed page size, allocation must end up with these values */ - cl_assert(git_pool__open_pages(&p) == 1); - cl_assert(git_pool__full_pages(&p) == 492); + cl_assert_equal_i(1, git_pool__open_pages(&p)); + cl_assert_equal_i(492, git_pool__full_pages(&p)); git_pool_clear(&p); } diff --git a/tests/merge/workdir/dirty.c b/tests/merge/workdir/dirty.c index 776e4ea69..2f776853e 100644 --- a/tests/merge/workdir/dirty.c +++ b/tests/merge/workdir/dirty.c @@ -97,7 +97,7 @@ static int merge_branch(void) cl_git_pass(git_oid_fromstr(&their_oids[0], MERGE_BRANCH_OID)); cl_git_pass(git_merge_head_from_id(&their_heads[0], repo, &their_oids[0])); - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_ALLOW_CONFLICTS; + checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE; error = git_merge(repo, (const git_merge_head **)their_heads, 1, &merge_opts, &checkout_opts); git_merge_head_free(their_heads[0]); diff --git a/tests/network/fetchlocal.c b/tests/network/fetchlocal.c index 0d23bef48..8809f427d 100644 --- a/tests/network/fetchlocal.c +++ b/tests/network/fetchlocal.c @@ -87,28 +87,43 @@ void test_network_fetchlocal__partial(void) git_remote_free(origin); } -void test_network_fetchlocal__clone_into_mirror(void) +static int remote_mirror_cb(git_remote **out, git_repository *repo, + const char *name, const char *url, void *payload) { - git_buf path = GIT_BUF_INIT; - git_repository *repo; + int error; git_remote *remote; - git_reference *head; - cl_git_pass(git_repository_init(&repo, "./foo.git", true)); - cl_git_pass(git_remote_create(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"))); + GIT_UNUSED(payload); + + if ((error = git_remote_create(&remote, repo, name, url)) < 0) + return error; git_remote_clear_refspecs(remote); - cl_git_pass(git_remote_add_fetch(remote, "+refs/*:refs/*")); - cl_git_pass(git_clone_into(repo, remote, NULL, NULL, NULL)); + if ((error = git_remote_add_fetch(remote, "+refs/*:refs/*")) < 0) { + git_remote_free(remote); + return error; + } + + *out = remote; + return 0; +} + +void test_network_fetchlocal__clone_into_mirror(void) +{ + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + git_repository *repo; + git_reference *head; + + opts.bare = true; + opts.remote_cb = remote_mirror_cb; + cl_git_pass(git_clone(&repo, cl_git_fixture_url("testrepo.git"), "./foo.git", &opts)); cl_git_pass(git_reference_lookup(&head, repo, "HEAD")); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); - git_remote_free(remote); git_reference_free(head); git_repository_free(repo); - git_buf_free(&path); cl_fixture_cleanup("./foo.git"); } diff --git a/tests/network/remote/remotes.c b/tests/network/remote/remotes.c index 333b52a5b..21c57119a 100644 --- a/tests/network/remote/remotes.c +++ b/tests/network/remote/remotes.c @@ -72,18 +72,17 @@ void test_network_remote_remotes__error_when_not_found(void) void test_network_remote_remotes__error_when_no_push_available(void) { git_remote *r; - git_transport *t; git_push *p; cl_git_pass(git_remote_create_anonymous(&r, _repo, cl_fixture("testrepo.git"), NULL)); - cl_git_pass(git_transport_local(&t,r,NULL)); + cl_git_pass(git_remote_set_transport(r, git_transport_local, NULL)); + + cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH)); /* Make sure that push is really not available */ - t->push = NULL; - cl_git_pass(git_remote_set_transport(r, t)); + r->transport->push = NULL; - cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH)); cl_git_pass(git_push_new(&p, r)); cl_git_pass(git_push_add_refspec(p, "refs/heads/master")); cl_git_fail_with(git_push_finish(p), GIT_ERROR); @@ -438,27 +437,6 @@ void test_network_remote_remotes__returns_ENOTFOUND_when_neither_url_nor_pushurl git_remote_load(&remote, _repo, "no-remote-url"), GIT_ENOTFOUND); } -void test_network_remote_remotes__check_structure_version(void) -{ - git_transport transport = GIT_TRANSPORT_INIT; - const git_error *err; - - git_remote_free(_remote); - _remote = NULL; - cl_git_pass(git_remote_create_anonymous(&_remote, _repo, "test-protocol://localhost", NULL)); - - transport.version = 0; - cl_git_fail(git_remote_set_transport(_remote, &transport)); - err = giterr_last(); - cl_assert_equal_i(GITERR_INVALID, err->klass); - - giterr_clear(); - transport.version = 1024; - cl_git_fail(git_remote_set_transport(_remote, &transport)); - err = giterr_last(); - cl_assert_equal_i(GITERR_INVALID, err->klass); -} - void assert_cannot_create_remote(const char *name, int expected_error) { git_remote *remote = NULL; diff --git a/tests/online/clone.c b/tests/online/clone.c index 4f4312a8c..2e2e97675 100644 --- a/tests/online/clone.c +++ b/tests/online/clone.c @@ -124,65 +124,49 @@ void test_online_clone__can_checkout_a_cloned_repo(void) git_buf_free(&path); } -void test_online_clone__clone_into(void) +static int remote_mirror_cb(git_remote **out, git_repository *repo, + const char *name, const char *url, void *payload) { - git_buf path = GIT_BUF_INIT; + int error; git_remote *remote; - git_reference *head; - git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; - git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; - - bool checkout_progress_cb_was_called = false, - fetch_progress_cb_was_called = false; - - checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE_CREATE; - checkout_opts.progress_cb = &checkout_progress; - checkout_opts.progress_payload = &checkout_progress_cb_was_called; + git_remote_callbacks *callbacks = (git_remote_callbacks *) payload; - cl_git_pass(git_repository_init(&g_repo, "./foo", false)); - cl_git_pass(git_remote_create(&remote, g_repo, "origin", LIVE_REPO_URL)); - callbacks.transfer_progress = &fetch_progress; - callbacks.payload = &fetch_progress_cb_was_called; - git_remote_set_callbacks(remote, &callbacks); + if ((error = git_remote_create(&remote, repo, name, url)) < 0) + return error; - cl_git_pass(git_clone_into(g_repo, remote, &checkout_opts, NULL, NULL)); - - cl_git_pass(git_buf_joinpath(&path, git_repository_workdir(g_repo), "master.txt")); - cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&path))); + if ((error = git_remote_set_callbacks(remote, callbacks)) < 0) { + git_remote_free(remote); + return error; + } - cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); - cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); - cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); + git_remote_clear_refspecs(remote); - cl_assert_equal_i(true, checkout_progress_cb_was_called); - cl_assert_equal_i(true, fetch_progress_cb_was_called); + if ((error = git_remote_add_fetch(remote, "+refs/*:refs/*")) < 0) { + git_remote_free(remote); + return error; + } - git_remote_free(remote); - git_reference_free(head); - git_buf_free(&path); + *out = remote; + return 0; } void test_online_clone__clone_mirror(void) { - git_buf path = GIT_BUF_INIT; - git_remote *remote; + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; git_reference *head; git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; bool fetch_progress_cb_was_called = false; - cl_git_pass(git_repository_init(&g_repo, "./foo.git", true)); - cl_git_pass(git_remote_create(&remote, g_repo, "origin", LIVE_REPO_URL)); - callbacks.transfer_progress = &fetch_progress; callbacks.payload = &fetch_progress_cb_was_called; - git_remote_set_callbacks(remote, &callbacks); - git_remote_clear_refspecs(remote); - cl_git_pass(git_remote_add_fetch(remote, "+refs/*:refs/*")); + opts.bare = true; + opts.remote_cb = remote_mirror_cb; + opts.remote_cb_payload = &callbacks; - cl_git_pass(git_clone_into(g_repo, remote, NULL, NULL, NULL)); + cl_git_pass(git_clone(&g_repo, LIVE_REPO_URL, "./foo.git", &opts)); cl_git_pass(git_reference_lookup(&head, g_repo, "HEAD")); cl_assert_equal_i(GIT_REF_SYMBOLIC, git_reference_type(head)); @@ -190,9 +174,7 @@ void test_online_clone__clone_mirror(void) cl_assert_equal_i(true, fetch_progress_cb_was_called); - git_remote_free(remote); git_reference_free(head); - git_buf_free(&path); git_repository_free(g_repo); g_repo = NULL; |
