diff options
author | Vicent Marti <tanoku@gmail.com> | 2011-11-28 18:44:47 +0100 |
---|---|---|
committer | Vicent Marti <tanoku@gmail.com> | 2011-11-28 18:44:47 +0100 |
commit | bb34a9362100ccdbfef10212dc9000f5800266d9 (patch) | |
tree | 1b26cee0c3d383043902c599893299fd8fdc5302 | |
parent | 880b6f0c22153db164ecb3a18c362ba8337365d3 (diff) | |
parent | d88d4311c7e08ad0d38edae006b50e2a548c937d (diff) | |
download | libgit2-bb34a9362100ccdbfef10212dc9000f5800266d9.tar.gz |
Merge branch 'repo-ownership' into development
72 files changed, 1987 insertions, 2081 deletions
diff --git a/examples/general.c b/examples/general.c index 8b58fa6ff..c67ff6f64 100644 --- a/examples/general.c +++ b/examples/general.c @@ -107,7 +107,7 @@ int main (int argc, char** argv) // For proper memory management, close the object when you are done with it or it will leak // memory. - git_odb_object_close(obj); + git_odb_object_free(obj); // #### Raw Object Writing @@ -167,12 +167,12 @@ int main (int argc, char** argv) git_commit_parent(&parent, commit, p); git_oid_fmt(out, git_commit_id(parent)); printf("Parent: %s\n", out); - git_commit_close(parent); + git_commit_free(parent); } // Don't forget to close the object to prevent memory leaks. You will have to do this for // all the objects you open and parse. - git_commit_close(commit); + git_commit_free(commit); // #### Writing Commits // @@ -243,7 +243,7 @@ int main (int argc, char** argv) tmessage = git_tag_message(tag); // "tag message\n" printf("Tag Message: %s\n", tmessage); - git_commit_close(commit); + git_commit_free(commit); // #### Tree Parsing // [Tree parsing][tp] is a bit different than the other objects, in that we have a subtype which is the @@ -276,7 +276,7 @@ int main (int argc, char** argv) git_tree_entry_2object(&objt, repo, entry); // blob // Remember to close the looked-up object once you are done using it - git_object_close(objt); + git_object_free(objt); // #### Blob Parsing // @@ -340,7 +340,7 @@ int main (int argc, char** argv) cmsg = git_commit_message(wcommit); cauth = git_commit_author(wcommit); printf("%s (%s)\n", cmsg, cauth->email); - git_commit_close(wcommit); + git_commit_free(wcommit); } // Like the other objects, be sure to free the revwalker when you're done to prevent memory leaks. diff --git a/examples/network/Makefile b/examples/network/Makefile index 59a607632..ed0c2099f 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -1,17 +1,8 @@ default: all -# If you've installed libgit2 to a non-standard location, you can use -# these lines to make pkg-config find it. - -#LIBGIT2_PATH ?= $(HOME)/staging/libgit2/lib DEPS = -#$(shell PKG_CONFIG_PATH=$(LIBGIT2_PATH)/pkgconfig pkg-config --cflags -#--libs libgit2) - -DEPS = $(shell pkg-config --cflags --libs libgit2) - CC = gcc CFLAGS += -g -CFLAGS += $(DEPS) +CFLAGS += -I../../include -L../../ -lgit2 OBJECTS = \ git2.o \ diff --git a/examples/network/fetch.c b/examples/network/fetch.c index dd732f22e..cdd4a4662 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -4,23 +4,6 @@ #include <stdlib.h> #include <string.h> -static void show_refs(git_headarray *refs) -{ - int i; - git_remote_head *head; - - if(refs->len == 0) - puts("Everything up-to-date"); - - for(i = 0; i < refs->len; ++i){ - char oid[GIT_OID_HEXSZ + 1] = {0}; - char *havewant; - head = refs->heads[i]; - git_oid_fmt(oid, &head->oid); - printf("%s\t%s\n", oid, head->name); - } -} - static int rename_packfile(char *packname, git_indexer *idx) { char path[GIT_PATH_MAX], oid[GIT_OID_HEXSZ + 1], *slash; @@ -50,20 +33,14 @@ static int rename_packfile(char *packname, git_indexer *idx) int fetch(git_repository *repo, int argc, char **argv) { git_remote *remote = NULL; - git_config *cfg = NULL; git_indexer *idx = NULL; git_indexer_stats stats; int error; char *packname = NULL; - // Load the repository's configuration - error = git_repository_config(&cfg, repo, NULL, NULL); - if (error < GIT_SUCCESS) - return error; - // Get the remote and connect to it printf("Fetching %s\n", argv[1]); - error = git_remote_get(&remote, cfg, argv[1]); + error = git_remote_new(&remote, repo, argv[1], NULL); if (error < GIT_SUCCESS) return error; @@ -71,13 +48,6 @@ int fetch(git_repository *repo, int argc, char **argv) if (error < GIT_SUCCESS) return error; - // Perform the packfile negotiation. This is where the two ends - // figure out the minimal amount of data that should be transmitted - // to bring the repository up-to-date - error = git_remote_negotiate(remote); - if (error < GIT_SUCCESS) - return error; - // Download the packfile from the server. As we don't know its hash // yet, it will get a temporary filename error = git_remote_download(&packname, remote); diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 77a9f215d..02d432e8b 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -4,31 +4,22 @@ #include <string.h> #include "common.h" -static void show_refs(git_headarray *refs) +static int show_ref__cb(git_remote_head *head, void *payload) { - int i; - git_remote_head *head; - -// Take each head that the remote has advertised, store the string -// representation of the OID in a buffer and print it - - for(i = 0; i < refs->len; ++i){ - char oid[GIT_OID_HEXSZ + 1] = {0}; - head = refs->heads[i]; - git_oid_fmt(oid, &head->oid); - printf("%s\t%s\n", oid, head->name); - } + char oid[GIT_OID_HEXSZ + 1] = {0}; + git_oid_fmt(oid, &head->oid); + printf("%s\t%s\n", oid, head->name); + return GIT_SUCCESS; } int use_unnamed(git_repository *repo, const char *url) { git_remote *remote = NULL; - git_headarray refs; int error; // Create an instance of a remote from the URL. The transport to use // is detected from the URL - error = git_remote_new(&remote, repo, url); + error = git_remote_new(&remote, repo, url, NULL); if (error < GIT_SUCCESS) goto cleanup; @@ -39,32 +30,20 @@ int use_unnamed(git_repository *repo, const char *url) goto cleanup; // With git_remote_ls we can retrieve the advertised heads - error = git_remote_ls(remote, &refs); - if (error < GIT_SUCCESS) - goto cleanup; - - show_refs(&refs); + error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); - return error; } int use_remote(git_repository *repo, char *name) { git_remote *remote = NULL; - git_config *cfg = NULL; - git_headarray refs; int error; - // Load the local configuration for the repository - error = git_repository_config(&cfg, repo, NULL, NULL); - if (error < GIT_SUCCESS) - return error; - // Find the remote by name - error = git_remote_get(&remote, cfg, name); + error = git_remote_load(&remote, repo, name); if (error < GIT_SUCCESS) goto cleanup; @@ -72,15 +51,10 @@ int use_remote(git_repository *repo, char *name) if (error < GIT_SUCCESS) goto cleanup; - error = git_remote_ls(remote, &refs); - if (error < GIT_SUCCESS) - goto cleanup; - - show_refs(&refs); + error = git_remote_ls(remote, &show_ref__cb, NULL); cleanup: git_remote_free(remote); - return error; } @@ -89,8 +63,6 @@ cleanup: int ls_remote(git_repository *repo, int argc, char **argv) { - git_headarray heads; - git_remote_head *head; int error, i; /* If there's a ':' in the name, assume it's an URL */ diff --git a/include/git2.h b/include/git2.h index 14c090e39..73b23aa63 100644 --- a/include/git2.h +++ b/include/git2.h @@ -38,7 +38,6 @@ #include "git2/refspec.h" #include "git2/net.h" -#include "git2/transport.h" #include "git2/status.h" #include "git2/indexer.h" diff --git a/include/git2/blob.h b/include/git2/blob.h index b2a2b034a..8b9380d82 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -54,7 +54,7 @@ GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, co /** * Close an open blob * - * This is a wrapper around git_object_close() + * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop @@ -63,9 +63,9 @@ GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, co * @param blob the blob to close */ -GIT_INLINE(void) git_blob_close(git_blob *blob) +GIT_INLINE(void) git_blob_free(git_blob *blob) { - git_object_close((git_object *) blob); + git_object_free((git_object *) blob); } diff --git a/include/git2/commit.h b/include/git2/commit.h index 3c90e8007..4e91b34b9 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -56,7 +56,7 @@ GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *re /** * Close an open commit * - * This is a wrapper around git_object_close() + * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop @@ -65,9 +65,9 @@ GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *re * @param commit the commit to close */ -GIT_INLINE(void) git_commit_close(git_commit *commit) +GIT_INLINE(void) git_commit_free(git_commit *commit) { - git_object_close((git_object *) commit); + git_object_free((git_object *) commit); } /** diff --git a/include/git2/net.h b/include/git2/net.h index 5fb918599..08bc81f16 100644 --- a/include/git2/net.h +++ b/include/git2/net.h @@ -30,6 +30,7 @@ GIT_BEGIN_DECL #define GIT_DIR_FETCH 0 #define GIT_DIR_PUSH 1 + /** * Remote head description, given out on `ls` calls. */ @@ -41,12 +42,9 @@ struct git_remote_head { }; /** - * Array of remote heads + * Callback for listing the remote heads */ -struct git_headarray { - unsigned int len; - struct git_remote_head **heads; -}; +typedef int (*git_headlist_cb)(git_remote_head *, void *); /** @} */ GIT_END_DECL diff --git a/include/git2/object.h b/include/git2/object.h index d82a71c3c..86a0a585d 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -24,7 +24,7 @@ GIT_BEGIN_DECL * Lookup a reference to one of the objects in a repostory. * * The generated reference is owned by the repository and - * should be closed with the `git_object_close` method + * should be closed with the `git_object_free` method * instead of free'd manually. * * The 'type' parameter must match the type of the object @@ -56,7 +56,7 @@ GIT_EXTERN(int) git_object_lookup( * the prefix; otherwise the method will fail. * * The generated reference is owned by the repository and - * should be closed with the `git_object_close` method + * should be closed with the `git_object_free` method * instead of free'd manually. * * The 'type' parameter must match the type of the object @@ -123,7 +123,7 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); * * @param object the object to close */ -GIT_EXTERN(void) git_object_close(git_object *object); +GIT_EXTERN(void) git_object_free(git_object *object); /** * Convert an object type to it's string representation. diff --git a/include/git2/odb.h b/include/git2/odb.h index 27837418b..b144eca7d 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -92,7 +92,7 @@ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, in * * @param db database pointer to close. If NULL no action is taken. */ -GIT_EXTERN(void) git_odb_close(git_odb *db); +GIT_EXTERN(void) git_odb_free(git_odb *db); /** * Read an object from the database. @@ -282,7 +282,7 @@ GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_otype type) * * @param object object to close */ -GIT_EXTERN(void) git_odb_object_close(git_odb_object *object); +GIT_EXTERN(void) git_odb_object_free(git_odb_object *object); /** * Return the OID of an ODB object diff --git a/include/git2/remote.h b/include/git2/remote.h index 43bbe9e1c..0ae38165c 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -10,6 +10,8 @@ #include "common.h" #include "repository.h" #include "refspec.h" +#include "net.h" + /** * @file git2/remote.h * @brief Git remote management functions @@ -39,7 +41,7 @@ GIT_BEGIN_DECL * @param name the remote's name * @return GIT_SUCCESS or an error code */ -int git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name); +GIT_EXTERN(int) git_remote_new(git_remote **out, git_repository *repo, const char *url, const char *name); /** * Get the information for a particular remote @@ -49,7 +51,7 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons * @param name the remote's name * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_remote_get(struct git_remote **out, struct git_config *cfg, const char *name); +GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const char *name); /** * Get the remote's name @@ -57,7 +59,7 @@ GIT_EXTERN(int) git_remote_get(struct git_remote **out, struct git_config *cfg, * @param remote the remote * @return a pointer to the name */ -GIT_EXTERN(const char *) git_remote_name(struct git_remote *remote); +GIT_EXTERN(const char *) git_remote_name(git_remote *remote); /** * Get the remote's url @@ -65,7 +67,7 @@ GIT_EXTERN(const char *) git_remote_name(struct git_remote *remote); * @param remote the remote * @return a pointer to the url */ -GIT_EXTERN(const char *) git_remote_url(struct git_remote *remote); +GIT_EXTERN(const char *) git_remote_url(git_remote *remote); /** * Get the fetch refspec @@ -73,7 +75,7 @@ GIT_EXTERN(const char *) git_remote_url(struct git_remote *remote); * @param remote the remote * @return a pointer to the fetch refspec or NULL if it doesn't exist */ -GIT_EXTERN(const git_refspec *) git_remote_fetchspec(struct git_remote *remote); +GIT_EXTERN(const git_refspec *) git_remote_fetchspec(git_remote *remote); /** * Get the push refspec @@ -82,7 +84,7 @@ GIT_EXTERN(const git_refspec *) git_remote_fetchspec(struct git_remote *remote); * @return a pointer to the push refspec or NULL if it doesn't exist */ -GIT_EXTERN(const git_refspec *) git_remote_pushspec(struct git_remote *remote); +GIT_EXTERN(const git_refspec *) git_remote_pushspec(git_remote *remote); /** * Open a connection to a remote @@ -95,7 +97,7 @@ GIT_EXTERN(const git_refspec *) git_remote_pushspec(struct git_remote *remote); * @param direction whether you want to receive or send data * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction); +GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction); /** * Get a list of refs at the remote @@ -107,7 +109,7 @@ GIT_EXTERN(int) git_remote_connect(struct git_remote *remote, int direction); * @param remote the remote * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headarray *refs); +GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload); /** * Download the packfile @@ -149,7 +151,7 @@ GIT_EXTERN(void) git_remote_disconnect(git_remote *remote); * * @param remote the remote to free */ -GIT_EXTERN(void) git_remote_free(struct git_remote *remote); +GIT_EXTERN(void) git_remote_free(git_remote *remote); /** * Update the tips to the new state @@ -159,7 +161,15 @@ GIT_EXTERN(void) git_remote_free(struct git_remote *remote); * * @param remote the remote to update */ -GIT_EXTERN(int) git_remote_update_tips(struct git_remote *remote); +GIT_EXTERN(int) git_remote_update_tips(git_remote *remote); + +/** + * Return whether a string is a valid remote URL + * + * @param tranport the url to check + * @param 1 if the url is valid, 0 otherwise + */ +GIT_EXTERN(int) git_remote_valid_url(const char *url); /** @} */ GIT_END_DECL diff --git a/include/git2/repository.h b/include/git2/repository.h index 2e9baf6c0..4250ae161 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -23,21 +23,11 @@ GIT_BEGIN_DECL /** * Open a git repository. * - * The 'path' argument must point to an existing git repository - * folder, e.g. + * The 'path' argument must point to either a git repository + * folder, or an existing work dir. * - * /path/to/my_repo/.git/ (normal repository) - * objects/ - * index - * HEAD - * - * /path/to/bare_repo/ (bare repository) - * objects/ - * index - * HEAD - * - * The method will automatically detect if 'path' is a normal - * or bare repository or fail is 'path' is neither. + * The method will automatically detect if 'path' is a normal + * or bare repository or fail is 'path' is neither. * * @param repository pointer to the repo which will be opened * @param path the path to the repository @@ -45,137 +35,47 @@ GIT_BEGIN_DECL */ GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *path); - -/** - * Open a git repository by manually specifying all its paths - * - * @param repository pointer to the repo which will be opened - * - * @param git_dir The full path to the repository folder - * e.g. a '.git' folder for live repos, any folder for bare - * Equivalent to $GIT_DIR. - * Cannot be NULL. - * - * @param git_object_directory The full path to the ODB folder. - * the folder where all the loose and packed objects are stored - * Equivalent to $GIT_OBJECT_DIRECTORY. - * If NULL, "$GIT_DIR/objects/" is assumed. - * - * @param git_index_file The full path to the index (dircache) file - * Equivalent to $GIT_INDEX_FILE. - * If NULL, "$GIT_DIR/index" is assumed. - * - * @param git_work_tree The full path to the working tree of the repository, - * if the repository is not bare. - * Equivalent to $GIT_WORK_TREE. - * If NULL, the repository is assumed to be bare. - * - * @return GIT_SUCCESS or an error code - */ -GIT_EXTERN(int) git_repository_open2(git_repository **repository, - const char *git_dir, - const char *git_object_directory, - const char *git_index_file, - const char *git_work_tree); - - -/** - * Open a git repository by manually specifying its paths and - * the object database it will use. - * - * @param repository pointer to the repo which will be opened - * - * @param git_dir The full path to the repository folder - * e.g. a '.git' folder for live repos, any folder for bare - * Equivalent to $GIT_DIR. - * Cannot be NULL. - * - * @param object_database A pointer to a git_odb created & initialized - * by the user (e.g. with custom backends). This object database - * will be owned by the repository and will be automatically free'd. - * It should not be manually free'd by the user, or this - * git_repository object will become invalid. - * - * @param git_index_file The full path to the index (dircache) file - * Equivalent to $GIT_INDEX_FILE. - * If NULL, "$GIT_DIR/index" is assumed. - * - * @param git_work_tree The full path to the working tree of the repository, - * if the repository is not bare. - * Equivalent to $GIT_WORK_TREE. - * If NULL, the repository is assumed to be bare. - * - * @return GIT_SUCCESS or an error code - */ - -GIT_EXTERN(int) git_repository_open3(git_repository **repository, - const char *git_dir, - git_odb *object_database, - const char *git_index_file, - const char *git_work_tree); - /** - * Look for a git repository and copy its path in the given buffer. The lookup start - * from base_path and walk across parent directories if nothing has been found. The - * lookup ends when the first repository is found, or when reaching a directory - * referenced in ceiling_dirs or when the filesystem changes (in case across_fs - * is true). + * Look for a git repository and copy its path in the given buffer. + * The lookup start from base_path and walk across parent directories + * if nothing has been found. The lookup ends when the first repository + * is found, or when reaching a directory referenced in ceiling_dirs + * or when the filesystem changes (in case across_fs is true). * - * The method will automatically detect if the repository is bare (if there is - * a repository). + * The method will automatically detect if the repository is bare + * (if there is a repository). * - * @param repository_path The user allocated buffer which will contain the found path. + * @param repository_path The user allocated buffer which will + * contain the found path. * * @param size repository_path size * * @param start_path The base path where the lookup starts. * - * @param across_fs If true, then the lookup will not stop when a filesystem device change - * is detected while exploring parent directories. + * @param across_fs If true, then the lookup will not stop when a + * filesystem device change is detected while exploring parent directories. * - * @param ceiling_dirs A GIT_PATH_LIST_SEPARATOR separated list of absolute symbolic link - * free paths. The lookup will stop when any of this paths is reached. Note that the - * lookup always performs on start_path no matter start_path appears in ceiling_dirs - * ceiling_dirs might be NULL (which is equivalent to an empty string) + * @param ceiling_dirs A GIT_PATH_LIST_SEPARATOR separated list of + * absolute symbolic link free paths. The lookup will stop when any + * of this paths is reached. Note that the lookup always performs on + * start_path no matter start_path appears in ceiling_dirs ceiling_dirs + * might be NULL (which is equivalent to an empty string) * * @return GIT_SUCCESS or an error code */ -GIT_EXTERN(int) git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs); - -/** - * Get the object database behind a Git repository - * - * @param repo a repository object - * @return a pointer to the object db - */ -GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo); - -/** - * Open the Index file of a Git repository - * - * This returns a new and unique `git_index` object representing the - * active index for the repository. - * - * This method may be called more than once (e.g. on different threads). - * - * Each returned `git_index` object is independent and suffers no race - * conditions: synchronization is done at the FS level. - * - * Each returned `git_index` object must be manually freed by the user, - * using `git_index_free`. - * - * @param index Pointer where to store the index - * @param repo a repository object - * @return GIT_SUCCESS or an error code - */ -GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo); +GIT_EXTERN(int) git_repository_discover( + char *repository_path, + size_t size, + const char *start_path, + int across_fs, + const char *ceiling_dirs); /** * Free a previously allocated repository * * Note that after a repository is free'd, all the objects it has spawned * will still exist until they are manually closed by the user - * with `git_object_close`, but accessing any of the attributes of + * with `git_object_free`, but accessing any of the attributes of * an object without a backing repository will result in undefined * behavior * @@ -188,7 +88,6 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); * * TODO: * - Reinit the repository - * - Create config files * * @param repo_out pointer to the repo which will be created or reinitialized * @param path the path to the repository @@ -247,31 +146,43 @@ GIT_EXTERN(int) git_repository_head_orphan(git_repository *repo); GIT_EXTERN(int) git_repository_is_empty(git_repository *repo); /** - * Internal path identifiers for a repository + * Get the path of this repository + * + * This is the path of the `.git` folder for normal repositories, + * or of the repository itself for bare repositories. + * + * @param repo A repository object + * @return the path to the repository + */ +GIT_EXTERN(const char *) git_repository_path(git_repository *repo); + +/** + * Get the path of the working directory for this repository + * + * If the repository is bare, this function will always return + * NULL. + * + * @param repo A repository object + * @return the path to the working dir, if it exists */ -typedef enum { - GIT_REPO_PATH, - GIT_REPO_PATH_INDEX, - GIT_REPO_PATH_ODB, - GIT_REPO_PATH_WORKDIR -} git_repository_pathid; +GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); /** - * Get one of the paths to the repository + * Set the path to the working directory for this repository * - * Possible values for `id`: + * The working directory doesn't need to be the same one + * that contains the `.git` folder for this repository. * - * GIT_REPO_PATH: return the path to the repository - * GIT_REPO_PATH_INDEX: return the path to the index - * GIT_REPO_PATH_ODB: return the path to the ODB - * GIT_REPO_PATH_WORKDIR: return the path to the working - * directory + * If this repository is bare, setting its working directory + * will turn it into a normal repository, capable of performing + * all the common workdir operations (checkout, status, index + * manipulation, etc). * - * @param repo a repository object - * @param id The ID of the path to return - * @return absolute path of the requested id + * @param repo A repository object + * @param workdir The path to a working directory + * @return GIT_SUCCESS, or an error code */ -GIT_EXTERN(const char *) git_repository_path(git_repository *repo, git_repository_pathid id); +GIT_EXTERN(int) git_repository_set_workdir(git_repository *repo, const char *workdir); /** * Check if a repository is bare @@ -282,52 +193,97 @@ GIT_EXTERN(const char *) git_repository_path(git_repository *repo, git_repositor GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); /** - * Retrieve the relevant configuration for a repository + * Get the configuration file for this repository. * - * If either the `global_config_path` or `system_config_path` - * variables are not NULL, the given config files will be also - * included in the configuration set. The global configuration file is - * located in $HOME/.gitconfig. On most UNIX systems, the system - * config file file may be found on `$sysconfdir/gitconfig`. + * If a configuration file has not been set, the default + * config set for the repository will be returned, including + * global and system configurations (if they are available). * - * The resulting `git_config` instance will query the files in the following - * order: + * The configuration file must be freed once it's no longer + * being used by the user. * - * - Repository configuration file - * - Global configuration file - * - System configuration file + * @param out Pointer to store the loaded config file + * @param repo A repository object + * @return GIT_SUCCESS, or an error code + */ +GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); + +/** + * Set the configuration file for this repository * - * The method will fail if any of the given config files can't be - * found or accessed. + * This configuration file will be used for all configuration + * queries involving this repository. * - * The returned `git_config` instance is owned by the caller and must - * be manually free'd once it's no longer on use. + * The repository will keep a reference to the config file; + * the user must still free the config after setting it + * to the repository, or it will leak. * - * @param out the repository's configuration - * @param repo the repository for which to get the config - * @param system_config_path Path to the global config file - * @param system_config_path Path to the system-wide config file + * @param repo A repository object + * @param config A Config object */ +GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *config); -GIT_EXTERN(int) git_repository_config(git_config **out, - git_repository *repo, - const char *global_config_path, - const char *system_config_path); +/** + * Get the Object Database for this repository. + * + * If a custom ODB has not been set, the default + * database for the repository will be returned (the one + * located in `.git/objects`). + * + * The ODB must be freed once it's no longer being used by + * the user. + * + * @param out Pointer to store the loaded ODB + * @param repo A repository object + * @return GIT_SUCCESS, or an error code + */ +GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); /** - * Automatically load the configuration files + * Set the Object Database for this repository + * + * The ODB will be used for all object-related operations + * involving this repository. + * + * The repository will keep a reference to the ODB; the user + * must still free the ODB object after setting it to the + * repository, or it will leak. + * + * @param repo A repository object + * @param odb An ODB object + */ +GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); + +/** + * Get the Index file for this repository. + * + * If a custom index has not been set, the default + * index for the repository will be returned (the one + * located in `.git/index`). + * + * The index must be freed once it's no longer being used by + * the user. + * + * @param out Pointer to store the loaded index + * @param repo A repository object + * @return GIT_SUCCESS, or an error code + */ +GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); + +/** + * Set the index file for this repository + * + * This index will be used for all index-related operations + * involving this repository. * - * A wrapper around `git_repository_config` that tries to guess where - * the global and system config files are located. No error is - * reported if either of these files are missing at the guessed - * locations. + * The repository will keep a reference to the index file; + * the user must still free the index after setting it + * to the repository, or it will leak. * - * @param out the repository's configuration - * @param repo the repository for which to get the config + * @param repo A repository object + * @param index An index object */ -GIT_EXTERN(int) git_repository_config_autoload( - git_config **out, - git_repository *repo); +GIT_EXTERN(void) git_repository_set_index(git_repository *repo, git_index *index); /** @} */ GIT_END_DECL diff --git a/include/git2/tag.h b/include/git2/tag.h index 63a522882..be49621e9 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -54,7 +54,7 @@ GIT_INLINE(int) git_tag_lookup_prefix(git_tag **tag, git_repository *repo, const /** * Close an open tag * - * This is a wrapper around git_object_close() + * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop @@ -63,9 +63,9 @@ GIT_INLINE(int) git_tag_lookup_prefix(git_tag **tag, git_repository *repo, const * @param tag the tag to close */ -GIT_INLINE(void) git_tag_close(git_tag *tag) +GIT_INLINE(void) git_tag_free(git_tag *tag) { - git_object_close((git_object *) tag); + git_object_free((git_object *) tag); } diff --git a/include/git2/transport.h b/include/git2/transport.h deleted file mode 100644 index f56a2f40a..000000000 --- a/include/git2/transport.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (C) 2009-2011 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_transport_h__ -#define INCLUDE_git_transport_h__ - -#include "common.h" -#include "types.h" -#include "net.h" - -/** - * @file git2/transport.h - * @brief Git protocol transport abstraction - * @defgroup git_transport Git protocol transport abstraction - * @ingroup Git - * @{ - */ -GIT_BEGIN_DECL - -/** - * Get the appropriate transport for an URL. - * @param tranport the transport for the url - * @param url the url of the repo - */ -GIT_EXTERN(int) git_transport_new(git_transport **transport, const char *url); - -/** - * Return whether a string is a valid transport URL - * - * @param tranport the url to check - * @param 1 if the url is valid, 0 otherwise - */ -GIT_EXTERN(int) git_transport_valid_url(const char *url); - -/** @} */ -GIT_END_DECL -#endif diff --git a/include/git2/tree.h b/include/git2/tree.h index 8ac8b1682..fefd4c6c3 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -54,7 +54,7 @@ GIT_INLINE(int) git_tree_lookup_prefix(git_tree **tree, git_repository *repo, co /** * Close an open tree * - * This is a wrapper around git_object_close() + * This is a wrapper around git_object_free() * * IMPORTANT: * It *is* necessary to call this method when you stop @@ -63,9 +63,9 @@ GIT_INLINE(int) git_tree_lookup_prefix(git_tree **tree, git_repository *repo, co * @param tree the tree to close */ -GIT_INLINE(void) git_tree_close(git_tree *tree) +GIT_INLINE(void) git_tree_free(git_tree *tree) { - git_object_close((git_object *) tree); + git_object_free((git_object *) tree); } @@ -273,7 +273,7 @@ GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_tr * relative path. * * The returned tree is owned by the repository and - * should be closed with the `git_object_close` method. + * should be closed with the `git_object_free` method. * * @param subtree Pointer where to store the subtree * @param root A previously loaded tree which will be the root of the relative path diff --git a/include/git2/types.h b/include/git2/types.h index 1df18974a..ea97ee915 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -161,13 +161,7 @@ typedef enum { typedef struct git_refspec git_refspec; typedef struct git_remote git_remote; -/** A transport to use */ -typedef struct git_transport git_transport; - -typedef int (*git_transport_cb)(git_transport **transport); - typedef struct git_remote_head git_remote_head; -typedef struct git_headarray git_headarray; /** @} */ GIT_END_DECL diff --git a/src/blob.c b/src/blob.c index f13a5be15..87f5686af 100644 --- a/src/blob.c +++ b/src/blob.c @@ -26,7 +26,7 @@ size_t git_blob_rawsize(git_blob *blob) void git_blob__free(git_blob *blob) { - git_odb_object_close(blob->odb_object); + git_odb_object_free(blob->odb_object); git__free(blob); } @@ -41,9 +41,14 @@ int git_blob__parse(git_blob *blob, git_odb_object *odb_obj) int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len) { int error; + git_odb *odb; git_odb_stream *stream; - if ((error = git_odb_open_wstream(&stream, repo->db, len, GIT_OBJ_BLOB)) < GIT_SUCCESS) + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + return error; + + if ((error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < GIT_SUCCESS) return git__rethrow(error, "Failed to create blob"); if ((error = stream->write(stream, buffer, len)) < GIT_SUCCESS) { @@ -69,11 +74,14 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat git_off_t size; git_odb_stream *stream; struct stat st; + const char *workdir; + git_odb *odb; - if (repo->path_workdir == NULL) + workdir = git_repository_workdir(repo); + if (workdir == NULL) return git__throw(GIT_ENOTFOUND, "Failed to create blob. (No working directory found)"); - git_path_join(full_path, repo->path_workdir, path); + git_path_join(full_path, workdir, path); error = p_lstat(full_path, &st); if (error < 0) { @@ -83,11 +91,16 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat islnk = S_ISLNK(st.st_mode); size = st.st_size; - if (!islnk) + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + return error; + + if (!islnk) { if ((fd = p_open(full_path, O_RDONLY)) < 0) return git__throw(GIT_ENOTFOUND, "Failed to create blob. Could not open '%s'", full_path); + } - if ((error = git_odb_open_wstream(&stream, repo->db, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) { + if ((error = git_odb_open_wstream(&stream, odb, (size_t)size, GIT_OBJ_BLOB)) < GIT_SUCCESS) { if (!islnk) p_close(fd); return git__rethrow(error, "Failed to create blob"); diff --git a/src/commit.c b/src/commit.c index 83bc9fc4c..bf6ca7855 100644 --- a/src/commit.c +++ b/src/commit.c @@ -103,6 +103,7 @@ int git_commit_create( { git_buf commit = GIT_BUF_INIT; int error, i; + git_odb *odb; if (git_object_owner((const git_object *)tree) != repo) return git__throw(GIT_EINVALIDARGS, "The given tree does not belong to this repository"); @@ -132,7 +133,11 @@ int git_commit_create( goto cleanup; } - error = git_odb_write(oid, git_repository_database(repo), commit.ptr, commit.size, GIT_OBJ_COMMIT); + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + goto cleanup; + + error = git_odb_write(oid, odb, commit.ptr, commit.size, GIT_OBJ_COMMIT); git_buf_free(&commit); if (error == GIT_SUCCESS && update_ref != NULL) { diff --git a/src/common.h b/src/common.h index 727a08e77..35316012d 100644 --- a/src/common.h +++ b/src/common.h @@ -60,4 +60,5 @@ extern void git___rethrow(const char *, ...) GIT_FORMAT_PRINTF(1, 2); #include "util.h" + #endif /* INCLUDE_common_h__ */ diff --git a/src/config.c b/src/config.c index 4e48ff7f4..a8e15405b 100644 --- a/src/config.c +++ b/src/config.c @@ -22,15 +22,12 @@ typedef struct { int priority; } file_internal; -void git_config_free(git_config *cfg) +static void config_free(git_config *cfg) { unsigned int i; git_config_file *file; file_internal *internal; - if (cfg == NULL) - return; - for(i = 0; i < cfg->files.length; ++i){ internal = git_vector_get(&cfg->files, i); file = internal->file; @@ -42,6 +39,14 @@ void git_config_free(git_config *cfg) git__free(cfg); } +void git_config_free(git_config *cfg) +{ + if (cfg == NULL) + return; + + GIT_REFCOUNT_DEC(cfg, config_free); +} + static int config_backend_cmp(const void *a, const void *b) { const file_internal *bk_a = (const file_internal *)(a); @@ -66,7 +71,7 @@ int git_config_new(git_config **out) } *out = cfg; - + GIT_REFCOUNT_INC(cfg); return GIT_SUCCESS; } diff --git a/src/config.h b/src/config.h index 43574a586..7f3494edc 100644 --- a/src/config.h +++ b/src/config.h @@ -17,8 +17,8 @@ #define GIT_CONFIG_FILE_MODE 0666 struct git_config { + git_refcount rc; git_vector files; - git_repository *repo; }; #endif diff --git a/src/config_file.c b/src/config_file.c index 5e862d487..7a5865210 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -256,6 +256,7 @@ static int config_open(git_config_file *cfg) diskfile_backend *b = (diskfile_backend *)cfg; error = git_futils_readbuffer(&b->reader.buffer, b->file_path); + /* It's fine if the file doesn't exist */ if (error == GIT_ENOTFOUND) return GIT_SUCCESS; @@ -269,7 +270,7 @@ static int config_open(git_config_file *cfg) git_futils_freebuffer(&b->reader.buffer); - return error; + return GIT_SUCCESS; cleanup: cvar_list_free(&b->var_list); diff --git a/src/fetch.c b/src/fetch.c index a42732925..f447248c5 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -18,83 +18,62 @@ #include "fetch.h" #include "netops.h" -static int filter_wants(git_remote *remote) -{ - git_vector list; - git_headarray refs; - git_remote_head *head; - git_transport *t = remote->transport; - git_repository *repo = remote->repo; +struct filter_payload { + git_remote *remote; const git_refspec *spec; - int error; - unsigned int i = 0; + git_odb *odb; + int found_head; +}; - error = git_vector_init(&list, 16, NULL); - if (error < GIT_SUCCESS) - return error; +static int filter_ref__cb(git_remote_head *head, void *payload) +{ + struct filter_payload *p = payload; + int error; - error = t->ls(t, &refs); - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to get remote ref list"); - goto cleanup; - } + if (!p->found_head && strcmp(head->name, GIT_HEAD_FILE) == 0) { + p->found_head = 1; + } else { + /* If it doesn't match the refpec, we don't want it */ + error = git_refspec_src_match(p->spec, head->name); - /* - * The fetch refspec can be NULL, and what this means is that the - * user didn't specify one. This is fine, as it means that we're - * not interested in any particular branch but just the remote's - * HEAD, which will be stored in FETCH_HEAD after the fetch. - */ - spec = git_remote_fetchspec(remote); + if (error == GIT_ENOMATCH) + return GIT_SUCCESS; - /* - * We need to handle HEAD separately, as we always want it, but it - * probably won't matcht he refspec. - */ - head = refs.heads[0]; - if (refs.len > 0 && !strcmp(head->name, GIT_HEAD_FILE)) { - if (git_odb_exists(repo->db, &head->oid)) - head->local = 1; - else - remote->need_pack = 1; - - i = 1; - error = git_vector_insert(&list, refs.heads[0]); if (error < GIT_SUCCESS) - goto cleanup; + return git__rethrow(error, "Error matching remote ref name"); } - for (; i < refs.len; ++i) { - head = refs.heads[i]; + /* If we have the object, mark it so we don't ask for it */ + if (git_odb_exists(p->odb, &head->oid)) + head->local = 1; + else + p->remote->need_pack = 1; - /* If it doesn't match the refpec, we don't want it */ - error = git_refspec_src_match(spec, head->name); - if (error == GIT_ENOMATCH) - continue; - if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Error matching remote ref name"); - goto cleanup; - } + return git_vector_insert(&p->remote->refs, head); +} - /* If we have the object, mark it so we don't ask for it */ - if (git_odb_exists(repo->db, &head->oid)) - head->local = 1; - else - remote->need_pack = 1; +static int filter_wants(git_remote *remote) +{ + int error; + struct filter_payload p; - error = git_vector_insert(&list, head); - if (error < GIT_SUCCESS) - goto cleanup; - } + git_vector_clear(&remote->refs); - remote->refs.len = list.length; - remote->refs.heads = (git_remote_head **) list.contents; + /* + * The fetch refspec can be NULL, and what this means is that the + * user didn't specify one. This is fine, as it means that we're + * not interested in any particular branch but just the remote's + * HEAD, which will be stored in FETCH_HEAD after the fetch. + */ + p.spec = git_remote_fetchspec(remote); + p.found_head = 0; + p.remote = remote; - return GIT_SUCCESS; + error = git_repository_odb__weakptr(&p.odb, remote->repo); + if (error < GIT_SUCCESS) + return error; -cleanup: - git_vector_free(&list); - return error; + return remote->transport->ls(remote->transport, &filter_ref__cb, &p); } /* @@ -112,8 +91,9 @@ int git_fetch_negotiate(git_remote *remote) return git__rethrow(error, "Failed to filter the reference list for wants"); /* Don't try to negotiate when we don't want anything */ - if (remote->refs.len == 0) + if (remote->refs.length == 0) return GIT_SUCCESS; + if (!remote->need_pack) return GIT_SUCCESS; diff --git a/src/index.c b/src/index.c index aad117164..d01262b39 100644 --- a/src/index.c +++ b/src/index.c @@ -31,6 +31,8 @@ static const unsigned int INDEX_HEADER_SIG = 0x44495243; static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; static const char INDEX_EXT_UNMERGED_SIG[] = {'R', 'E', 'U', 'C'}; +#define INDEX_OWNER(idx) ((git_repository *)(GIT_REFCOUNT_OWNER(idx))) + struct index_header { uint32_t signature; uint32_t version; @@ -124,7 +126,7 @@ static unsigned int index_create_mode(unsigned int mode) return S_IFREG | ((mode & 0100) ? 0755 : 0644); } -static int index_initialize(git_index **index_out, git_repository *owner, const char *index_path) +int git_index_open(git_index **index_out, const char *index_path) { git_index *index; @@ -142,8 +144,6 @@ static int index_initialize(git_index **index_out, git_repository *owner, const return GIT_ENOMEM; } - index->repository = owner; - git_vector_init(&index->entries, 32, index_cmp); /* Check if index file is stored on disk already */ @@ -151,23 +151,18 @@ static int index_initialize(git_index **index_out, git_repository *owner, const index->on_disk = 1; *index_out = index; + GIT_REFCOUNT_INC(index); return git_index_read(index); } -int git_index_open(git_index **index_out, const char *index_path) +static void index_free(git_index *index) { - return index_initialize(index_out, NULL, index_path); -} - -/* - * Moved from `repository.c` - */ -int git_repository_index(git_index **index_out, git_repository *repo) -{ - if (repo->is_bare) - return git__throw(GIT_EBAREINDEX, "Failed to open index. Repository is bare"); + git_index_clear(index); + git_vector_free(&index->entries); + git_vector_free(&index->unmerged); - return index_initialize(index_out, repo, repo->path_index); + git__free(index->index_file_path); + git__free(index); } void git_index_free(git_index *index) @@ -175,12 +170,7 @@ void git_index_free(git_index *index) if (index == NULL) return; - git_index_clear(index); - git_vector_free(&index->entries); - git_vector_free(&index->unmerged); - - git__free(index->index_file_path); - git__free(index); + GIT_REFCOUNT_DEC(index, index_free); } void git_index_clear(git_index *index) @@ -298,20 +288,29 @@ static int index_entry_init(git_index_entry **entry_out, git_index *index, const struct stat st; git_oid oid; int error; + const char *workdir; + + if (INDEX_OWNER(index) == NULL) + return git__throw(GIT_EBAREINDEX, + "Failed to initialize entry. Repository is bare"); - if (index->repository == NULL) - return git__throw(GIT_EBAREINDEX, "Failed to initialize entry. Repository is bare"); + workdir = git_repository_workdir(INDEX_OWNER(index)); + if (workdir == NULL) + return git__throw(GIT_EBAREINDEX, + "Failed to initialize entry. Cannot resolved workdir"); - git_path_join(full_path, index->repository->path_workdir, rel_path); + git_path_join(full_path, workdir, rel_path); if (p_lstat(full_path, &st) < 0) - return git__throw(GIT_ENOTFOUND, "Failed to initialize entry. '%s' cannot be opened", full_path); + return git__throw(GIT_ENOTFOUND, + "Failed to initialize entry. '%s' cannot be opened", full_path); if (stage < 0 || stage > 3) - return git__throw(GIT_ERROR, "Failed to initialize entry. Invalid stage %i", stage); + return git__throw(GIT_ERROR, + "Failed to initialize entry. Invalid stage %i", stage); /* write the blob to disk and get the oid */ - if ((error = git_blob_create_fromfile(&oid, index->repository, rel_path)) < GIT_SUCCESS) + if ((error = git_blob_create_fromfile(&oid, INDEX_OWNER(index), rel_path)) < GIT_SUCCESS) return git__rethrow(error, "Failed to initialize index entry"); entry = git__malloc(sizeof(git_index_entry)); diff --git a/src/index.h b/src/index.h index a1cd3403e..9464afb6c 100644 --- a/src/index.h +++ b/src/index.h @@ -18,7 +18,8 @@ #define GIT_INDEX_FILE_MODE 0666 struct git_index { - git_repository *repository; + git_refcount rc; + char *index_file_path; time_t last_modified; diff --git a/src/object.c b/src/object.c index c84e94b05..95c7cf9d2 100644 --- a/src/object.c +++ b/src/object.c @@ -77,9 +77,15 @@ static int create_object(git_object **object_out, git_otype type) return GIT_SUCCESS; } -int git_object_lookup_prefix(git_object **object_out, git_repository *repo, const git_oid *id, unsigned int len, git_otype type) +int git_object_lookup_prefix( + git_object **object_out, + git_repository *repo, + const git_oid *id, + unsigned int len, + git_otype type) { git_object *object = NULL; + git_odb *odb = NULL; git_odb_object *odb_obj; int error = GIT_SUCCESS; @@ -89,6 +95,10 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons return git__throw(GIT_EAMBIGUOUSOIDPREFIX, "Failed to lookup object. Prefix length is lower than %d.", GIT_OID_MINPREFIXLEN); + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + return error; + if (len > GIT_OID_HEXSZ) len = GIT_OID_HEXSZ; @@ -98,10 +108,11 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons */ object = git_cache_get(&repo->objects, id); if (object != NULL) { - if (type != GIT_OBJ_ANY && type != object->type) - { - git_object_close(object); - return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB"); + if (type != GIT_OBJ_ANY && type != object->type) { + git_object_free(object); + return git__throw(GIT_EINVALIDTYPE, + "Failed to lookup object. " + "The given type does not match the type on the ODB"); } *object_out = object; @@ -113,7 +124,7 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons * it is the same cost for packed and loose object backends, * but it may be much more costly for sqlite and hiredis. */ - error = git_odb_read(&odb_obj, repo->db, id); + error = git_odb_read(&odb_obj, odb, id); } else { git_oid short_oid; @@ -133,14 +144,14 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons * - We never explore the cache, go right to exploring the backends * We chose the latter : we explore directly the backends. */ - error = git_odb_read_prefix(&odb_obj, repo->db, &short_oid, len); + error = git_odb_read_prefix(&odb_obj, odb, &short_oid, len); } if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to lookup object"); if (type != GIT_OBJ_ANY && type != odb_obj->raw.type) { - git_odb_object_close(odb_obj); + git_odb_object_free(odb_obj); return git__throw(GIT_EINVALIDTYPE, "Failed to lookup object. The given type does not match the type on the ODB"); } @@ -174,7 +185,7 @@ int git_object_lookup_prefix(git_object **object_out, git_repository *repo, cons break; } - git_odb_object_close(odb_obj); + git_odb_object_free(odb_obj); if (error < GIT_SUCCESS) { git_object__free(object); @@ -218,7 +229,7 @@ void git_object__free(void *_obj) } } -void git_object_close(git_object *object) +void git_object_free(git_object *object) { if (object == NULL) return; @@ -108,7 +108,7 @@ git_otype git_odb_object_type(git_odb_object *object) return object->raw.type; } -void git_odb_object_close(git_odb_object *object) +void git_odb_object_free(git_odb_object *object) { git_cached_obj_decref((git_cached_obj *)object, &free_odb_object); } @@ -275,6 +275,7 @@ int git_odb_new(git_odb **out) } *out = db; + GIT_REFCOUNT_INC(db); return GIT_SUCCESS; } @@ -405,17 +406,14 @@ int git_odb_open(git_odb **out, const char *objects_dir) return GIT_SUCCESS; cleanup: - git_odb_close(db); + git_odb_free(db); return error; /* error already set - pass through */ } -void git_odb_close(git_odb *db) +static void odb_free(git_odb *db) { unsigned int i; - if (db == NULL) - return; - for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *backend = internal->backend; @@ -431,6 +429,14 @@ void git_odb_close(git_odb *db) git__free(db); } +void git_odb_free(git_odb *db) +{ + if (db == NULL) + return; + + GIT_REFCOUNT_DEC(db, odb_free); +} + int git_odb_exists(git_odb *db, const git_oid *id) { git_odb_object *object; @@ -440,7 +446,7 @@ int git_odb_exists(git_odb *db, const git_oid *id) assert(db && id); if ((object = git_cache_get(&db->cache, id)) != NULL) { - git_odb_object_close(object); + git_odb_object_free(object); return 1; } @@ -466,7 +472,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git if ((object = git_cache_get(&db->cache, id)) != NULL) { *len_p = object->raw.len; *type_p = object->raw.type; - git_odb_object_close(object); + git_odb_object_free(object); return GIT_SUCCESS; } @@ -491,7 +497,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git *len_p = object->raw.len; *type_p = object->raw.type; - git_odb_object_close(object); + git_odb_object_free(object); } return GIT_SUCCESS; @@ -33,7 +33,7 @@ struct git_odb_object { /* EXPORT */ struct git_odb { - void *_internal; + git_refcount rc; git_vector backends; git_cache cache; }; @@ -316,30 +316,30 @@ static int send_want_with_caps(git_remote_head *head, git_transport_caps *caps, * is overwrite the OID each time. */ -int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf) +int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf) { unsigned int i = 0; int error; git_remote_head *head; if (caps->common) { - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (!head->local) break; } - error = buffer_want_with_caps(refs->heads[i], caps, buf); + error = buffer_want_with_caps(refs->contents[i], caps, buf); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to buffer want with caps"); i++; } - for (; i < refs->len; ++i) { + for (; i < refs->length; ++i) { char oid[GIT_OID_HEXSZ]; - head = refs->heads[i]; + head = refs->contents[i]; if (head->local) continue; @@ -352,7 +352,7 @@ int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf return git_pkt_buffer_flush(buf); } -int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) +int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd) { unsigned int i = 0; int error = GIT_SUCCESS; @@ -365,15 +365,15 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) /* If there are common caps, find the first one */ if (caps->common) { - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (head->local) continue; else break; } - error = send_want_with_caps(refs->heads[i], caps, fd); + error = send_want_with_caps(refs->contents[i], caps, fd); if (error < GIT_SUCCESS) return git__rethrow(error, "Failed to send want pkt with caps"); /* Increase it here so it's correct whether we run this or not */ @@ -381,8 +381,8 @@ int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd) } /* Continue from where we left off */ - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; if (head->local) continue; @@ -68,8 +68,8 @@ int git_pkt_buffer_flush(git_buf *buf); int git_pkt_send_flush(int s); int git_pkt_buffer_done(git_buf *buf); int git_pkt_send_done(int s); -int git_pkt_buffer_wants(git_headarray *refs, git_transport_caps *caps, git_buf *buf); -int git_pkt_send_wants(git_headarray *refs, git_transport_caps *caps, int fd); +int git_pkt_buffer_wants(const git_vector *refs, git_transport_caps *caps, git_buf *buf); +int git_pkt_send_wants(const git_vector *refs, git_transport_caps *caps, int fd); int git_pkt_buffer_have(git_oid *oid, git_buf *buf); int git_pkt_send_have(git_oid *oid, int fd); void git_pkt_free(git_pkt *pkt); diff --git a/src/refs.c b/src/refs.c index 2374cc72f..8931d5bac 100644 --- a/src/refs.c +++ b/src/refs.c @@ -686,7 +686,7 @@ static int packed_find_peel(git_repository *repo, struct packref *ref) */ } - git_object_close(object); + git_object_free(object); return GIT_SUCCESS; } @@ -1195,7 +1195,8 @@ cleanup: */ int git_reference_set_oid(git_reference *ref, const git_oid *id) { - int error = GIT_SUCCESS; + int error = GIT_SUCCESS, exists; + git_odb *odb = NULL; if ((ref->flags & GIT_REF_OID) == 0) return git__throw(GIT_EINVALIDREFSTATE, @@ -1203,23 +1204,29 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id) assert(ref->owner); + error = git_repository_odb__weakptr(&odb, ref->owner); + if (error < GIT_SUCCESS) + return error; + + exists = git_odb_exists(odb, id); + + git_odb_free(odb); + /* Don't let the user create references to OIDs that * don't exist in the ODB */ - if (!git_odb_exists(git_repository_database(ref->owner), id)) + if (!exists) return git__throw(GIT_ENOTFOUND, "Failed to set OID target of reference. OID doesn't exist in ODB"); /* Update the OID value on `ref` */ git_oid_cpy(&ref->target.oid, id); + /* Write back to disk */ error = loose_write(ref); if (error < GIT_SUCCESS) - goto cleanup; + return git__rethrow(error, "Failed to set OID target of reference"); return GIT_SUCCESS; - -cleanup: - return git__rethrow(error, "Failed to set OID target of reference"); } /* diff --git a/src/remote.c b/src/remote.c index a222023d8..75e861681 100644 --- a/src/remote.c +++ b/src/remote.c @@ -70,16 +70,21 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons memset(remote, 0x0, sizeof(git_remote)); remote->repo = repo; + if (git_vector_init(&remote->refs, 32, NULL) < 0) { + git_remote_free(remote); + return GIT_ENOMEM; + } + remote->url = git__strdup(url); if (remote->url == NULL) { - git__free(remote); + git_remote_free(remote); return GIT_ENOMEM; } if (name != NULL) { remote->name = git__strdup(name); if (remote->name == NULL) { - git__free(remote); + git_remote_free(remote); return GIT_ENOMEM; } } @@ -88,14 +93,19 @@ int git_remote_new(git_remote **out, git_repository *repo, const char *url, cons return GIT_SUCCESS; } -int git_remote_get(git_remote **out, git_config *cfg, const char *name) +int git_remote_load(git_remote **out, git_repository *repo, const char *name) { git_remote *remote; char *buf = NULL; const char *val; int ret, error, buf_len; + git_config *config; - assert(out && cfg && name); + assert(out && repo && name); + + error = git_repository_config__weakptr(&config, repo); + if (error < GIT_SUCCESS) + return error; remote = git__malloc(sizeof(git_remote)); if (remote == NULL) @@ -108,6 +118,11 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) goto cleanup; } + if (git_vector_init(&remote->refs, 32, NULL) < 0) { + error = GIT_ENOMEM; + goto cleanup; + } + /* "fetch" is the longest var name we're interested in */ buf_len = strlen("remote.") + strlen(".fetch") + strlen(name) + 1; buf = git__malloc(buf_len); @@ -122,13 +137,13 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) goto cleanup; } - error = git_config_get_string(cfg, buf, &val); + error = git_config_get_string(config, buf, &val); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Remote's url doesn't exist"); goto cleanup; } - remote->repo = cfg->repo; + remote->repo = repo; remote->url = git__strdup(val); if (remote->url == NULL) { error = GIT_ENOMEM; @@ -141,7 +156,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) goto cleanup; } - error = parse_remote_refspec(cfg, &remote->fetch, buf); + error = parse_remote_refspec(config, &remote->fetch, buf); if (error < GIT_SUCCESS) { error = git__rethrow(error, "Failed to get fetch refspec"); goto cleanup; @@ -153,7 +168,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) goto cleanup; } - error = parse_remote_refspec(cfg, &remote->push, buf); + error = parse_remote_refspec(config, &remote->push, buf); /* Not finding push is fine */ if (error == GIT_ENOTFOUND) error = GIT_SUCCESS; @@ -165,6 +180,7 @@ int git_remote_get(git_remote **out, git_config *cfg, const char *name) cleanup: git__free(buf); + if (error < GIT_SUCCESS) git_remote_free(remote); @@ -221,10 +237,14 @@ cleanup: return error; } -int git_remote_ls(git_remote *remote, git_headarray *refs) +int git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload) { - assert(remote && refs); - return remote->transport->ls(remote->transport, refs); + assert(remote); + + if (!remote->transport) + return git__throw(GIT_ERROR, "The remote is not connected"); + + return remote->transport->ls(remote->transport, list_cb, payload); } int git_remote_download(char **filename, git_remote *remote) @@ -244,7 +264,7 @@ int git_remote_update_tips(git_remote *remote) int error = GIT_SUCCESS; unsigned int i = 0; char refname[GIT_PATH_MAX]; - git_headarray *refs = &remote->refs; + git_vector *refs = &remote->refs; git_remote_head *head; git_reference *ref; struct git_refspec *spec = &remote->fetch; @@ -253,11 +273,11 @@ int git_remote_update_tips(git_remote *remote) memset(refname, 0x0, sizeof(refname)); - if (refs->len == 0) + if (refs->length == 0) return GIT_SUCCESS; /* HEAD is only allowed to be the first in the list */ - head = refs->heads[0]; + head = refs->contents[0]; if (!strcmp(head->name, GIT_HEAD_FILE)) { error = git_reference_create_oid(&ref, remote->repo, GIT_FETCH_HEAD_FILE, &head->oid, 1); i = 1; @@ -266,8 +286,8 @@ int git_remote_update_tips(git_remote *remote) return git__rethrow(error, "Failed to update FETCH_HEAD"); } - for (; i < refs->len; ++i) { - head = refs->heads[i]; + for (; i < refs->length; ++i) { + head = refs->contents[i]; error = git_refspec_transform(refname, sizeof(refname), spec, head->name); if (error < GIT_SUCCESS) @@ -313,6 +333,7 @@ void git_remote_free(git_remote *remote) git__free(remote->push.dst); git__free(remote->url); git__free(remote->name); + git_vector_free(&remote->refs); git_remote_disconnect(remote); git__free(remote); } diff --git a/src/remote.h b/src/remote.h index 4b1db6c4e..a24e14845 100644 --- a/src/remote.h +++ b/src/remote.h @@ -14,7 +14,7 @@ struct git_remote { char *name; char *url; - git_headarray refs; + git_vector refs; struct git_refspec fetch; struct git_refspec push; git_transport *transport; diff --git a/src/repository.c b/src/repository.c index f8195e2d9..f1a37c945 100644 --- a/src/repository.c +++ b/src/repository.c @@ -24,118 +24,57 @@ #define GIT_BRANCH_MASTER "master" -/* - * Git repository open methods - * - * Open a repository object from its path - */ -static int assign_repository_dirs( - git_repository *repo, - const char *git_dir, - const char *git_object_directory, - const char *git_index_file, - const char *git_work_tree) -{ - char path_aux[GIT_PATH_MAX]; - int error = GIT_SUCCESS; - - assert(repo); - - if (git_dir == NULL) - return git__throw(GIT_ENOTFOUND, "Failed to open repository. Git dir not found"); - - error = git_path_prettify_dir(path_aux, git_dir, NULL); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open repository"); - /* store GIT_DIR */ - repo->path_repository = git__strdup(path_aux); - if (repo->path_repository == NULL) - return GIT_ENOMEM; - - /* path to GIT_OBJECT_DIRECTORY */ - if (git_object_directory == NULL) - git_path_join(path_aux, repo->path_repository, GIT_OBJECTS_DIR); - else { - error = git_path_prettify_dir(path_aux, git_object_directory, NULL); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open repository"); +static void drop_odb(git_repository *repo) +{ + if (repo->_odb != NULL) { + GIT_REFCOUNT_OWN(repo->_odb, NULL); + git_odb_free(repo->_odb); + repo->_odb = NULL; } +} - /* Store GIT_OBJECT_DIRECTORY */ - repo->path_odb = git__strdup(path_aux); - if (repo->path_odb == NULL) - return GIT_ENOMEM; - - /* path to GIT_WORK_TREE */ - if (git_work_tree == NULL) - repo->is_bare = 1; - else { - error = git_path_prettify_dir(path_aux, git_work_tree, NULL); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open repository"); - - /* Store GIT_WORK_TREE */ - repo->path_workdir = git__strdup(path_aux); - if (repo->path_workdir == NULL) - return GIT_ENOMEM; - - /* Path to GIT_INDEX_FILE */ - if (git_index_file == NULL) - git_path_join(path_aux, repo->path_repository, GIT_INDEX_FILE); - else { - error = git_path_prettify(path_aux, git_index_file, NULL); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open repository"); - } - - /* store GIT_INDEX_FILE */ - repo->path_index = git__strdup(path_aux); - if (repo->path_index == NULL) - return GIT_ENOMEM; +static void drop_config(git_repository *repo) +{ + if (repo->_config != NULL) { + GIT_REFCOUNT_OWN(repo->_config, NULL); + git_config_free(repo->_config); + repo->_config = NULL; } - - return GIT_SUCCESS; } -static int check_repository_dirs(git_repository *repo) +static void drop_index(git_repository *repo) { - char path_aux[GIT_PATH_MAX]; - - if (git_futils_isdir(repo->path_repository) < GIT_SUCCESS) - return git__throw(GIT_ENOTAREPO, "`%s` is not a folder", repo->path_repository); - - /* Ensure GIT_OBJECT_DIRECTORY exists */ - if (git_futils_isdir(repo->path_odb) < GIT_SUCCESS) - return git__throw(GIT_ENOTAREPO, "`%s` does not exist", repo->path_odb); - - /* Ensure HEAD file exists */ - git_path_join(path_aux, repo->path_repository, GIT_HEAD_FILE); - if (git_futils_isfile(path_aux) < 0) - return git__throw(GIT_ENOTAREPO, "HEAD file is missing"); - - return GIT_SUCCESS; + if (repo->_index != NULL) { + GIT_REFCOUNT_OWN(repo->_index, NULL); + git_index_free(repo->_index); + repo->_index = NULL; + } } -static int guess_repository_dirs(git_repository *repo, const char *repository_path) +void git_repository_free(git_repository *repo) { - char buffer[GIT_PATH_MAX]; - const char *path_work_tree = NULL; + if (repo == NULL) + return; - /* Git directory name */ - if (git_path_basename_r(buffer, sizeof(buffer), repository_path) < 0) - return git__throw(GIT_EINVALIDPATH, "Unable to parse folder name from `%s`", repository_path); + git_cache_free(&repo->objects); + git_repository__refcache_free(&repo->references); - if (strcmp(buffer, DOT_GIT) == 0) { - /* Path to working dir */ - if (git_path_dirname_r(buffer, sizeof(buffer), repository_path) < 0) - return git__throw(GIT_EINVALIDPATH, "Unable to parse parent folder name from `%s`", repository_path); - path_work_tree = buffer; - } + git__free(repo->path_repository); + git__free(repo->workdir); - return assign_repository_dirs(repo, repository_path, NULL, NULL, path_work_tree); + drop_config(repo); + drop_index(repo); + drop_odb(repo); + + git__free(repo); } +/* + * Git repository open methods + * + * Open a repository object from its path + */ static int quickcheck_repository_dir(const char *repository_path) { char path_aux[GIT_PATH_MAX]; @@ -156,6 +95,7 @@ static int quickcheck_repository_dir(const char *repository_path) return GIT_SUCCESS; } + static git_repository *repository_alloc(void) { int error; @@ -175,94 +115,97 @@ static git_repository *repository_alloc(void) return repo; } -static int init_odb(git_repository *repo) +static int load_config_data(git_repository *repo) { - return git_odb_open(&repo->db, repo->path_odb); -} + int error, is_bare; + git_config *config; -int git_repository_open3(git_repository **repo_out, - const char *git_dir, - git_odb *object_database, - const char *git_index_file, - const char *git_work_tree) -{ - git_repository *repo; - int error = GIT_SUCCESS; + error = git_repository_config__weakptr(&config, repo); + if (error < GIT_SUCCESS) + return error; - assert(repo_out); + error = git_config_get_bool(config, "core.bare", &is_bare); + if (error == GIT_SUCCESS) + repo->is_bare = is_bare; - if (object_database == NULL) - return git__throw(GIT_EINVALIDARGS, "Failed to open repository. `object_database` can't be null"); + /* TODO: what else can we load/cache here? */ - repo = repository_alloc(); - if (repo == NULL) - return GIT_ENOMEM; + return GIT_SUCCESS; +} - error = assign_repository_dirs(repo, - git_dir, - NULL, - git_index_file, - git_work_tree); +static int load_workdir(git_repository *repo) +{ + if (!repo->is_bare) { + char workdir_buf[GIT_PATH_MAX]; - if (error < GIT_SUCCESS) - goto cleanup; + if (git_path_dirname_r(workdir_buf, sizeof(workdir_buf), repo->path_repository) < 0) + return git__throw(GIT_EOSERR, + "Failed to resolved working directory"); - error = check_repository_dirs(repo); - if (error < GIT_SUCCESS) - goto cleanup; + git_path_join(workdir_buf, workdir_buf, ""); - repo->db = object_database; + repo->workdir = git__strdup(workdir_buf); + if (repo->workdir == NULL) + return GIT_ENOMEM; + } - *repo_out = repo; return GIT_SUCCESS; - -cleanup: - git_repository_free(repo); - return git__rethrow(error, "Failed to open repository"); } - -int git_repository_open2(git_repository **repo_out, - const char *git_dir, - const char *git_object_directory, - const char *git_index_file, - const char *git_work_tree) +int git_repository_open(git_repository **repo_out, const char *path) { - git_repository *repo; int error = GIT_SUCCESS; + char path_buf[GIT_PATH_MAX]; + size_t path_len; + git_repository *repo = NULL; - assert(repo_out); + error = git_path_prettify_dir(path_buf, path, NULL); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to open repository"); + + path_len = strlen(path_buf); + + /** + * Check if the path we've been given is actually the path + * of the working dir, by testing if it contains a `.git` + * folder inside of it. + */ + git_path_join(path_buf, path_buf, DOT_GIT); + if (git_futils_isdir(path_buf) < GIT_SUCCESS) { + path_buf[path_len] = 0; + } + + if (quickcheck_repository_dir(path_buf) < GIT_SUCCESS) + return git__throw(GIT_ENOTAREPO, + "The given path is not a valid Git repository"); repo = repository_alloc(); if (repo == NULL) return GIT_ENOMEM; - error = assign_repository_dirs(repo, - git_dir, - git_object_directory, - git_index_file, - git_work_tree); - - if (error < GIT_SUCCESS) - goto cleanup; + repo->path_repository = git__strdup(path_buf); + if (repo->path_repository == NULL) { + git_repository_free(repo); + return GIT_ENOMEM; + } - error = check_repository_dirs(repo); - if (error < GIT_SUCCESS) - goto cleanup; + error = load_config_data(repo); + if (error < GIT_SUCCESS) { + git_repository_free(repo); + return error; + } - error = init_odb(repo); - if (error < GIT_SUCCESS) - goto cleanup; + error = load_workdir(repo); + if (error < GIT_SUCCESS) { + git_repository_free(repo); + return error; + } *repo_out = repo; return GIT_SUCCESS; - -cleanup: - git_repository_free(repo); - return git__rethrow(error, "Failed to open repository"); } -int git_repository_config( +static int load_config( git_config **out, git_repository *repo, const char *global_config_path, @@ -270,98 +213,178 @@ int git_repository_config( { char config_path[GIT_PATH_MAX]; int error; + git_config *cfg = NULL; - assert(out && repo); + assert(repo && out); - error = git_config_new(out); + error = git_config_new(&cfg); if (error < GIT_SUCCESS) return error; git_path_join(config_path, repo->path_repository, GIT_CONFIG_FILENAME_INREPO); - error = git_config_add_file_ondisk(*out, config_path, 3); + error = git_config_add_file_ondisk(cfg, config_path, 3); if (error < GIT_SUCCESS) goto cleanup; if (global_config_path != NULL) { - error = git_config_add_file_ondisk(*out, global_config_path, 2); + error = git_config_add_file_ondisk(cfg, global_config_path, 2); if (error < GIT_SUCCESS) goto cleanup; } if (system_config_path != NULL) { - error = git_config_add_file_ondisk(*out, system_config_path, 1); + error = git_config_add_file_ondisk(cfg, system_config_path, 1); if (error < GIT_SUCCESS) goto cleanup; } - (*out)->repo = repo; + *out = cfg; return GIT_SUCCESS; cleanup: - git_config_free(*out); + git_config_free(cfg); + *out = NULL; return error; } -int git_repository_config_autoload( - git_config **out, - git_repository *repo) +int git_repository_config__weakptr(git_config **out, git_repository *repo) { - char global[GIT_PATH_MAX], system[GIT_PATH_MAX]; - char *global_path, *system_path; - int error; + if (repo->_config == NULL) { + int error; + char buf_global[GIT_PATH_MAX], buf_system[GIT_PATH_MAX]; - error = git_config_find_global(global); - global_path = error < GIT_SUCCESS ? NULL : global; + const char *global_config_path = NULL; + const char *system_config_path = NULL; - error = git_config_find_system(system); - system_path = error < GIT_SUCCESS ? NULL : system; + if (git_config_find_global(buf_global) == GIT_SUCCESS) + global_config_path = buf_global; + + if (git_config_find_system(buf_system) == GIT_SUCCESS) + system_config_path = buf_system; + + error = load_config(&repo->_config, repo, global_config_path, system_config_path); + if (error < GIT_SUCCESS) + return error; - return git_repository_config(out, repo, global_path, system_path); + GIT_REFCOUNT_OWN(repo->_config, repo); + } + + *out = repo->_config; + return GIT_SUCCESS; } -static int discover_repository_dirs(git_repository *repo, const char *path) +int git_repository_config(git_config **out, git_repository *repo) { - int error; + int error = git_repository_config__weakptr(out, repo); - error = guess_repository_dirs(repo, path); - if (error < GIT_SUCCESS) - return error; + if (error == GIT_SUCCESS) { + GIT_REFCOUNT_INC(*out); + } - error = check_repository_dirs(repo); - if (error < GIT_SUCCESS) - return error; + return error; +} + +void git_repository_set_config(git_repository *repo, git_config *config) +{ + assert(repo && config); + + drop_config(repo); + + repo->_config = config; + GIT_REFCOUNT_OWN(repo->_config, repo); +} + +int git_repository_odb__weakptr(git_odb **out, git_repository *repo) +{ + assert(repo && out); + + if (repo->_odb == NULL) { + int error; + char odb_path[GIT_PATH_MAX]; + + git_path_join(odb_path, repo->path_repository, GIT_OBJECTS_DIR); + + error = git_odb_open(&repo->_odb, odb_path); + if (error < GIT_SUCCESS) + return error; + + GIT_REFCOUNT_OWN(repo->_odb, repo); + } + GIT_REFCOUNT_INC(repo->_odb); + *out = repo->_odb; return GIT_SUCCESS; } -int git_repository_open(git_repository **repo_out, const char *path) +int git_repository_odb(git_odb **out, git_repository *repo) { - git_repository *repo; - int error = GIT_SUCCESS; + int error = git_repository_odb__weakptr(out, repo); - assert(repo_out && path); + if (error == GIT_SUCCESS) { + GIT_REFCOUNT_INC(*out); + } - repo = repository_alloc(); - if (repo == NULL) - return GIT_ENOMEM; + return error; +} - error = discover_repository_dirs(repo, path); - if (error < GIT_SUCCESS) - goto cleanup; +void git_repository_set_odb(git_repository *repo, git_odb *odb) +{ + assert(repo && odb); - error = init_odb(repo); - if (error < GIT_SUCCESS) - goto cleanup; + drop_odb(repo); - *repo_out = repo; + repo->_odb = odb; + GIT_REFCOUNT_OWN(repo->_odb, repo); +} + +int git_repository_index__weakptr(git_index **out, git_repository *repo) +{ + assert(out && repo); + + if (repo->is_bare) + return git__throw(GIT_EBAREINDEX, "Cannot open index in bare repository"); + + if (repo->_index == NULL) { + int error; + char index_path[GIT_PATH_MAX]; + + git_path_join(index_path, repo->path_repository, GIT_INDEX_FILE); + + error = git_index_open(&repo->_index, index_path); + if (error < GIT_SUCCESS) + return error; + + GIT_REFCOUNT_OWN(repo->_index, repo); + } + + GIT_REFCOUNT_INC(repo->_index); + *out = repo->_index; return GIT_SUCCESS; +} -cleanup: - git_repository_free(repo); - return git__rethrow(error, "Failed to open repository"); +int git_repository_index(git_index **out, git_repository *repo) +{ + int error = git_repository_index__weakptr(out, repo); + + if (error == GIT_SUCCESS) { + GIT_REFCOUNT_INC(*out); + } + + return error; } +void git_repository_set_index(git_repository *repo, git_index *index) +{ + assert(repo && index); + + drop_index(repo); + + repo->_index = index; + GIT_REFCOUNT_OWN(repo->_index, repo); +} + + static int retrieve_device(dev_t *device_out, const char *path) { struct stat path_info; @@ -460,34 +483,12 @@ static int read_gitfile(char *path_out, const char *file_path, const char *base_ return git__throw(GIT_EOBJCORRUPTED, "The `.git` file points to an inexisting path"); } -static void git_repository__free_dirs(git_repository *repo) -{ - git__free(repo->path_workdir); - repo->path_workdir = NULL; - git__free(repo->path_index); - repo->path_index = NULL; - git__free(repo->path_repository); - repo->path_repository = NULL; - git__free(repo->path_odb); - repo->path_odb = NULL; -} - -void git_repository_free(git_repository *repo) -{ - if (repo == NULL) - return; - - git_cache_free(&repo->objects); - git_repository__refcache_free(&repo->references); - git_repository__free_dirs(repo); - - if (repo->db != NULL) - git_odb_close(repo->db); - - git__free(repo); -} - -int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs) +int git_repository_discover( + char *repository_path, + size_t size, + const char *start_path, + int across_fs, + const char *ceiling_dirs) { int error, ceiling_offset; char bare_path[GIT_PATH_MAX]; @@ -519,11 +520,13 @@ int git_repository_discover(char *repository_path, size_t size, const char *star error = read_gitfile(repository_path, normal_path, bare_path); if (error < GIT_SUCCESS) - return git__rethrow(error, "Unable to read git file `%s`", normal_path); + return git__rethrow(error, + "Unable to read git file `%s`", normal_path); error = quickcheck_repository_dir(repository_path); if (error < GIT_SUCCESS) - return git__throw(GIT_ENOTFOUND, "The `.git` file found at '%s' points" + return git__throw(GIT_ENOTFOUND, + "The `.git` file found at '%s' points" "to an inexisting Git folder", normal_path); return GIT_SUCCESS; @@ -558,7 +561,8 @@ int git_repository_discover(char *repository_path, size_t size, const char *star error = retrieve_device(&new_device, normal_path); if (error < GIT_SUCCESS || current_device != new_device) { - return git__throw(GIT_ENOTAREPO,"Not a git repository (or any parent up to mount parent %s)\n" + return git__throw(GIT_ENOTAREPO, + "Not a git repository (or any parent up to mount parent %s)\n" "Stopping at filesystem boundary.", bare_path); } current_device = new_device; @@ -569,42 +573,66 @@ int git_repository_discover(char *repository_path, size_t size, const char *star // nothing has been found, lets try the parent directory if (bare_path[ceiling_offset] == '\0') { - return git__throw(GIT_ENOTAREPO,"Not a git repository (or any of the parent directories): %s", start_path); + return git__throw(GIT_ENOTAREPO, + "Not a git repository (or any of the parent directories): %s", start_path); } } if (size < strlen(found_path) + 2) { - return git__throw(GIT_ESHORTBUFFER, "The repository buffer is not long enough to handle the repository path `%s`", found_path); + return git__throw(GIT_ESHORTBUFFER, + "The repository buffer is not long enough to handle the repository path `%s`", found_path); } git_path_join(repository_path, found_path, ""); return GIT_SUCCESS; } -git_odb *git_repository_database(git_repository *repo) -{ - assert(repo); - return repo->db; -} - static int repo_init_reinit(const char *repository_path, int is_bare) { /* TODO: reinit the repository */ return git__throw(GIT_ENOTIMPLEMENTED, "Failed to reinitialize the %srepository at '%s'. " "This feature is not yet implemented", - is_bare ? "bare" : "", repository_path); + is_bare ? "bare " : "", repository_path); } -static int repo_init_createhead(git_repository *repo) +static int repo_init_createhead(const char *git_dir) { - int error; - git_reference *head_reference; + char ref_path[GIT_PATH_MAX]; + git_filebuf ref = GIT_FILEBUF_INIT; + + git_path_join(ref_path, git_dir, GIT_HEAD_FILE); + + git_filebuf_open(&ref, ref_path, 0); + git_filebuf_printf(&ref, "ref: refs/heads/master\n"); + + return git_filebuf_commit(&ref, GIT_REFS_FILE_MODE); +} + +static int repo_init_config(const char *git_dir, int is_bare) +{ + char cfg_path[GIT_PATH_MAX]; + git_config *config; + int error = GIT_SUCCESS; + +#define SET_REPO_CONFIG(type, name, val) {\ + error = git_config_set_##type(config, name, val);\ + if (error < GIT_SUCCESS)\ + goto cleanup;\ +} - error = git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0); + git_path_join(cfg_path, git_dir, GIT_CONFIG_FILENAME_INREPO); - git_reference_free(head_reference); + error = git_config_open_ondisk(&config, cfg_path); + if (error < GIT_SUCCESS) + return error; + SET_REPO_CONFIG(bool, "core.bare", is_bare); + SET_REPO_CONFIG(int32, "core.repositoryformatversion", 0); + /* TODO: what other defaults? */ + +cleanup: + git_config_free(config); return error; } @@ -674,31 +702,15 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is if (error < GIT_SUCCESS) goto cleanup; - repo = repository_alloc(); - if (repo == NULL) { - error = GIT_ENOMEM; - goto cleanup; - } - - error = guess_repository_dirs(repo, repository_path); + error = repo_init_config(repository_path, is_bare); if (error < GIT_SUCCESS) goto cleanup; - assert(repo->is_bare == is_bare); - - error = init_odb(repo); - if (error < GIT_SUCCESS) - goto cleanup; - - error = repo_init_createhead(repo); + error = repo_init_createhead(repository_path); if (error < GIT_SUCCESS) goto cleanup; - /* should never fail */ - assert(check_repository_dirs(repo) == GIT_SUCCESS); - - *repo_out = repo; - return GIT_SUCCESS; + return git_repository_open(repo_out, repository_path); cleanup: git_repository_free(repo); @@ -709,8 +721,13 @@ int git_repository_head_detached(git_repository *repo) { git_reference *ref; int error; - size_t GIT_UNUSED(_size); + size_t _size; git_otype type; + git_odb *odb = NULL; + + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + return error; error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE); if (error < GIT_SUCCESS) @@ -721,7 +738,7 @@ int git_repository_head_detached(git_repository *repo) return 0; } - error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref)); + error = git_odb_read_header(&_size, &type, odb, git_reference_oid(ref)); git_reference_free(ref); @@ -797,26 +814,34 @@ int git_repository_is_empty(git_repository *repo) return error == GIT_ENOTFOUND ? 1 : error; } -const char *git_repository_path(git_repository *repo, git_repository_pathid id) +const char *git_repository_path(git_repository *repo) { assert(repo); + return repo->path_repository; +} - switch (id) { - case GIT_REPO_PATH: - return repo->path_repository; +const char *git_repository_workdir(git_repository *repo) +{ + assert(repo); - case GIT_REPO_PATH_INDEX: - return repo->path_index; + if (repo->is_bare) + return NULL; - case GIT_REPO_PATH_ODB: - return repo->path_odb; + return repo->workdir; +} - case GIT_REPO_PATH_WORKDIR: - return repo->path_workdir; +int git_repository_set_workdir(git_repository *repo, const char *workdir) +{ + assert(repo && workdir); - default: - return NULL; - } + free(repo->workdir); + + repo->workdir = git__strdup(workdir); + if (repo->workdir == NULL) + return GIT_ENOMEM; + + repo->is_bare = 0; + return GIT_SUCCESS; } int git_repository_is_bare(git_repository *repo) diff --git a/src/repository.h b/src/repository.h index 0c17958fd..c3a9a5c60 100644 --- a/src/repository.h +++ b/src/repository.h @@ -32,15 +32,15 @@ struct git_object { }; struct git_repository { - git_odb *db; + git_odb *_odb; + git_config *_config; + git_index *_index; git_cache objects; git_refcache references; char *path_repository; - char *path_index; - char *path_odb; - char *path_workdir; + char *workdir; unsigned is_bare:1; unsigned int lru_counter; @@ -53,4 +53,8 @@ void git_object__free(void *object); int git_oid__parse(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); void git_oid__writebuf(git_buf *buf, const char *header, const git_oid *oid); +int git_repository_config__weakptr(git_config **out, git_repository *repo); +int git_repository_odb__weakptr(git_odb **out, git_repository *repo); +int git_repository_index__weakptr(git_index **out, git_repository *repo); + #endif diff --git a/src/revwalk.c b/src/revwalk.c index 7e31650ff..d632a19b8 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -34,6 +34,7 @@ typedef struct commit_list { struct git_revwalk { git_repository *repo; + git_odb *odb; git_hashtable *commits; @@ -225,16 +226,16 @@ static int commit_parse(git_revwalk *walk, commit_object *commit) if (commit->parsed) return GIT_SUCCESS; - if ((error = git_odb_read(&obj, walk->repo->db, &commit->oid)) < GIT_SUCCESS) + if ((error = git_odb_read(&obj, walk->odb, &commit->oid)) < GIT_SUCCESS) return git__rethrow(error, "Failed to parse commit. Can't read object"); if (obj->raw.type != GIT_OBJ_COMMIT) { - git_odb_object_close(obj); + git_odb_object_free(obj); return git__throw(GIT_EOBJTYPE, "Failed to parse commit. Object is no commit object"); } error = commit_quick_parse(walk, commit, &obj->raw); - git_odb_object_close(obj); + git_odb_object_free(obj); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse commit"); } @@ -429,6 +430,7 @@ static int prepare_walk(git_revwalk *walk) int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { + int error; git_revwalk *walk; walk = git__malloc(sizeof(git_revwalk)); @@ -455,6 +457,12 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) walk->repo = repo; + error = git_repository_odb(&walk->odb, repo); + if (error < GIT_SUCCESS) { + git_revwalk_free(walk); + return error; + } + *revwalk_out = walk; return GIT_SUCCESS; } @@ -469,6 +477,7 @@ void git_revwalk_free(git_revwalk *walk) return; git_revwalk_reset(walk); + git_odb_free(walk->odb); /* if the parent has more than PARENTS_PER_COMMIT parents, * we had to allocate a separate array for those parents. diff --git a/src/status.c b/src/status.c index d50199d9a..97093a553 100644 --- a/src/status.c +++ b/src/status.c @@ -162,7 +162,7 @@ static int retrieve_head_tree(git_tree **tree_out, git_repository *repo) *tree_out = tree; exit: - git_commit_close(head_commit); + git_commit_free(head_commit); return error; } @@ -214,7 +214,7 @@ static int process_folder(struct status_st *st, const git_tree_entry *tree_entry } if (tree_entry_type == GIT_OBJ_TREE) { - git_object_close(subtree); + git_object_free(subtree); st->head_tree_relative_path_len -= 1 + tree_entry->filename_len; st->tree = pushed_tree; st->tree_position = pushed_tree_position; @@ -410,9 +410,15 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig unsigned int i; git_tree *tree; struct status_entry *e; + const char *workdir; - if ((error = git_repository_index(&index, repo)) < GIT_SUCCESS) { - return git__rethrow(error, "Failed to determine statuses. Index can't be opened"); + if ((workdir = git_repository_workdir(repo)) == NULL) + return git__throw(GIT_ERROR, + "Cannot retrieve status on a bare repository"); + + if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) { + return git__rethrow(error, + "Failed to determine statuses. Index can't be opened"); } if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) { @@ -422,7 +428,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig git_vector_init(&entries, DEFAULT_SIZE, status_cmp); - dirent_st.workdir_path_len = strlen(repo->path_workdir); + dirent_st.workdir_path_len = strlen(workdir); dirent_st.tree_position = 0; dirent_st.index_position = 0; dirent_st.tree = tree; @@ -432,18 +438,29 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig dirent_st.head_tree_relative_path_len = 0; dirent_st.is_dir = 1; - strcpy(temp_path, repo->path_workdir); + strcpy(temp_path, workdir); if (git_futils_isdir(temp_path)) { - error = git__throw(GIT_EINVALIDPATH, "Failed to determine status of file '%s'. Provided path doesn't lead to a folder", temp_path); + error = git__throw(GIT_EINVALIDPATH, + "Failed to determine status of file '%s'. " + "The given path doesn't lead to a folder", temp_path); goto exit; } - if ((error = alphasorted_futils_direach(temp_path, sizeof(temp_path), dirent_cb, &dirent_st)) < GIT_SUCCESS) - error = git__rethrow(error, "Failed to determine statuses. An error occured while processing the working directory"); + error = alphasorted_futils_direach( + temp_path, sizeof(temp_path), + dirent_cb, &dirent_st + ); + + if (error < GIT_SUCCESS) + error = git__rethrow(error, + "Failed to determine statuses. " + "An error occured while processing the working directory"); if ((error == GIT_SUCCESS) && ((error = dirent_cb(&dirent_st, NULL)) < GIT_SUCCESS)) - error = git__rethrow(error, "Failed to determine statuses. An error occured while post-processing the HEAD tree and the index"); + error = git__rethrow(error, + "Failed to determine statuses. " + "An error occured while post-processing the HEAD tree and the index"); for (i = 0; i < entries.length; ++i) { e = (struct status_entry *)git_vector_get(&entries, i); @@ -451,7 +468,8 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig if (error == GIT_SUCCESS) { error = callback(e->path, e->status_flags, payload); if (error < GIT_SUCCESS) - error = git__rethrow(error, "Failed to determine statuses. User callback failed"); + error = git__rethrow(error, + "Failed to determine statuses. User callback failed"); } git__free(e); @@ -459,8 +477,7 @@ int git_status_foreach(git_repository *repo, int (*callback)(const char *, unsig exit: git_vector_free(&entries); - git_tree_close(tree); - git_index_free(index); + git_tree_free(tree); return error; } @@ -495,7 +512,7 @@ static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char return git__throw(GIT_EOBJCORRUPTED, "Can't find tree object '%s'", tree_entry->filename); error = recurse_tree_entry(subtree, e, dir_sep+1); - git_tree_close(subtree); + git_tree_free(subtree); return error; } @@ -506,12 +523,19 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char char temp_path[GIT_PATH_MAX]; int error = GIT_SUCCESS; git_tree *tree = NULL; + const char *workdir; assert(status_flags && repo && path); - git_path_join(temp_path, repo->path_workdir, path); + if ((workdir = git_repository_workdir(repo)) == NULL) + return git__throw(GIT_ERROR, + "Cannot retrieve status on a bare repository"); + + git_path_join(temp_path, workdir, path); if (git_futils_isdir(temp_path) == GIT_SUCCESS) - return git__throw(GIT_EINVALIDPATH, "Failed to determine status of file '%s'. Provided path leads to a folder, not a file", path); + return git__throw(GIT_EINVALIDPATH, + "Failed to determine status of file '%s'. " + "Given path leads to a folder, not a file", path); e = status_entry_new(NULL, path); if (e == NULL) @@ -524,16 +548,18 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char } /* Find file in Index */ - if ((error = git_repository_index(&index, repo)) < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to determine status of file '%s'. Index can't be opened", path); + if ((error = git_repository_index__weakptr(&index, repo)) < GIT_SUCCESS) { + error = git__rethrow(error, + "Failed to determine status of file '%s'." + "Index can't be opened", path); goto exit; } status_entry_update_from_index(e, index); - git_index_free(index); if ((error = retrieve_head_tree(&tree, repo)) < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to determine status of file '%s'", path); + error = git__rethrow(error, + "Failed to determine status of file '%s'", path); goto exit; } @@ -543,7 +569,9 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char error = recurse_tree_entry(tree, e, temp_path); if (error < GIT_SUCCESS) { - error = git__rethrow(error, "Failed to determine status of file '%s'. An error occured while processing the tree", path); + error = git__rethrow(error, + "Failed to determine status of file '%s'. " + "An error occured while processing the tree", path); goto exit; } } @@ -557,7 +585,7 @@ int git_status_file(unsigned int *status_flags, git_repository *repo, const char *status_flags = e->status_flags; exit: - git_tree_close(tree); + git_tree_free(tree); git__free(e); return error; } @@ -175,6 +175,7 @@ static int write_tag_annotation( { int error = GIT_SUCCESS; git_buf tag = GIT_BUF_INIT; + git_odb *odb; git_oid__writebuf(&tag, "object ", git_object_id(target)); git_buf_printf(&tag, "type %s\n", git_object_type2string(git_object_type(target))); @@ -188,7 +189,13 @@ static int write_tag_annotation( return git__throw(GIT_ENOMEM, "Not enough memory to build the tag data"); } - error = git_odb_write(oid, git_repository_database(repo), tag.ptr, tag.size, GIT_OBJ_TAG); + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) { + git_buf_free(&tag); + return error; + } + + error = git_odb_write(oid, odb, tag.ptr, tag.size, GIT_OBJ_TAG); git_buf_free(&tag); if (error < GIT_SUCCESS) @@ -286,6 +293,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu { git_tag tag; int error, should_update_ref = 0; + git_odb *odb; git_odb_stream *stream; git_odb_object *target_obj; @@ -296,18 +304,22 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu memset(&tag, 0, sizeof(tag)); + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) + return error; + /* validate the buffer */ if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS) return git__rethrow(error, "Failed to create tag"); /* validate the target */ - if ((error = git_odb_read(&target_obj, repo->db, &tag.target)) < GIT_SUCCESS) + if ((error = git_odb_read(&target_obj, odb, &tag.target)) < GIT_SUCCESS) return git__rethrow(error, "Failed to create tag"); if (tag.type != target_obj->raw.type) return git__throw(error, "The type for the given target is invalid"); - git_odb_object_close(target_obj); + git_odb_object_free(target_obj); error = retrieve_tag_reference(&new_ref, ref_name, repo, tag.tag_name); @@ -334,7 +346,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu } /* write the buffer */ - if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) { + if ((error = git_odb_open_wstream(&stream, odb, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) { git_reference_free(new_ref); return git__rethrow(error, "Failed to create tag"); } diff --git a/src/transport.c b/src/transport.c index 0d67e1967..d836561b4 100644 --- a/src/transport.c +++ b/src/transport.c @@ -6,7 +6,7 @@ */ #include "common.h" #include "git2/types.h" -#include "git2/transport.h" +#include "git2/remote.h" #include "git2/net.h" #include "transport.h" @@ -49,11 +49,6 @@ int git_transport_dummy(git_transport **GIT_UNUSED(transport)) return git__throw(GIT_ENOTIMPLEMENTED, "This protocol isn't implemented. Sorry"); } -int git_transport_valid_url(const char *url) -{ - return transport_find_fn(url) != NULL; -} - int git_transport_new(git_transport **out, const char *url) { git_transport_cb fn; @@ -81,3 +76,10 @@ int git_transport_new(git_transport **out, const char *url) return GIT_SUCCESS; } + +/* from remote.h */ +int git_remote_valid_url(const char *url) +{ + return transport_find_fn(url) != NULL; +} + diff --git a/src/transport.h b/src/transport.h index 23b83b690..2ed8ad32a 100644 --- a/src/transport.h +++ b/src/transport.h @@ -7,7 +7,6 @@ #ifndef INCLUDE_transport_h__ #define INCLUDE_transport_h__ -#include "git2/transport.h" #include "git2/net.h" #include "vector.h" @@ -61,7 +60,7 @@ struct git_transport { /** * Give a list of references, useful for ls-remote */ - int (*ls)(struct git_transport *transport, git_headarray *headarray); + int (*ls)(struct git_transport *transport, git_headlist_cb list_cb, void *opaque); /** * Push the changes over */ @@ -74,7 +73,7 @@ struct git_transport { * Negotiate the minimal amount of objects that need to be * retrieved */ - int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, git_headarray *list); + int (*negotiate_fetch)(struct git_transport *transport, git_repository *repo, const git_vector *wants); /** * Send a flush */ @@ -97,9 +96,15 @@ struct git_transport { void (*free)(struct git_transport *transport); }; + +int git_transport_new(struct git_transport **transport, const char *url); int git_transport_local(struct git_transport **transport); int git_transport_git(struct git_transport **transport); int git_transport_http(struct git_transport **transport); int git_transport_dummy(struct git_transport **transport); +int git_transport_valid_url(const char *url); + +typedef struct git_transport git_transport; +typedef int (*git_transport_cb)(git_transport **transport); #endif diff --git a/src/transports/git.c b/src/transports/git.c index 2ee2e4831..bdb94d090 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -226,32 +226,30 @@ cleanup: return error; } -static int git_ls(git_transport *transport, git_headarray *array) +static int git_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque) { transport_git *t = (transport_git *) transport; git_vector *refs = &t->refs; - int len = 0; unsigned int i; + git_pkt *p = NULL; - array->heads = git__calloc(refs->length, sizeof(git_remote_head *)); - if (array->heads == NULL) - return GIT_ENOMEM; + git_vector_foreach(refs, i, p) { + git_pkt_ref *pkt = NULL; - for (i = 0; i < refs->length; ++i) { - git_pkt *p = git_vector_get(refs, i); if (p->type != GIT_PKT_REF) continue; - ++len; - array->heads[i] = &(((git_pkt_ref *) p)->head); + pkt = (git_pkt_ref *)p; + + if (list_cb(&pkt->head, opaque) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); } - array->len = len; - t->heads = array->heads; return GIT_SUCCESS; } -static int git_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants) +static int git_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) { transport_git *t = (transport_git *) transport; git_revwalk *walk; @@ -290,6 +288,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, g if (git_reference_type(ref) == GIT_REF_SYMBOLIC) continue; + error = git_revwalk_push(walk, git_reference_oid(ref)); if (error < GIT_ERROR) { error = git__rethrow(error, "Failed to push %s", refs.strings[i]); diff --git a/src/transports/http.c b/src/transports/http.c index ae0c56a73..e463a0f59 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -301,29 +301,22 @@ cleanup: return error; } -static int http_ls(git_transport *transport, git_headarray *array) +static int http_ls(git_transport *transport, git_headlist_cb list_cb, void *opaque) { transport_http *t = (transport_http *) transport; git_vector *refs = &t->refs; unsigned int i; - int len = 0; git_pkt_ref *p; - array->heads = git__calloc(refs->length, sizeof(git_remote_head*)); - if (array->heads == NULL) - return GIT_ENOMEM; - git_vector_foreach(refs, i, p) { if (p->type != GIT_PKT_REF) continue; - array->heads[len] = &p->head; - len++; + if (list_cb(&p->head, opaque) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); } - array->len = len; - t->heads = array->heads; - return GIT_SUCCESS; } @@ -470,7 +463,7 @@ cleanup: return error; } -static int http_negotiate_fetch(git_transport *transport, git_repository *repo, git_headarray *wants) +static int http_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) { transport_http *t = (transport_http *) transport; int error; diff --git a/src/transports/local.c b/src/transports/local.c index 058ed7e79..f50a96173 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -6,7 +6,6 @@ */ #include "common.h" #include "git2/types.h" -#include "git2/transport.h" #include "git2/net.h" #include "git2/repository.h" #include "git2/object.h" @@ -18,39 +17,10 @@ typedef struct { git_transport parent; git_repository *repo; - git_vector *refs; + git_vector refs; } transport_local; -/* - * Try to open the url as a git directory. The direction doesn't - * matter in this case because we're calulating the heads ourselves. - */ -static int local_connect(git_transport *transport, int GIT_UNUSED(direction)) -{ - git_repository *repo; - int error; - transport_local *t = (transport_local *) transport; - const char *path; - const char file_prefix[] = "file://"; - GIT_UNUSED_ARG(direction); - - /* The repo layer doesn't want the prefix */ - if (!git__prefixcmp(transport->url, file_prefix)) - path = transport->url + strlen(file_prefix); - else - path = transport->url; - - error = git_repository_open(&repo, path); - if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to open remote"); - - t->repo = repo; - t->parent.connected = 1; - - return GIT_SUCCESS; -} - -static int add_ref(const char *name, git_repository *repo, git_vector *vec) +static int add_ref(transport_local *t, const char *name) { const char peeled[] = "^{}"; git_remote_head *head; @@ -68,7 +38,7 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) goto out; } - error = git_reference_lookup(&ref, repo, name); + error = git_reference_lookup(&ref, t->repo, name); if (error < GIT_SUCCESS) goto out; @@ -78,15 +48,17 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) git_oid_cpy(&head->oid, git_reference_oid(ref)); - error = git_vector_insert(vec, head); + error = git_vector_insert(&t->refs, head); if (error < GIT_SUCCESS) goto out; + head = NULL; + /* If it's not a tag, we don't need to try to peel it */ if (git__prefixcmp(name, GIT_REFS_TAGS_DIR)) goto out; - error = git_object_lookup(&obj, repo, &head->oid, GIT_OBJ_ANY); + error = git_object_lookup(&obj, t->repo, &head->oid, GIT_OBJ_ANY); if (error < GIT_SUCCESS) { git__rethrow(error, "Failed to lookup object"); } @@ -100,13 +72,12 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) peel_len = strlen(name) + strlen(peeled); head->name = git__malloc(peel_len + 1); ret = p_snprintf(head->name, peel_len + 1, "%s%s", name, peeled); - if (ret >= peel_len + 1) { - error = git__throw(GIT_ERROR, "The string is magically to long"); - } + + assert(ret < peel_len + 1); git_oid_cpy(&head->oid, git_tag_target_oid((git_tag *) obj)); - error = git_vector_insert(vec, head); + error = git_vector_insert(&t->refs, head); if (error < GIT_SUCCESS) goto out; @@ -114,71 +85,109 @@ static int add_ref(const char *name, git_repository *repo, git_vector *vec) git_reference_free(ref); git_reference_free(resolved_ref); - git_object_close(obj); - if (error < GIT_SUCCESS) { + git_object_free(obj); + if (head && error < GIT_SUCCESS) { git__free(head->name); git__free(head); } + return error; } -static int local_ls(git_transport *transport, git_headarray *array) +static int store_refs(transport_local *t) { int error; unsigned int i; - git_repository *repo; - git_vector *vec; - git_strarray refs; - transport_local *t = (transport_local *) transport; + git_strarray ref_names = {0}; - assert(transport && transport->connected); - - repo = t->repo; + assert(t); - error = git_reference_listall(&refs, repo, GIT_REF_LISTALL); + error = git_vector_init(&t->refs, ref_names.count, NULL); if (error < GIT_SUCCESS) - return git__rethrow(error, "Failed to list remote heads"); - - vec = git__malloc(sizeof(git_vector)); - if (vec == NULL) { - error = GIT_ENOMEM; - goto out; - } + return error; - error = git_vector_init(vec, refs.count, NULL); + error = git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL); if (error < GIT_SUCCESS) - return error; + return git__rethrow(error, "Failed to list remote heads"); /* Sort the references first */ - git__tsort((void **)refs.strings, refs.count, &git__strcmp_cb); + git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); /* Add HEAD */ - error = add_ref(GIT_HEAD_FILE, repo, vec); + error = add_ref(t, GIT_HEAD_FILE); if (error < GIT_SUCCESS) - goto out; + goto cleanup; - for (i = 0; i < refs.count; ++i) { - error = add_ref(refs.strings[i], repo, vec); + for (i = 0; i < ref_names.count; ++i) { + error = add_ref(t, ref_names.strings[i]); if (error < GIT_SUCCESS) - goto out; + goto cleanup; } - array->len = vec->length; - array->heads = (git_remote_head **)vec->contents; +cleanup: + git_strarray_free(&ref_names); + return error; +} - t->refs = vec; +static int local_ls(git_transport *transport, git_headlist_cb list_cb, void *payload) +{ + transport_local *t = (transport_local *) transport; + git_vector *refs = &t->refs; + unsigned int i; + git_remote_head *h; - out: + assert(transport && transport->connected); - git_strarray_free(&refs); + git_vector_foreach(refs, i, h) { + if (list_cb(h, payload) < 0) + return git__throw(GIT_ERROR, + "The user callback returned an error code"); + } - return error; + return GIT_SUCCESS; +} + + +/* + * Try to open the url as a git directory. The direction doesn't + * matter in this case because we're calulating the heads ourselves. + */ +static int local_connect(git_transport *transport, int GIT_UNUSED(direction)) +{ + git_repository *repo; + int error; + transport_local *t = (transport_local *) transport; + const char *path; + const char file_prefix[] = "file://"; + GIT_UNUSED_ARG(direction); + + /* The repo layer doesn't want the prefix */ + if (!git__prefixcmp(transport->url, file_prefix)) + path = transport->url + strlen(file_prefix); + else + path = transport->url; + + error = git_repository_open(&repo, path); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to open remote"); + + error = store_refs(t); + if (error < GIT_SUCCESS) + return git__rethrow(error, "Failed to retrieve references"); + + t->repo = repo; + t->parent.connected = 1; + + return GIT_SUCCESS; } static int local_close(git_transport *GIT_UNUSED(transport)) { - /* Nothing to do */ - GIT_UNUSED_ARG(transport); + transport_local *t = (transport_local *)transport; + + git_repository_free(t->repo); + t->repo = NULL; + return GIT_SUCCESS; } @@ -186,21 +195,17 @@ static void local_free(git_transport *transport) { unsigned int i; transport_local *t = (transport_local *) transport; - git_vector *vec = t->refs; + git_vector *vec = &t->refs; git_remote_head *h; assert(transport); - if (t->refs != NULL) { - git_vector_foreach (vec, i, h) { - git__free(h->name); - git__free(h); - } - git_vector_free(vec); - git__free(vec); + git_vector_foreach (vec, i, h) { + git__free(h->name); + git__free(h); } + git_vector_free(vec); - git_repository_free(t->repo); git__free(t->parent.url); git__free(t); } diff --git a/src/tree.c b/src/tree.c index 92ca5ab77..702095d14 100644 --- a/src/tree.c +++ b/src/tree.c @@ -300,9 +300,15 @@ static int append_entry(git_treebuilder *bld, const char *filename, const git_oi return GIT_SUCCESS; } -static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsigned int start) +static int write_tree( + git_oid *oid, + git_repository *repo, + git_index *index, + const char *dirname, + unsigned int start) { git_treebuilder *bld = NULL; + unsigned int i, entries = git_index_entrycount(index); int error; size_t dirname_len = strlen(dirname); @@ -358,7 +364,7 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig } /* Write out the subtree */ - written = write_tree(&sub_oid, index, subdir, i); + written = write_tree(&sub_oid, repo, index, subdir, i); if (written < 0) { error = git__rethrow(written, "Failed to write subtree %s", subdir); } else { @@ -391,7 +397,7 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig } } - error = git_treebuilder_write(oid, index->repository, bld); + error = git_treebuilder_write(oid, repo, bld); if (error < GIT_SUCCESS) error = git__rethrow(error, "Failed to write tree to db"); @@ -406,10 +412,15 @@ static int write_tree(git_oid *oid, git_index *index, const char *dirname, unsig int git_tree_create_fromindex(git_oid *oid, git_index *index) { + git_repository *repo; int error; - if (index->repository == NULL) - return git__throw(GIT_EBAREINDEX, "Failed to create tree. The index file is not backed up by an existing repository"); + repo = (git_repository *)GIT_REFCOUNT_OWNER(index); + + if (repo == NULL) + return git__throw(GIT_EBAREINDEX, + "Failed to create tree. " + "The index file is not backed up by an existing repository"); if (index->tree != NULL && index->tree->entries >= 0) { git_oid_cpy(oid, &index->tree->oid); @@ -417,7 +428,7 @@ int git_tree_create_fromindex(git_oid *oid, git_index *index) } /* The tree cache didn't help us */ - error = write_tree(oid, index, "", 0); + error = write_tree(oid, repo, index, "", 0); return (error < GIT_SUCCESS) ? git__rethrow(error, "Failed to create tree") : GIT_SUCCESS; } @@ -546,6 +557,7 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b unsigned int i; int error; git_buf tree = GIT_BUF_INIT; + git_odb *odb; assert(bld); @@ -570,7 +582,13 @@ int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *b return git__throw(GIT_ENOMEM, "Not enough memory to build the tree data"); } - error = git_odb_write(oid, git_repository_database(repo), tree.ptr, tree.size, GIT_OBJ_TREE); + error = git_repository_odb__weakptr(&odb, repo); + if (error < GIT_SUCCESS) { + git_buf_free(&tree); + return error; + } + + error = git_odb_write(oid, odb, tree.ptr, tree.size, GIT_OBJ_TREE); git_buf_free(&tree); return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write tree"); @@ -662,7 +680,7 @@ static int tree_frompath( slash_pos - treeentry_path + 1 ); - git_tree_close(subtree); + git_tree_free(subtree); return error; } @@ -713,7 +731,7 @@ static int tree_walk_post( payload ); - git_tree_close(subtree); + git_tree_free(subtree); } } diff --git a/src/util.h b/src/util.h index fbf9012a3..4b1104b7b 100644 --- a/src/util.h +++ b/src/util.h @@ -104,29 +104,34 @@ extern void git__strtolower(char *str); extern int git__fnmatch(const char *pattern, const char *name, int flags); -/* - * Realloc the buffer pointed at by variable 'x' so that it can hold - * at least 'nr' entries; the number of entries currently allocated - * is 'alloc', using the standard growing factor alloc_nr() macro. - * - * DO NOT USE any expression with side-effect for 'x' or 'alloc'. - */ -#define alloc_nr(x) (((x)+16)*3/2) -#define ALLOC_GROW(x, nr, alloc) \ - do { \ - if ((nr) > alloc) { \ - if (alloc_nr(alloc) < (nr)) \ - alloc = (nr); \ - else \ - alloc = alloc_nr(alloc); \ - x = xrealloc((x), alloc * sizeof(*(x))); \ - } \ - } while (0) - extern void git__tsort(void **dst, size_t size, int (*cmp)(const void *, const void *)); extern void **git__bsearch(const void *key, void **base, size_t nmemb, int (*compar)(const void *, const void *)); extern int git__strcmp_cb(const void *a, const void *b); +typedef struct { + short refcount; + void *owner; +} git_refcount; + +typedef void (*git_refcount_freeptr)(void *r); + +#define GIT_REFCOUNT_INC(r) { \ + ((git_refcount *)(r))->refcount++; \ +} + +#define GIT_REFCOUNT_DEC(_r, do_free) { \ + git_refcount *r = (git_refcount *)(_r); \ + r->refcount--; \ + if (r->refcount <= 0 && r->owner == NULL) { do_free(_r); } \ +} + +#define GIT_REFCOUNT_OWN(r, o) { \ + ((git_refcount *)(r))->owner = o; \ +} + +#define GIT_REFCOUNT_OWNER(r) (((git_refcount *)(r))->owner) + + #endif /* INCLUDE_util_h__ */ diff --git a/tests-clay/clay.h b/tests-clay/clay.h index 3db9600b3..b05a8247e 100644 --- a/tests-clay/clay.h +++ b/tests-clay/clay.h @@ -59,10 +59,30 @@ void cl_fixture_cleanup(const char *fixture_name); */ extern void test_buf_basic__printf(void); extern void test_buf_basic__resize(void); +extern void test_config_add__cleanup(void); +extern void test_config_add__initialize(void); +extern void test_config_add__to_existing_section(void); +extern void test_config_add__to_new_section(void); extern void test_config_new__write_new_config(void); +extern void test_config_read__blank_lines(void); +extern void test_config_read__case_sensitive(void); +extern void test_config_read__empty_files(void); +extern void test_config_read__header_in_last_line(void); +extern void test_config_read__invalid_ext_headers(void); +extern void test_config_read__lone_variable(void); +extern void test_config_read__multiline_value(void); +extern void test_config_read__number_suffixes(void); +extern void test_config_read__prefixes(void); +extern void test_config_read__simple_read(void); +extern void test_config_read__subsection_header(void); extern void test_config_stress__cleanup(void); extern void test_config_stress__dont_break_on_invalid_input(void); extern void test_config_stress__initialize(void); +extern void test_config_write__cleanup(void); +extern void test_config_write__delete_inexistent(void); +extern void test_config_write__delete_value(void); +extern void test_config_write__initialize(void); +extern void test_config_write__replace_value(void); extern void test_core_dirent__dont_traverse_dot(void); extern void test_core_dirent__dont_traverse_empty_folders(void); extern void test_core_dirent__traverse_slash_terminated_folder(void); @@ -133,6 +153,31 @@ extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void); extern void test_object_tree_frompath__initialize(void); extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void); +extern void test_odb_loose__cleanup(void); +extern void test_odb_loose__exists(void); +extern void test_odb_loose__initialize(void); +extern void test_odb_loose__simple_reads(void); +extern void test_odb_packed__cleanup(void); +extern void test_odb_packed__initialize(void); +extern void test_odb_packed__mass_read(void); +extern void test_odb_packed__read_header_0(void); +extern void test_odb_packed__read_header_1(void); +extern void test_odb_sorting__alternate_backends_sorting(void); +extern void test_odb_sorting__basic_backends_sorting(void); +extern void test_odb_sorting__cleanup(void); +extern void test_odb_sorting__initialize(void); +extern void test_repo_getters__cleanup(void); +extern void test_repo_getters__empty(void); +extern void test_repo_getters__head_detached(void); +extern void test_repo_getters__head_orphan(void); +extern void test_repo_getters__initialize(void); +extern void test_repo_init__bare_repo(void); +extern void test_repo_init__bare_repo_noslash(void); +extern void test_repo_init__initialize(void); +extern void test_repo_init__standard_repo(void); +extern void test_repo_init__standard_repo_noslash(void); +extern void test_repo_open__bare_empty_repo(void); +extern void test_repo_open__standard_empty_repo(void); extern void test_status_single__hash_single_file(void); extern void test_status_worktree__cleanup(void); extern void test_status_worktree__empty_repository(void); diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c index 2f9a49d36..5c97057ec 100644 --- a/tests-clay/clay_main.c +++ b/tests-clay/clay_main.c @@ -108,12 +108,34 @@ static const struct clay_func _clay_cb_buf_basic[] = { {"printf", &test_buf_basic__printf}, {"resize", &test_buf_basic__resize} }; +static const struct clay_func _clay_cb_config_add[] = { + {"to_existing_section", &test_config_add__to_existing_section}, + {"to_new_section", &test_config_add__to_new_section} +}; static const struct clay_func _clay_cb_config_new[] = { {"write_new_config", &test_config_new__write_new_config} }; +static const struct clay_func _clay_cb_config_read[] = { + {"blank_lines", &test_config_read__blank_lines}, + {"case_sensitive", &test_config_read__case_sensitive}, + {"empty_files", &test_config_read__empty_files}, + {"header_in_last_line", &test_config_read__header_in_last_line}, + {"invalid_ext_headers", &test_config_read__invalid_ext_headers}, + {"lone_variable", &test_config_read__lone_variable}, + {"multiline_value", &test_config_read__multiline_value}, + {"number_suffixes", &test_config_read__number_suffixes}, + {"prefixes", &test_config_read__prefixes}, + {"simple_read", &test_config_read__simple_read}, + {"subsection_header", &test_config_read__subsection_header} +}; static const struct clay_func _clay_cb_config_stress[] = { {"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input} }; +static const struct clay_func _clay_cb_config_write[] = { + {"delete_inexistent", &test_config_write__delete_inexistent}, + {"delete_value", &test_config_write__delete_value}, + {"replace_value", &test_config_write__replace_value} +}; static const struct clay_func _clay_cb_core_dirent[] = { {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot}, {"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders}, @@ -216,6 +238,34 @@ static const struct clay_func _clay_cb_object_tree_frompath[] = { {"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment}, {"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry} }; +static const struct clay_func _clay_cb_odb_loose[] = { + {"exists", &test_odb_loose__exists}, + {"simple_reads", &test_odb_loose__simple_reads} +}; +static const struct clay_func _clay_cb_odb_packed[] = { + {"mass_read", &test_odb_packed__mass_read}, + {"read_header_0", &test_odb_packed__read_header_0}, + {"read_header_1", &test_odb_packed__read_header_1} +}; +static const struct clay_func _clay_cb_odb_sorting[] = { + {"alternate_backends_sorting", &test_odb_sorting__alternate_backends_sorting}, + {"basic_backends_sorting", &test_odb_sorting__basic_backends_sorting} +}; +static const struct clay_func _clay_cb_repo_getters[] = { + {"empty", &test_repo_getters__empty}, + {"head_detached", &test_repo_getters__head_detached}, + {"head_orphan", &test_repo_getters__head_orphan} +}; +static const struct clay_func _clay_cb_repo_init[] = { + {"bare_repo", &test_repo_init__bare_repo}, + {"bare_repo_noslash", &test_repo_init__bare_repo_noslash}, + {"standard_repo", &test_repo_init__standard_repo}, + {"standard_repo_noslash", &test_repo_init__standard_repo_noslash} +}; +static const struct clay_func _clay_cb_repo_open[] = { + {"bare_empty_repo", &test_repo_open__bare_empty_repo}, + {"standard_empty_repo", &test_repo_open__standard_empty_repo} +}; static const struct clay_func _clay_cb_status_single[] = { {"hash_single_file", &test_status_single__hash_single_file} }; @@ -232,18 +282,36 @@ static const struct clay_suite _clay_suites[] = { _clay_cb_buf_basic, 2 }, { + "config::add", + {"initialize", &test_config_add__initialize}, + {"cleanup", &test_config_add__cleanup}, + _clay_cb_config_add, 2 + }, + { "config::new", {NULL, NULL}, {NULL, NULL}, _clay_cb_config_new, 1 }, { + "config::read", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_config_read, 11 + }, + { "config::stress", {"initialize", &test_config_stress__initialize}, {"cleanup", &test_config_stress__cleanup}, _clay_cb_config_stress, 1 }, { + "config::write", + {"initialize", &test_config_write__initialize}, + {"cleanup", &test_config_write__cleanup}, + _clay_cb_config_write, 3 + }, + { "core::dirent", {NULL, NULL}, {NULL, NULL}, @@ -358,6 +426,42 @@ static const struct clay_suite _clay_suites[] = { _clay_cb_object_tree_frompath, 3 }, { + "odb::loose", + {"initialize", &test_odb_loose__initialize}, + {"cleanup", &test_odb_loose__cleanup}, + _clay_cb_odb_loose, 2 + }, + { + "odb::packed", + {"initialize", &test_odb_packed__initialize}, + {"cleanup", &test_odb_packed__cleanup}, + _clay_cb_odb_packed, 3 + }, + { + "odb::sorting", + {"initialize", &test_odb_sorting__initialize}, + {"cleanup", &test_odb_sorting__cleanup}, + _clay_cb_odb_sorting, 2 + }, + { + "repo::getters", + {"initialize", &test_repo_getters__initialize}, + {"cleanup", &test_repo_getters__cleanup}, + _clay_cb_repo_getters, 3 + }, + { + "repo::init", + {"initialize", &test_repo_init__initialize}, + {NULL, NULL}, + _clay_cb_repo_init, 4 + }, + { + "repo::open", + {NULL, NULL}, + {NULL, NULL}, + _clay_cb_repo_open, 2 + }, + { "status::single", {NULL, NULL}, {NULL, NULL}, @@ -371,8 +475,8 @@ static const struct clay_suite _clay_suites[] = { } }; -static size_t _clay_suite_count = 24; -static size_t _clay_callback_count = 71; +static size_t _clay_suite_count = 33; +static size_t _clay_callback_count = 103; /* Core test functions */ static void diff --git a/tests-clay/config/add.c b/tests-clay/config/add.c new file mode 100644 index 000000000..de549af15 --- /dev/null +++ b/tests-clay/config/add.c @@ -0,0 +1,37 @@ +#include "clay_libgit2.h" + +void test_config_add__initialize(void) +{ + cl_fixture_sandbox("config/config10"); +} + +void test_config_add__cleanup(void) +{ + cl_fixture_cleanup("config10"); +} + +void test_config_add__to_existing_section(void) +{ + git_config *cfg; + int32_t i; + + cl_git_pass(git_config_open_ondisk(&cfg, "config10")); + cl_git_pass(git_config_set_int32(cfg, "empty.tmp", 5)); + cl_git_pass(git_config_get_int32(cfg, "empty.tmp", &i)); + cl_assert(i == 5); + cl_git_pass(git_config_delete(cfg, "empty.tmp")); + git_config_free(cfg); +} + +void test_config_add__to_new_section(void) +{ + git_config *cfg; + int32_t i; + + cl_git_pass(git_config_open_ondisk(&cfg, "config10")); + cl_git_pass(git_config_set_int32(cfg, "section.tmp", 5)); + cl_git_pass(git_config_get_int32(cfg, "section.tmp", &i)); + cl_assert(i == 5); + cl_git_pass(git_config_delete(cfg, "section.tmp")); + git_config_free(cfg); +} diff --git a/tests-clay/config/read.c b/tests-clay/config/read.c new file mode 100644 index 000000000..08dc03a88 --- /dev/null +++ b/tests-clay/config/read.c @@ -0,0 +1,209 @@ +#include "clay_libgit2.h" + +void test_config_read__simple_read(void) +{ + git_config *cfg; + int32_t i; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config0"))); + + cl_git_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &i)); + cl_assert(i == 0); + cl_git_pass(git_config_get_bool(cfg, "core.filemode", &i)); + cl_assert(i == 1); + cl_git_pass(git_config_get_bool(cfg, "core.bare", &i)); + cl_assert(i == 0); + cl_git_pass(git_config_get_bool(cfg, "core.logallrefupdates", &i)); + cl_assert(i == 1); + + git_config_free(cfg); +} + +void test_config_read__case_sensitive(void) +{ + git_config *cfg; + int i; + const char *str; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config1"))); + + cl_git_pass(git_config_get_string(cfg, "this.that.other", &str)); + cl_assert(!strcmp(str, "true")); + cl_git_pass(git_config_get_string(cfg, "this.That.other", &str)); + cl_assert(!strcmp(str, "yes")); + + cl_git_pass(git_config_get_bool(cfg, "this.that.other", &i)); + cl_assert(i == 1); + cl_git_pass(git_config_get_bool(cfg, "this.That.other", &i)); + cl_assert(i == 1); + + /* This one doesn't exist */ + cl_must_fail(git_config_get_bool(cfg, "this.thaT.other", &i)); + + git_config_free(cfg); +} + +/* + * If \ is the last non-space character on the line, we read the next + * one, separating each line with SP. + */ +void test_config_read__multiline_value(void) +{ + git_config *cfg; + const char *str; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config2"))); + + cl_git_pass(git_config_get_string(cfg, "this.That.and", &str)); + cl_assert(!strcmp(str, "one one one two two three three")); + + git_config_free(cfg); +} + +/* + * This kind of subsection declaration is case-insensitive + */ +void test_config_read__subsection_header(void) +{ + git_config *cfg; + const char *str; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config3"))); + + cl_git_pass(git_config_get_string(cfg, "section.subsection.var", &str)); + cl_assert(!strcmp(str, "hello")); + + /* The subsection is transformed to lower-case */ + cl_must_fail(git_config_get_string(cfg, "section.subSectIon.var", &str)); + + git_config_free(cfg); +} + +void test_config_read__lone_variable(void) +{ + git_config *cfg; + const char *str; + int i; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config4"))); + + cl_git_pass(git_config_get_string(cfg, "some.section.variable", &str)); + cl_assert(str == NULL); + + cl_git_pass(git_config_get_bool(cfg, "some.section.variable", &i)); + cl_assert(i == 1); + + git_config_free(cfg); +} + +void test_config_read__number_suffixes(void) +{ + git_config *cfg; + int64_t i; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config5"))); + + cl_git_pass(git_config_get_int64(cfg, "number.simple", &i)); + cl_assert(i == 1); + + cl_git_pass(git_config_get_int64(cfg, "number.k", &i)); + cl_assert(i == 1 * 1024); + + cl_git_pass(git_config_get_int64(cfg, "number.kk", &i)); + cl_assert(i == 1 * 1024); + + cl_git_pass(git_config_get_int64(cfg, "number.m", &i)); + cl_assert(i == 1 * 1024 * 1024); + + cl_git_pass(git_config_get_int64(cfg, "number.mm", &i)); + cl_assert(i == 1 * 1024 * 1024); + + cl_git_pass(git_config_get_int64(cfg, "number.g", &i)); + cl_assert(i == 1 * 1024 * 1024 * 1024); + + cl_git_pass(git_config_get_int64(cfg, "number.gg", &i)); + cl_assert(i == 1 * 1024 * 1024 * 1024); + + git_config_free(cfg); +} + +void test_config_read__blank_lines(void) +{ + git_config *cfg; + int i; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config6"))); + + cl_git_pass(git_config_get_bool(cfg, "valid.subsection.something", &i)); + cl_assert(i == 1); + + cl_git_pass(git_config_get_bool(cfg, "something.else.something", &i)); + cl_assert(i == 0); + + git_config_free(cfg); +} + +void test_config_read__invalid_ext_headers(void) +{ + git_config *cfg; + cl_must_fail(git_config_open_ondisk(&cfg, cl_fixture("config/config7"))); +} + +void test_config_read__empty_files(void) +{ + git_config *cfg; + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config8"))); + git_config_free(cfg); +} + +void test_config_read__header_in_last_line(void) +{ + git_config *cfg; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config10"))); + git_config_free(cfg); +} + +void test_config_read__prefixes(void) +{ + git_config *cfg; + const char *str; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9"))); + cl_git_pass(git_config_get_string(cfg, "remote.ab.url", &str)); + cl_assert(strcmp(str, "http://example.com/git/ab") == 0); + + cl_git_pass(git_config_get_string(cfg, "remote.abba.url", &str)); + cl_assert(strcmp(str, "http://example.com/git/abba") == 0); + + git_config_free(cfg); +} + +#if 0 + +BEGIN_TEST(config10, "a repo's config overrides the global config") + git_repository *repo; + git_config *cfg; + int32_t version; + + cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + cl_git_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL)); + cl_git_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &version)); + cl_assert(version == 0); + git_config_free(cfg); + git_repository_free(repo); +END_TEST + +BEGIN_TEST(config11, "fall back to the global config") + git_repository *repo; + git_config *cfg; + int32_t num; + + cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + cl_git_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL)); + cl_git_pass(git_config_get_int32(cfg, "core.something", &num)); + cl_assert(num == 2); + git_config_free(cfg); + git_repository_free(repo); +END_TEST +#endif diff --git a/tests-clay/config/stress.c b/tests-clay/config/stress.c index 832321556..b48ed399d 100644 --- a/tests-clay/config/stress.c +++ b/tests-clay/config/stress.c @@ -4,23 +4,21 @@ #include "fileops.h" #include "posix.h" -#define TEST_CONFIG "git-test-config" - void test_config_stress__initialize(void) { git_filebuf file = GIT_FILEBUF_INIT; - git_filebuf_open(&file, TEST_CONFIG, 0); + cl_git_pass(git_filebuf_open(&file, "git-test-config", 0)); git_filebuf_printf(&file, "[color]\n\tui = auto\n"); git_filebuf_printf(&file, "[core]\n\teditor = \n"); - git_filebuf_commit(&file, 0666); + cl_git_pass(git_filebuf_commit(&file, 0666)); } void test_config_stress__cleanup(void) { - p_unlink(TEST_CONFIG); + p_unlink("git-test-config"); } void test_config_stress__dont_break_on_invalid_input(void) @@ -29,8 +27,8 @@ void test_config_stress__dont_break_on_invalid_input(void) struct git_config_file *file; git_config *config; - cl_git_pass(git_futils_exists(TEST_CONFIG)); - cl_git_pass(git_config_file__ondisk(&file, TEST_CONFIG)); + cl_git_pass(git_futils_exists("git-test-config")); + cl_git_pass(git_config_file__ondisk(&file, "git-test-config")); cl_git_pass(git_config_new(&config)); cl_git_pass(git_config_add_file(config, file, 0)); diff --git a/tests-clay/config/write.c b/tests-clay/config/write.c new file mode 100644 index 000000000..57610ab63 --- /dev/null +++ b/tests-clay/config/write.c @@ -0,0 +1,77 @@ +#include "clay_libgit2.h" + +void test_config_write__initialize(void) +{ + cl_fixture_sandbox("config/config9"); +} + +void test_config_write__cleanup(void) +{ + cl_fixture_cleanup("config9"); +} + +void test_config_write__replace_value(void) +{ + git_config *cfg; + int i; + int64_t l, expected = +9223372036854775803; + + /* By freeing the config, we make sure we flush the values */ + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_get_int32(cfg, "core.dummy", &i)); + cl_assert(i == 5); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected)); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_get_int64(cfg, "core.verylong", &l)); + cl_assert(l == expected); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_must_fail(git_config_get_int32(cfg, "core.verylong", &i)); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1)); + git_config_free(cfg); +} + +void test_config_write__delete_value(void) +{ + git_config *cfg; + int32_t i; + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5)); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_git_pass(git_config_delete(cfg, "core.dummy")); + git_config_free(cfg); + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_assert(git_config_get_int32(cfg, "core.dummy", &i) == GIT_ENOTFOUND); + cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); + git_config_free(cfg); +} + +void test_config_write__delete_inexistent(void) +{ + git_config *cfg; + + cl_git_pass(git_config_open_ondisk(&cfg, "config9")); + cl_assert(git_config_delete(cfg, "core.imaginary") == GIT_ENOTFOUND); + git_config_free(cfg); +} diff --git a/tests-clay/network/remotes.c b/tests-clay/network/remotes.c index a7cc742db..2c3a32e7f 100644 --- a/tests-clay/network/remotes.c +++ b/tests-clay/network/remotes.c @@ -1,45 +1,43 @@ #include "clay_libgit2.h" -#define REPOSITORY_FOLDER "testrepo.git" - -static git_remote *remote; -static git_repository *repo; -static git_config *cfg; -static const git_refspec *refspec; +static git_remote *_remote; +static git_repository *_repo; +static const git_refspec *_refspec; void test_network_remotes__initialize(void) { - cl_fixture_sandbox(REPOSITORY_FOLDER); - cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - cl_git_pass(git_repository_config(&cfg, repo, NULL, NULL)); - cl_git_pass(git_remote_get(&remote, cfg, "test")); - refspec = git_remote_fetchspec(remote); - cl_assert(refspec != NULL); + cl_fixture_sandbox("testrepo.git"); + + cl_git_pass(git_repository_open(&_repo, "testrepo.git")); + cl_git_pass(git_remote_load(&_remote, _repo, "test")); + + _refspec = git_remote_fetchspec(_remote); + cl_assert(_refspec != NULL); } void test_network_remotes__cleanup(void) { - git_config_free(cfg); - git_repository_free(repo); - git_remote_free(remote); + git_remote_free(_remote); + git_repository_free(_repo); + cl_fixture_cleanup("testrepo.git"); } void test_network_remotes__parsing(void) { - cl_assert(!strcmp(git_remote_name(remote), "test")); - cl_assert(!strcmp(git_remote_url(remote), "git://github.com/libgit2/libgit2")); + cl_assert(!strcmp(git_remote_name(_remote), "test")); + cl_assert(!strcmp(git_remote_url(_remote), "git://github.com/libgit2/libgit2")); } void test_network_remotes__refspec_parsing(void) { - cl_assert(!strcmp(git_refspec_src(refspec), "refs/heads/*")); - cl_assert(!strcmp(git_refspec_dst(refspec), "refs/remotes/test/*")); + cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*")); + cl_assert(!strcmp(git_refspec_dst(_refspec), "refs/remotes/test/*")); } void test_network_remotes__fnmatch(void) { - cl_git_pass(git_refspec_src_match(refspec, "refs/heads/master")); - cl_git_pass(git_refspec_src_match(refspec, "refs/heads/multi/level/branch")); + cl_git_pass(git_refspec_src_match(_refspec, "refs/heads/master")); + cl_git_pass(git_refspec_src_match(_refspec, "refs/heads/multi/level/branch")); } void test_network_remotes__transform(void) @@ -47,6 +45,6 @@ void test_network_remotes__transform(void) char ref[1024]; memset(ref, 0x0, sizeof(ref)); - cl_git_pass(git_refspec_transform(ref, sizeof(ref), refspec, "refs/heads/master")); + cl_git_pass(git_refspec_transform(ref, sizeof(ref), _refspec, "refs/heads/master")); cl_assert(!strcmp(ref, "refs/remotes/test/master")); } diff --git a/tests-clay/object/tree/frompath.c b/tests-clay/object/tree/frompath.c index 1effcb1db..06d08ac7b 100644 --- a/tests-clay/object/tree/frompath.c +++ b/tests-clay/object/tree/frompath.c @@ -1,7 +1,5 @@ #include "clay_libgit2.h" -#define REPOSITORY_FOLDER "testrepo.git" - static git_repository *repo; const char *tree_with_subtrees_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; static git_tree *tree; @@ -10,8 +8,8 @@ void test_object_tree_frompath__initialize(void) { git_oid id; - cl_fixture_sandbox(REPOSITORY_FOLDER); - cl_git_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(git_repository_open(&repo, "testrepo.git")); cl_assert(repo != NULL); cl_git_pass(git_oid_fromstr(&id, tree_with_subtrees_oid)); @@ -21,8 +19,9 @@ void test_object_tree_frompath__initialize(void) void test_object_tree_frompath__cleanup(void) { - git_tree_close(tree); + git_tree_free(tree); git_repository_free(repo); + cl_fixture_cleanup("testrepo.git"); } static void assert_tree_from_path(git_tree *root, const char *path, git_error expected_result, const char *expected_raw_oid) @@ -38,7 +37,7 @@ static void assert_tree_from_path(git_tree *root, const char *path, git_error ex cl_assert(git_oid_streq(git_object_id((const git_object *)containing_tree), expected_raw_oid) == GIT_SUCCESS); - git_tree_close(containing_tree); + git_tree_free(containing_tree); } void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void) diff --git a/tests-clay/odb/loose.c b/tests-clay/odb/loose.c new file mode 100644 index 000000000..1d534704e --- /dev/null +++ b/tests-clay/odb/loose.c @@ -0,0 +1,84 @@ +#include "clay_libgit2.h" +#include "odb.h" +#include "posix.h" +#include "loose_data.h" + +static void write_object_files(object_data *d) +{ + int fd; + + if (p_mkdir(d->dir, GIT_OBJECT_DIR_MODE) < 0) + cl_assert(errno == EEXIST); + + cl_assert((fd = p_creat(d->file, S_IREAD | S_IWRITE)) >= 0); + cl_must_pass(p_write(fd, d->bytes, d->blen)); + + p_close(fd); +} + +static void cmp_objects(git_rawobj *o, object_data *d) +{ + cl_assert(o->type == git_object_string2type(d->type)); + cl_assert(o->len == d->dlen); + + if (o->len > 0) + cl_assert(memcmp(o->data, d->data, o->len) == 0); +} + +static void test_read_object(object_data *data) +{ + git_oid id; + git_odb_object *obj; + git_odb *odb; + + write_object_files(data); + + cl_git_pass(git_odb_open(&odb, "test-objects")); + cl_git_pass(git_oid_fromstr(&id, data->id)); + cl_git_pass(git_odb_read(&obj, odb, &id)); + + cmp_objects((git_rawobj *)&obj->raw, data); + + git_odb_object_free(obj); + git_odb_free(odb); +} + +void test_odb_loose__initialize(void) +{ + cl_must_pass(p_mkdir("test-objects", GIT_OBJECT_DIR_MODE)); +} + +void test_odb_loose__cleanup(void) +{ + cl_fixture_cleanup("test-objects"); +} + +void test_odb_loose__exists(void) +{ + git_oid id, id2; + git_odb *odb; + + write_object_files(&one); + cl_git_pass(git_odb_open(&odb, "test-objects")); + + cl_git_pass(git_oid_fromstr(&id, one.id)); + + cl_assert(git_odb_exists(odb, &id)); + + /* Test for a non-existant object */ + cl_git_pass(git_oid_fromstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa")); + cl_assert(!git_odb_exists(odb, &id2)); + + git_odb_free(odb); +} + +void test_odb_loose__simple_reads(void) +{ + test_read_object(&commit); + test_read_object(&tree); + test_read_object(&tag); + test_read_object(&zero); + test_read_object(&one); + test_read_object(&two); + test_read_object(&some); +} diff --git a/tests/t02-data.h b/tests-clay/odb/loose_data.h index 705a2d7af..c10c9bc7f 100644 --- a/tests/t02-data.h +++ b/tests-clay/odb/loose_data.h @@ -1,5 +1,13 @@ - -static char *odb_dir = "test-objects"; +typedef struct object_data { + unsigned char *bytes; /* (compressed) bytes stored in object store */ + size_t blen; /* length of data in object store */ + char *id; /* object id (sha1) */ + char *type; /* object type */ + char *dir; /* object store (fan-out) directory name */ + char *file; /* object store filename */ + unsigned char *data; /* (uncompressed) object data */ + size_t dlen; /* length of (uncompressed) object data */ +} object_data; /* one == 8b137891791fe96927ad78e64b0aad7bded08bdc */ static unsigned char one_bytes[] = { @@ -512,4 +520,3 @@ static object_data some = { some_data, sizeof(some_data), }; - diff --git a/tests/t02-oids.h b/tests-clay/odb/pack_data.h index 1a5ed5df0..e6371beb1 100644 --- a/tests/t02-oids.h +++ b/tests-clay/odb/pack_data.h @@ -149,4 +149,3 @@ static const char *loose_objects[] = { "a4a7dce85cf63874e984719f4fdd239f5145052f", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045" }; - diff --git a/tests-clay/odb/packed.c b/tests-clay/odb/packed.c new file mode 100644 index 000000000..4e9918d3e --- /dev/null +++ b/tests-clay/odb/packed.c @@ -0,0 +1,78 @@ +#include "clay_libgit2.h" +#include "odb.h" +#include "pack_data.h" + +static git_odb *_odb; + +void test_odb_packed__initialize(void) +{ + cl_git_pass(git_odb_open(&_odb, cl_fixture("testrepo.git/objects"))); +} + +void test_odb_packed__cleanup(void) +{ + git_odb_free(_odb); +} + +void test_odb_packed__mass_read(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { + git_oid id; + git_odb_object *obj; + + cl_git_pass(git_oid_fromstr(&id, packed_objects[i])); + cl_assert(git_odb_exists(_odb, &id) == 1); + cl_git_pass(git_odb_read(&obj, _odb, &id)); + + git_odb_object_free(obj); + } +} + +void test_odb_packed__read_header_0(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { + git_oid id; + git_odb_object *obj; + size_t len; + git_otype type; + + cl_git_pass(git_oid_fromstr(&id, packed_objects[i])); + + cl_git_pass(git_odb_read(&obj, _odb, &id)); + cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); + + cl_assert(obj->raw.len == len); + cl_assert(obj->raw.type == type); + + git_odb_object_free(obj); + } +} + +void test_odb_packed__read_header_1(void) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(loose_objects); ++i) { + git_oid id; + git_odb_object *obj; + size_t len; + git_otype type; + + cl_git_pass(git_oid_fromstr(&id, loose_objects[i])); + + cl_assert(git_odb_exists(_odb, &id) == 1); + + cl_git_pass(git_odb_read(&obj, _odb, &id)); + cl_git_pass(git_odb_read_header(&len, &type, _odb, &id)); + + cl_assert(obj->raw.len == len); + cl_assert(obj->raw.type == type); + + git_odb_object_free(obj); + } +} + diff --git a/tests-clay/odb/sorting.c b/tests-clay/odb/sorting.c new file mode 100644 index 000000000..779660707 --- /dev/null +++ b/tests-clay/odb/sorting.c @@ -0,0 +1,71 @@ +#include "clay_libgit2.h" +#include "git2/odb_backend.h" +#include "odb.h" + +typedef struct { + git_odb_backend base; + int position; +} fake_backend; + +static git_odb_backend *new_backend(int position) +{ + fake_backend *b; + + b = git__malloc(sizeof(fake_backend)); + if (b == NULL) + return NULL; + + memset(b, 0x0, sizeof(fake_backend)); + b->position = position; + return (git_odb_backend *)b; +} + +static void check_backend_sorting(git_odb *odb) +{ + unsigned int i; + + for (i = 0; i < odb->backends.length; ++i) { + fake_backend *internal = + *((fake_backend **)git_vector_get(&odb->backends, i)); + + cl_assert(internal != NULL); + cl_assert(internal->position == (int)i); + } +} + +static git_odb *_odb; + +void test_odb_sorting__initialize(void) +{ + cl_git_pass(git_odb_new(&_odb)); +} + +void test_odb_sorting__cleanup(void) +{ + git_odb_free(_odb); + _odb = NULL; +} + +void test_odb_sorting__basic_backends_sorting(void) +{ + cl_git_pass(git_odb_add_backend(_odb, new_backend(0), 5)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(2), 3)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 4)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 1)); + + check_backend_sorting(_odb); +} + +void test_odb_sorting__alternate_backends_sorting(void) +{ + cl_git_pass(git_odb_add_backend(_odb, new_backend(0), 5)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(2), 3)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(1), 4)); + cl_git_pass(git_odb_add_backend(_odb, new_backend(3), 1)); + cl_git_pass(git_odb_add_alternate(_odb, new_backend(4), 5)); + cl_git_pass(git_odb_add_alternate(_odb, new_backend(6), 3)); + cl_git_pass(git_odb_add_alternate(_odb, new_backend(5), 4)); + cl_git_pass(git_odb_add_alternate(_odb, new_backend(7), 1)); + + check_backend_sorting(_odb); +} diff --git a/tests-clay/repo/getters.c b/tests-clay/repo/getters.c new file mode 100644 index 000000000..3acdb7566 --- /dev/null +++ b/tests-clay/repo/getters.c @@ -0,0 +1,68 @@ +#include "clay_libgit2.h" + +void test_repo_getters__initialize(void) +{ + cl_fixture_sandbox("testrepo.git"); +} + +void test_repo_getters__cleanup(void) +{ + cl_fixture_cleanup("testrepo.git"); +} + +void test_repo_getters__empty(void) +{ + git_repository *repo_empty, *repo_normal; + + cl_git_pass(git_repository_open(&repo_normal, cl_fixture("testrepo.git"))); + cl_assert(git_repository_is_empty(repo_normal) == 0); + git_repository_free(repo_normal); + + cl_git_pass(git_repository_open(&repo_empty, cl_fixture("empty_bare.git"))); + cl_assert(git_repository_is_empty(repo_empty) == 1); + git_repository_free(repo_empty); +} + +void test_repo_getters__head_detached(void) +{ + git_repository *repo; + git_reference *ref; + git_oid oid; + + cl_git_pass(git_repository_open(&repo, "testrepo.git")); + + cl_assert(git_repository_head_detached(repo) == 0); + + /* detach the HEAD */ + git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd"); + cl_git_pass(git_reference_create_oid(&ref, repo, "HEAD", &oid, 1)); + cl_assert(git_repository_head_detached(repo) == 1); + + /* take the reop back to it's original state */ + cl_git_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/master", 1)); + cl_assert(git_repository_head_detached(repo) == 0); + + git_reference_free(ref); + git_repository_free(repo); +} + +void test_repo_getters__head_orphan(void) +{ + git_repository *repo; + git_reference *ref; + + cl_git_pass(git_repository_open(&repo, "testrepo.git")); + + cl_assert(git_repository_head_orphan(repo) == 0); + + /* orphan HEAD */ + cl_git_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/orphan", 1)); + cl_assert(git_repository_head_orphan(repo) == 1); + + /* take the reop back to it's original state */ + cl_git_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/master", 1)); + cl_assert(git_repository_head_orphan(repo) == 0); + + git_reference_free(ref); + git_repository_free(repo); +} diff --git a/tests-clay/repo/init.c b/tests-clay/repo/init.c new file mode 100644 index 000000000..95cd704e9 --- /dev/null +++ b/tests-clay/repo/init.c @@ -0,0 +1,104 @@ +#include "clay_libgit2.h" +#include "fileops.h" + +enum repo_mode { + STANDARD_REPOSITORY = 0, + BARE_REPOSITORY = 1 +}; + +static git_repository *_repo; + +void test_repo_init__initialize(void) +{ + _repo = NULL; +} + +static void cleanup_repository(void *path) +{ + git_repository_free(_repo); + cl_fixture_cleanup((const char *)path); +} + +static void ensure_repository_init( + const char *working_directory, + int is_bare, + const char *expected_path_repository, + const char *expected_working_directory) +{ + const char *workdir; + + cl_git_pass(git_repository_init(&_repo, working_directory, is_bare)); + + workdir = git_repository_workdir(_repo); + if (workdir != NULL || expected_working_directory != NULL) { + cl_assert( + git__suffixcmp(workdir, expected_working_directory) == 0 + ); + } + + cl_assert( + git__suffixcmp(git_repository_path(_repo), expected_path_repository) == 0 + ); + + cl_assert(git_repository_is_bare(_repo) == is_bare); + +#ifdef GIT_WIN32 + if (!is_bare) { + cl_assert((GetFileAttributes(_repo->path_repository) & FILE_ATTRIBUTE_HIDDEN) != 0); + } +#endif + + cl_assert(git_repository_is_empty(_repo)); +} + +void test_repo_init__standard_repo(void) +{ + cl_set_cleanup(&cleanup_repository, "testrepo"); + ensure_repository_init("testrepo/", 0, "testrepo/.git/", "testrepo/"); +} + +void test_repo_init__standard_repo_noslash(void) +{ + cl_set_cleanup(&cleanup_repository, "testrepo"); + ensure_repository_init("testrepo", 0, "testrepo/.git/", "testrepo/"); +} + +void test_repo_init__bare_repo(void) +{ + cl_set_cleanup(&cleanup_repository, "testrepo.git"); + ensure_repository_init("testrepo.git/", 1, "testrepo.git/", NULL); +} + +void test_repo_init__bare_repo_noslash(void) +{ + cl_set_cleanup(&cleanup_repository, "testrepo.git"); + ensure_repository_init("testrepo.git", 1, "testrepo.git/", NULL); +} + +#if 0 +BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory") + char path_repository[GIT_PATH_MAX]; + char current_workdir[GIT_PATH_MAX]; + const mode_t mode = 0777; + git_repository* repo; + + must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); + + git_path_join(path_repository, TEMP_REPO_FOLDER, "a/b/c/"); + must_pass(git_futils_mkdir_r(path_repository, mode)); + + must_pass(chdir(path_repository)); + + must_pass(git_repository_init(&repo, "../d/e.git", 1)); + must_pass(git__suffixcmp(repo->path_repository, "/a/b/d/e.git/")); + + git_repository_free(repo); + + must_pass(git_repository_open(&repo, "../d/e.git")); + + git_repository_free(repo); + + must_pass(chdir(current_workdir)); + must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); +END_TEST +#endif diff --git a/tests-clay/repo/open.c b/tests-clay/repo/open.c new file mode 100644 index 000000000..235af1447 --- /dev/null +++ b/tests-clay/repo/open.c @@ -0,0 +1,54 @@ +#include "clay_libgit2.h" +#include "posix.h" + +void test_repo_open__bare_empty_repo(void) +{ + git_repository *repo; + + cl_git_pass(git_repository_open(&repo, cl_fixture("empty_bare.git"))); + cl_assert(git_repository_path(repo) != NULL); + cl_assert(git_repository_workdir(repo) == NULL); + + git_repository_free(repo); +} + +void test_repo_open__standard_empty_repo(void) +{ + git_repository *repo; + + cl_git_pass(git_repository_open(&repo, cl_fixture("empty_standard_repo/.gitted"))); + cl_assert(git_repository_path(repo) != NULL); + cl_assert(git_repository_workdir(repo) != NULL); + + git_repository_free(repo); +} + +/* TODO TODO */ +#if 0 +BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of the current working directory") + char new_current_workdir[GIT_PATH_MAX]; + char current_workdir[GIT_PATH_MAX]; + char path_repository[GIT_PATH_MAX]; + + const mode_t mode = 0777; + git_repository* repo; + + /* Setup the repository to open */ + must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); + strcpy(path_repository, current_workdir); + git_path_join_n(path_repository, 3, path_repository, TEMP_REPO_FOLDER, "a/d/e.git"); + must_pass(copydir_recurs(REPOSITORY_FOLDER, path_repository)); + + /* Change the current working directory */ + git_path_join(new_current_workdir, TEMP_REPO_FOLDER, "a/b/c/"); + must_pass(git_futils_mkdir_r(new_current_workdir, mode)); + must_pass(chdir(new_current_workdir)); + + must_pass(git_repository_open(&repo, "../../d/e.git")); + + git_repository_free(repo); + + must_pass(chdir(current_workdir)); + must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); +END_TEST +#endif diff --git a/tests/resources/bad_tag.git/refs/dummy-marker.txt b/tests/resources/bad_tag.git/refs/dummy-marker.txt new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/tests/resources/bad_tag.git/refs/dummy-marker.txt diff --git a/tests/t02-objread.c b/tests/t02-objread.c deleted file mode 100644 index 4bcff2742..000000000 --- a/tests/t02-objread.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "test_lib.h" -#include "test_helpers.h" -#include "odb.h" - -#include "t02-data.h" -#include "t02-oids.h" - - -BEGIN_TEST(existsloose0, "check if a loose object exists on the odb") - git_odb *db; - git_oid id, id2; - - must_pass(write_object_files(odb_dir, &one)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, one.id)); - - must_be_true(git_odb_exists(db, &id)); - - /* Test for a non-existant object */ - must_pass(git_oid_fromstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa")); - must_be_true(0 == git_odb_exists(db, &id2)); - - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &one)); -END_TEST - -BEGIN_TEST(readloose0, "read a loose commit") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &commit)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, commit.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects((git_rawobj *)&obj->raw, &commit)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &commit)); -END_TEST - -BEGIN_TEST(readloose1, "read a loose tree") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &tree)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, tree.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects((git_rawobj *)&obj->raw, &tree)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &tree)); -END_TEST - -BEGIN_TEST(readloose2, "read a loose tag") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &tag)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, tag.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects((git_rawobj *)&obj->raw, &tag)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &tag)); -END_TEST - -BEGIN_TEST(readloose3, "read a loose zero-bytes object") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &zero)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, zero.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects((git_rawobj *)&obj->raw, &zero)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &zero)); -END_TEST - -BEGIN_TEST(readloose4, "read a one-byte long loose object") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &one)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, one.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects(&obj->raw, &one)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &one)); -END_TEST - -BEGIN_TEST(readloose5, "read a two-bytes long loose object") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &two)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, two.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects(&obj->raw, &two)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &two)); -END_TEST - -BEGIN_TEST(readloose6, "read a loose object which is several bytes long") - git_odb *db; - git_oid id; - git_odb_object *obj; - - must_pass(write_object_files(odb_dir, &some)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_fromstr(&id, some.id)); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(cmp_objects(&obj->raw, &some)); - - git_odb_object_close(obj); - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &some)); -END_TEST - -BEGIN_TEST(readpack0, "read several packed objects") - unsigned int i; - git_odb *db; - - must_pass(git_odb_open(&db, ODB_FOLDER)); - - for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { - git_oid id; - git_odb_object *obj; - - must_pass(git_oid_fromstr(&id, packed_objects[i])); - must_be_true(git_odb_exists(db, &id) == 1); - must_pass(git_odb_read(&obj, db, &id)); - - git_odb_object_close(obj); - } - - git_odb_close(db); -END_TEST - -BEGIN_TEST(readheader0, "read only the header of several packed objects") - unsigned int i; - git_odb *db; - - must_pass(git_odb_open(&db, ODB_FOLDER)); - - for (i = 0; i < ARRAY_SIZE(packed_objects); ++i) { - git_oid id; - git_odb_object *obj; - size_t len; - git_otype type; - - must_pass(git_oid_fromstr(&id, packed_objects[i])); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(git_odb_read_header(&len, &type, db, &id)); - - must_be_true(obj->raw.len == len); - must_be_true(obj->raw.type == type); - - git_odb_object_close(obj); - } - - git_odb_close(db); -END_TEST - -BEGIN_TEST(readheader1, "read only the header of several loose objects") - unsigned int i; - git_odb *db; - - must_pass(git_odb_open(&db, ODB_FOLDER)); - - for (i = 0; i < ARRAY_SIZE(loose_objects); ++i) { - git_oid id; - git_odb_object *obj; - size_t len; - git_otype type; - - must_pass(git_oid_fromstr(&id, loose_objects[i])); - - must_be_true(git_odb_exists(db, &id) == 1); - - must_pass(git_odb_read(&obj, db, &id)); - must_pass(git_odb_read_header(&len, &type, db, &id)); - - must_be_true(obj->raw.len == len); - must_be_true(obj->raw.type == type); - - git_odb_object_close(obj); - } - - git_odb_close(db); -END_TEST - -BEGIN_SUITE(objread) - ADD_TEST(existsloose0); - - ADD_TEST(readloose0); - ADD_TEST(readloose1); - ADD_TEST(readloose2); - ADD_TEST(readloose3); - ADD_TEST(readloose4); - ADD_TEST(readloose5); - ADD_TEST(readloose6); - -/* - ADD_TEST(readloose_enc0); - ADD_TEST(readloose_enc1); - ADD_TEST(readloose_enc2); - ADD_TEST(readloose_enc3); - ADD_TEST(readloose_enc4); - ADD_TEST(readloose_enc5); - ADD_TEST(readloose_enc6); -*/ - - ADD_TEST(readpack0); - - ADD_TEST(readheader0); - ADD_TEST(readheader1); -END_SUITE diff --git a/tests/t03-objwrite.c b/tests/t03-objwrite.c index 7563d0e3a..1fc0cac5e 100644 --- a/tests/t03-objwrite.c +++ b/tests/t03-objwrite.c @@ -113,8 +113,8 @@ BEGIN_TEST(write0, "write loose commit object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &commit_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&commit)); END_TEST @@ -134,8 +134,8 @@ BEGIN_TEST(write1, "write loose tree object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &tree_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&tree)); END_TEST @@ -155,8 +155,8 @@ BEGIN_TEST(write2, "write loose tag object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &tag_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&tag)); END_TEST @@ -176,8 +176,8 @@ BEGIN_TEST(write3, "write zero-length object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &zero_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&zero)); END_TEST @@ -197,8 +197,8 @@ BEGIN_TEST(write4, "write one-byte long object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &one_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&one)); END_TEST @@ -218,8 +218,8 @@ BEGIN_TEST(write5, "write two-byte long object") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &two_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&two)); END_TEST @@ -239,8 +239,8 @@ BEGIN_TEST(write6, "write an object which is several bytes long") must_pass(git_odb_read(&obj, db, &id1)); must_pass(cmp_objects(&obj->raw, &some_obj)); - git_odb_object_close(obj); - git_odb_close(db); + git_odb_object_free(obj); + git_odb_free(db); must_pass(remove_object_files(&some)); END_TEST diff --git a/tests/t04-commit.c b/tests/t04-commit.c index d0bb1b583..a0e6037e4 100644 --- a/tests/t04-commit.c +++ b/tests/t04-commit.c @@ -609,18 +609,18 @@ BEGIN_TEST(details0, "query the details on a parsed commit") must_be_true(parents <= 2); for (p = 0;p < parents;p++) { if (old_parent != NULL) - git_commit_close(old_parent); + git_commit_free(old_parent); old_parent = parent; must_pass(git_commit_parent(&parent, commit, p)); must_be_true(parent != NULL); must_be_true(git_commit_author(parent) != NULL); // is it really a commit? } - git_commit_close(old_parent); - git_commit_close(parent); + git_commit_free(old_parent); + git_commit_free(parent); must_fail(git_commit_parent(&parent, commit, parents)); - git_commit_close(commit); + git_commit_free(commit); } git_repository_free(repo); @@ -665,8 +665,8 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk") tree, 1, parent)); - git_object_close((git_object *)parent); - git_object_close((git_object *)tree); + git_object_free((git_object *)parent); + git_object_free((git_object *)tree); git_signature_free(committer); git_signature_free(author); @@ -696,7 +696,7 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk") must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); - git_commit_close(commit); + git_commit_free(commit); git_repository_free(repo); END_TEST @@ -742,7 +742,7 @@ BEGIN_TEST(root0, "create a root commit") tree, 0)); - git_object_close((git_object *)tree); + git_object_free((git_object *)tree); git_signature_free(committer); git_signature_free(author); @@ -764,7 +764,7 @@ BEGIN_TEST(root0, "create a root commit") must_pass(git_reference_delete(branch)); must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); git__free(head_old); - git_commit_close(commit); + git_commit_free(commit); git_repository_free(repo); git_reference_free(head); diff --git a/tests/t08-tag.c b/tests/t08-tag.c index 44efb584d..47d7be840 100644 --- a/tests/t08-tag.c +++ b/tests/t08-tag.c @@ -60,9 +60,9 @@ BEGIN_TEST(read0, "read and parse a tag from the repository") must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); - git_tag_close(tag1); - git_tag_close(tag2); - git_commit_close(commit); + git_tag_free(tag1); + git_tag_free(tag2); + git_commit_free(commit); git_repository_free(repo); END_TEST @@ -133,8 +133,8 @@ BEGIN_TEST(read3, "read and parse a tag without a tagger field") must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); - git_tag_close(bad_tag); - git_commit_close(commit); + git_tag_free(bad_tag); + git_commit_free(commit); git_repository_free(repo); END_TEST @@ -170,7 +170,7 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") TAGGER_MESSAGE, 0)); - git_object_close(target); + git_object_free(target); git_signature_free(tagger); must_pass(git_tag_lookup(&tag, repo, &tag_id)); @@ -195,7 +195,7 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag)); - git_tag_close(tag); + git_tag_free(tag); git_repository_free(repo); END_TEST @@ -222,7 +222,7 @@ BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already TAGGER_MESSAGE, 0)); - git_object_close(target); + git_object_free(target); git_signature_free(tagger); git_repository_free(repo); @@ -256,7 +256,7 @@ BEGIN_TEST(write3, "Replace an already existing tag") TAGGER_MESSAGE, 1)); - git_object_close(target); + git_object_free(target); git_signature_free(tagger); must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b")); @@ -286,7 +286,7 @@ BEGIN_TEST(write4, "write a lightweight tag to the repository and read it again" target, 0)); - git_object_close(target); + git_object_free(target); must_be_true(git_oid_cmp(&object_id, &target_id) == 0); @@ -320,7 +320,7 @@ BEGIN_TEST(write5, "Attempt to write a lightweight tag bearing the same name tha git_oid_fromstr(&existing_object_id, tag2_id); must_be_true(git_oid_cmp(&object_id, &existing_object_id) == 0); - git_object_close(target); + git_object_free(target); git_repository_free(repo); END_TEST diff --git a/tests/t09-tree.c b/tests/t09-tree.c index 2341a1ca4..8995b45ef 100644 --- a/tests/t09-tree.c +++ b/tests/t09-tree.c @@ -53,13 +53,13 @@ static int print_tree(git_repository *repo, const git_oid *tree_oid, int depth) if (entry->attr == S_IFDIR) { if (print_tree(repo, &entry->oid, depth + 1) < GIT_SUCCESS) { - git_tree_close(tree); + git_tree_free(tree); return GIT_ERROR; } } } - git_tree_close(tree); + git_tree_free(tree); return GIT_SUCCESS; } #endif @@ -83,7 +83,7 @@ BEGIN_TEST(read0, "acces randomly the entries on a loaded tree") must_be_true(git_tree_entry_byindex(tree, 3) == NULL); must_be_true(git_tree_entry_byindex(tree, (unsigned int)-1) == NULL); - git_tree_close(tree); + git_tree_free(tree); git_repository_free(repo); END_TEST @@ -105,7 +105,7 @@ BEGIN_TEST(read1, "read a tree from the repository") /* GH-86: git_object_lookup() should also check the type if the object comes from the cache */ must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_TREE) == 0); must_be_true(obj != NULL); - git_object_close(obj); + git_object_free(obj); obj = NULL; must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_BLOB) == GIT_EINVALIDTYPE); must_be_true(obj == NULL); @@ -118,8 +118,8 @@ BEGIN_TEST(read1, "read a tree from the repository") must_pass(git_tree_entry_2object(&obj, repo, entry)); must_be_true(obj != NULL); - git_object_close(obj); - git_tree_close(tree); + git_object_free(obj); + git_tree_free(tree); git_repository_free(repo); END_TEST @@ -164,7 +164,7 @@ BEGIN_TEST(write2, "write a tree from a memory") must_be_true(git_oid_cmp(&rid, &id2) == 0); git_treebuilder_free(builder); - git_tree_close(tree); + git_tree_free(tree); close_temp_repo(repo); END_TEST @@ -193,7 +193,7 @@ BEGIN_TEST(write3, "write a hierarchical tree from a memory") must_pass(git_treebuilder_insert(NULL,builder,"new",&subtree_id,040000)); must_pass(git_treebuilder_write(&id_hiearar,repo,builder)); git_treebuilder_free(builder); - git_tree_close(tree); + git_tree_free(tree); must_be_true(git_oid_cmp(&id_hiearar, &id3) == 0); @@ -204,7 +204,7 @@ BEGIN_TEST(write3, "write a hierarchical tree from a memory") must_be_true((loose_object_dir_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_DIR_MODE); must_be_true((loose_object_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_FILE_MODE); #endif - git_tree_close(tree); + git_tree_free(tree); close_temp_repo(repo); diff --git a/tests/t10-refs.c b/tests/t10-refs.c index e5e722992..b00ccfac6 100644 --- a/tests/t10-refs.c +++ b/tests/t10-refs.c @@ -54,7 +54,7 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") git_path_join(ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object)); must_be_true(strcmp(ref_name_from_tag_name, loose_tag_ref_name) == 0); - git_object_close(object); + git_object_free(object); git_repository_free(repo); git_reference_free(reference); @@ -99,7 +99,7 @@ BEGIN_TEST(readsym0, "lookup a symbolic reference") git_oid_fromstr(&id, current_master_tip); must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0); - git_object_close(object); + git_object_free(object); git_repository_free(repo); git_reference_free(reference); @@ -129,7 +129,7 @@ BEGIN_TEST(readsym1, "lookup a nested symbolic reference") git_oid_fromstr(&id, current_master_tip); must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0); - git_object_close(object); + git_object_free(object); git_repository_free(repo); git_reference_free(reference); @@ -200,7 +200,7 @@ BEGIN_TEST(readpacked0, "lookup a packed reference") must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); - git_object_close(object); + git_object_free(object); git_repository_free(repo); git_reference_free(reference); diff --git a/tests/t12-repo.c b/tests/t12-repo.c index 47dc852f3..acf8b743d 100644 --- a/tests/t12-repo.c +++ b/tests/t12-repo.c @@ -29,288 +29,8 @@ #include "git2/odb_backend.h" #include "repository.h" -typedef struct { - git_odb_backend base; - int position; -} fake_backend; - -static git_odb_backend *new_backend(int position) -{ - fake_backend *b; - - b = git__malloc(sizeof(fake_backend)); - if (b == NULL) - return NULL; - - memset(b, 0x0, sizeof(fake_backend)); - b->position = position; - return (git_odb_backend *)b; -} - -static int test_backend_sorting(git_odb *odb) -{ - unsigned int i; - - for (i = 0; i < odb->backends.length; ++i) { - fake_backend *internal = *((fake_backend **)git_vector_get(&odb->backends, i)); - - if (internal == NULL) - return GIT_ERROR; - - if (internal->position != (int)i) - return GIT_ERROR; - } - - return GIT_SUCCESS; -} - -BEGIN_TEST(odb0, "assure that ODB backends are properly sorted") - git_odb *odb; - must_pass(git_odb_new(&odb)); - must_pass(git_odb_add_backend(odb, new_backend(0), 5)); - must_pass(git_odb_add_backend(odb, new_backend(2), 3)); - must_pass(git_odb_add_backend(odb, new_backend(1), 4)); - must_pass(git_odb_add_backend(odb, new_backend(3), 1)); - must_pass(test_backend_sorting(odb)); - git_odb_close(odb); -END_TEST - -BEGIN_TEST(odb1, "assure that alternate backends are properly sorted") - git_odb *odb; - must_pass(git_odb_new(&odb)); - must_pass(git_odb_add_backend(odb, new_backend(0), 5)); - must_pass(git_odb_add_backend(odb, new_backend(2), 3)); - must_pass(git_odb_add_backend(odb, new_backend(1), 4)); - must_pass(git_odb_add_backend(odb, new_backend(3), 1)); - must_pass(git_odb_add_alternate(odb, new_backend(4), 5)); - must_pass(git_odb_add_alternate(odb, new_backend(6), 3)); - must_pass(git_odb_add_alternate(odb, new_backend(5), 4)); - must_pass(git_odb_add_alternate(odb, new_backend(7), 1)); - must_pass(test_backend_sorting(odb)); - git_odb_close(odb); -END_TEST - - -#define STANDARD_REPOSITORY 0 -#define BARE_REPOSITORY 1 - -static int ensure_repository_init( - const char *working_directory, - int repository_kind, - const char *expected_path_index, - const char *expected_path_repository, - const char *expected_working_directory) -{ - char path_odb[GIT_PATH_MAX]; - git_repository *repo; - - if (git_futils_isdir(working_directory) == GIT_SUCCESS) - return GIT_ERROR; - - git_path_join(path_odb, expected_path_repository, GIT_OBJECTS_DIR); - - if (git_repository_init(&repo, working_directory, repository_kind) < GIT_SUCCESS) - return GIT_ERROR; - - if (repo->path_workdir != NULL || expected_working_directory != NULL) { - if (git__suffixcmp(repo->path_workdir, expected_working_directory) != 0) - goto cleanup; - } - - if (git__suffixcmp(repo->path_odb, path_odb) != 0) - goto cleanup; - - if (git__suffixcmp(repo->path_repository, expected_path_repository) != 0) - goto cleanup; - - if (repo->path_index != NULL || expected_path_index != NULL) { - if (git__suffixcmp(repo->path_index, expected_path_index) != 0) - goto cleanup; - -#ifdef GIT_WIN32 - if ((GetFileAttributes(repo->path_repository) & FILE_ATTRIBUTE_HIDDEN) == 0) - goto cleanup; -#endif - - if (git_repository_is_bare(repo) == 1) - goto cleanup; - } else if (git_repository_is_bare(repo) == 0) - goto cleanup; - - if (git_repository_is_empty(repo) == 0) - goto cleanup; - - git_repository_free(repo); - git_futils_rmdir_r(working_directory, 1); - - return GIT_SUCCESS; - -cleanup: - git_repository_free(repo); - git_futils_rmdir_r(working_directory, 1); - return GIT_ERROR; -} - -BEGIN_TEST(init0, "initialize a standard repo") - char path_index[GIT_PATH_MAX], path_repository[GIT_PATH_MAX]; - - git_path_join(path_repository, TEMP_REPO_FOLDER, GIT_DIR); - git_path_join(path_index, path_repository, GIT_INDEX_FILE); - - must_pass(ensure_repository_init(TEMP_REPO_FOLDER, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER)); - must_pass(ensure_repository_init(TEMP_REPO_FOLDER_NS, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER)); -END_TEST - -BEGIN_TEST(init1, "initialize a bare repo") - char path_repository[GIT_PATH_MAX]; - - git_path_join(path_repository, TEMP_REPO_FOLDER, ""); - - must_pass(ensure_repository_init(TEMP_REPO_FOLDER, BARE_REPOSITORY, NULL, path_repository, NULL)); - must_pass(ensure_repository_init(TEMP_REPO_FOLDER_NS, BARE_REPOSITORY, NULL, path_repository, NULL)); -END_TEST - -BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory") - char path_repository[GIT_PATH_MAX]; - char current_workdir[GIT_PATH_MAX]; - const mode_t mode = 0777; - git_repository* repo; - - must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); - - git_path_join(path_repository, TEMP_REPO_FOLDER, "a/b/c/"); - must_pass(git_futils_mkdir_r(path_repository, mode)); - - must_pass(chdir(path_repository)); - - must_pass(git_repository_init(&repo, "../d/e.git", 1)); - must_pass(git__suffixcmp(repo->path_repository, "/a/b/d/e.git/")); - - git_repository_free(repo); - - must_pass(git_repository_open(&repo, "../d/e.git")); - - git_repository_free(repo); - - must_pass(chdir(current_workdir)); - must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); -END_TEST - #define EMPTY_BARE_REPOSITORY_FOLDER TEST_RESOURCES "/empty_bare.git/" -BEGIN_TEST(open0, "Open a bare repository that has just been initialized by git") - git_repository *repo; - - must_pass(copydir_recurs(EMPTY_BARE_REPOSITORY_FOLDER, TEMP_REPO_FOLDER)); - must_pass(remove_placeholders(TEMP_REPO_FOLDER, "dummy-marker.txt")); - - must_pass(git_repository_open(&repo, TEMP_REPO_FOLDER)); - must_be_true(git_repository_path(repo, GIT_REPO_PATH) != NULL); - must_be_true(git_repository_path(repo, GIT_REPO_PATH_WORKDIR) == NULL); - - git_repository_free(repo); - must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); -END_TEST - -BEGIN_TEST(open1, "Open a standard repository that has just been initialized by git") - git_repository *repo; - - must_pass(copydir_recurs(EMPTY_REPOSITORY_FOLDER, TEST_STD_REPO_FOLDER)); - must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt")); - - must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER)); - must_be_true(git_repository_path(repo, GIT_REPO_PATH) != NULL); - must_be_true(git_repository_path(repo, GIT_REPO_PATH_WORKDIR) != NULL); - - git_repository_free(repo); - must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); -END_TEST - - -BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of the current working directory") - char new_current_workdir[GIT_PATH_MAX]; - char current_workdir[GIT_PATH_MAX]; - char path_repository[GIT_PATH_MAX]; - - const mode_t mode = 0777; - git_repository* repo; - - /* Setup the repository to open */ - must_pass(p_getcwd(current_workdir, sizeof(current_workdir))); - strcpy(path_repository, current_workdir); - git_path_join_n(path_repository, 3, path_repository, TEMP_REPO_FOLDER, "a/d/e.git"); - must_pass(copydir_recurs(REPOSITORY_FOLDER, path_repository)); - - /* Change the current working directory */ - git_path_join(new_current_workdir, TEMP_REPO_FOLDER, "a/b/c/"); - must_pass(git_futils_mkdir_r(new_current_workdir, mode)); - must_pass(chdir(new_current_workdir)); - - must_pass(git_repository_open(&repo, "../../d/e.git")); - - git_repository_free(repo); - - must_pass(chdir(current_workdir)); - must_pass(git_futils_rmdir_r(TEMP_REPO_FOLDER, 1)); -END_TEST - -BEGIN_TEST(empty0, "test if a repository is empty or not") - - git_repository *repo_empty, *repo_normal; - - must_pass(git_repository_open(&repo_normal, REPOSITORY_FOLDER)); - must_be_true(git_repository_is_empty(repo_normal) == 0); - git_repository_free(repo_normal); - - must_pass(git_repository_open(&repo_empty, EMPTY_BARE_REPOSITORY_FOLDER)); - must_be_true(git_repository_is_empty(repo_empty) == 1); - git_repository_free(repo_empty); -END_TEST - -BEGIN_TEST(detached0, "test if HEAD is detached") - git_repository *repo; - git_reference *ref; - git_oid oid; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - - must_be_true(git_repository_head_detached(repo) == 0); - - /* detach the HEAD */ - git_oid_fromstr(&oid, "c47800c7266a2be04c571c04d5a6614691ea99bd"); - must_pass(git_reference_create_oid(&ref, repo, "HEAD", &oid, 1)); - must_be_true(git_repository_head_detached(repo) == 1); - - /* take the reop back to it's original state */ - must_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/master", 1)); - must_be_true(git_repository_head_detached(repo) == 0); - - git_repository_free(repo); - - git_reference_free(ref); -END_TEST - -BEGIN_TEST(orphan0, "test if HEAD is orphan") - git_repository *repo; - git_reference *ref; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - - must_be_true(git_repository_head_orphan(repo) == 0); - - /* orphan HEAD */ - must_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/orphan", 1)); - must_be_true(git_repository_head_orphan(repo) == 1); - - /* take the reop back to it's original state */ - must_pass(git_reference_create_symbolic(&ref, repo, "HEAD", "refs/heads/master", 1)); - must_be_true(git_repository_head_orphan(repo) == 0); - - git_repository_free(repo); - - git_reference_free(ref); -END_TEST - #define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git" #define SUB_REPOSITORY_FOLDER_NAME "sub_repo" @@ -449,17 +169,6 @@ BEGIN_TEST(discover0, "test discover") END_TEST BEGIN_SUITE(repository) - ADD_TEST(odb0); - ADD_TEST(odb1); - ADD_TEST(init0); - ADD_TEST(init1); - ADD_TEST(init2); - ADD_TEST(open0); - ADD_TEST(open1); - ADD_TEST(open2); - ADD_TEST(empty0); - ADD_TEST(detached0); - ADD_TEST(orphan0); ADD_TEST(discover0); END_SUITE diff --git a/tests/t15-config.c b/tests/t15-config.c deleted file mode 100644 index 9f0deb3e3..000000000 --- a/tests/t15-config.c +++ /dev/null @@ -1,358 +0,0 @@ -/* - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "test_lib.h" -#include "test_helpers.h" - -#include <git2.h> -#include <posix.h> -#include "filebuf.h" - -#define CONFIG_BASE TEST_RESOURCES "/config" -#define GLOBAL_CONFIG CONFIG_BASE "/.gitconfig" - -/* - * This one is so we know the code isn't completely broken - */ -BEGIN_TEST(config0, "read a simple configuration") - git_config *cfg; - int32_t i; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config0")); - must_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &i)); - must_be_true(i == 0); - must_pass(git_config_get_bool(cfg, "core.filemode", &i)); - must_be_true(i == 1); - must_pass(git_config_get_bool(cfg, "core.bare", &i)); - must_be_true(i == 0); - must_pass(git_config_get_bool(cfg, "core.logallrefupdates", &i)); - must_be_true(i == 1); - - git_config_free(cfg); -END_TEST - -/* - * [this "that"] and [this "That] are different namespaces. Make sure - * each returns the correct one. - */ -BEGIN_TEST(config1, "case sensitivity") - git_config *cfg; - int i; - const char *str; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config1")); - - must_pass(git_config_get_string(cfg, "this.that.other", &str)); - must_be_true(!strcmp(str, "true")); - must_pass(git_config_get_string(cfg, "this.That.other", &str)); - must_be_true(!strcmp(str, "yes")); - - must_pass(git_config_get_bool(cfg, "this.that.other", &i)); - must_be_true(i == 1); - must_pass(git_config_get_bool(cfg, "this.That.other", &i)); - must_be_true(i == 1); - - /* This one doesn't exist */ - must_fail(git_config_get_bool(cfg, "this.thaT.other", &i)); - - git_config_free(cfg); -END_TEST - -/* - * If \ is the last non-space character on the line, we read the next - * one, separating each line with SP. - */ -BEGIN_TEST(config2, "parse a multiline value") - git_config *cfg; - const char *str; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config2")); - - must_pass(git_config_get_string(cfg, "this.That.and", &str)); - must_be_true(!strcmp(str, "one one one two two three three")); - - git_config_free(cfg); -END_TEST - -/* - * This kind of subsection declaration is case-insensitive - */ -BEGIN_TEST(config3, "parse a [section.subsection] header") - git_config *cfg; - const char *str; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config3")); - - must_pass(git_config_get_string(cfg, "section.subsection.var", &str)); - must_be_true(!strcmp(str, "hello")); - - /* The subsection is transformed to lower-case */ - must_fail(git_config_get_string(cfg, "section.subSectIon.var", &str)); - - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config4, "a variable name on its own is valid") - git_config *cfg; -const char *str; -int i; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config4")); - - must_pass(git_config_get_string(cfg, "some.section.variable", &str)); - must_be_true(str == NULL); - - must_pass(git_config_get_bool(cfg, "some.section.variable", &i)); - must_be_true(i == 1); - - - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config5, "test number suffixes") - git_config *cfg; - int64_t i; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config5")); - - must_pass(git_config_get_int64(cfg, "number.simple", &i)); - must_be_true(i == 1); - - must_pass(git_config_get_int64(cfg, "number.k", &i)); - must_be_true(i == 1 * 1024); - - must_pass(git_config_get_int64(cfg, "number.kk", &i)); - must_be_true(i == 1 * 1024); - - must_pass(git_config_get_int64(cfg, "number.m", &i)); - must_be_true(i == 1 * 1024 * 1024); - - must_pass(git_config_get_int64(cfg, "number.mm", &i)); - must_be_true(i == 1 * 1024 * 1024); - - must_pass(git_config_get_int64(cfg, "number.g", &i)); - must_be_true(i == 1 * 1024 * 1024 * 1024); - - must_pass(git_config_get_int64(cfg, "number.gg", &i)); - must_be_true(i == 1 * 1024 * 1024 * 1024); - - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config6, "test blank lines") - git_config *cfg; - int i; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config6")); - - must_pass(git_config_get_bool(cfg, "valid.subsection.something", &i)); - must_be_true(i == 1); - - must_pass(git_config_get_bool(cfg, "something.else.something", &i)); - must_be_true(i == 0); - - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config7, "test for invalid ext headers") - git_config *cfg; - - must_fail(git_config_open_ondisk(&cfg, CONFIG_BASE "/config7")); - -END_TEST - -BEGIN_TEST(config8, "don't fail on empty files") - git_config *cfg; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config8")); - - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config9, "replace a value") - git_config *cfg; - int i; - int64_t l, expected = +9223372036854775803; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_set_int32(cfg, "core.dummy", 5)); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_get_int32(cfg, "core.dummy", &i)); - must_be_true(i == 5); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_set_int32(cfg, "core.dummy", 1)); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_set_int64(cfg, "core.verylong", expected)); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_get_int64(cfg, "core.verylong", &l)); - must_be_true(l == expected); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_fail(git_config_get_int32(cfg, "core.verylong", &i)); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_set_int64(cfg, "core.verylong", 1)); - git_config_free(cfg); - -END_TEST - -BEGIN_TEST(config10, "a repo's config overrides the global config") - git_repository *repo; - git_config *cfg; - int32_t version; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL)); - must_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &version)); - must_be_true(version == 0); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_TEST(config11, "fall back to the global config") - git_repository *repo; - git_config *cfg; - int32_t num; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, GLOBAL_CONFIG, NULL)); - must_pass(git_config_get_int32(cfg, "core.something", &num)); - must_be_true(num == 2); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_TEST(config12, "delete a value") - git_config *cfg; - int32_t i; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_set_int32(cfg, "core.dummy", 5)); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_delete(cfg, "core.dummy")); - git_config_free(cfg); - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_be_true(git_config_get_int32(cfg, "core.dummy", &i) == GIT_ENOTFOUND); - must_pass(git_config_set_int32(cfg, "core.dummy", 1)); - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config13, "can't delete a non-existent value") - git_config *cfg; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_be_true(git_config_delete(cfg, "core.imaginary") == GIT_ENOTFOUND); - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config14, "don't fail horribly if a section header is in the last line") - git_config *cfg; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config10")); - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config15, "add a variable in an existing section") - git_config *cfg; - int32_t i; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config10")); - must_pass(git_config_set_int32(cfg, "empty.tmp", 5)); - must_pass(git_config_get_int32(cfg, "empty.tmp", &i)); - must_be_true(i == 5); - must_pass(git_config_delete(cfg, "empty.tmp")); - git_config_free(cfg); -END_TEST - -BEGIN_TEST(config16, "add a variable in a new section") - git_config *cfg; - int32_t i; - git_filebuf buf = GIT_FILEBUF_INIT; - - /* By freeing the config, we make sure we flush the values */ - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config10")); - must_pass(git_config_set_int32(cfg, "section.tmp", 5)); - must_pass(git_config_get_int32(cfg, "section.tmp", &i)); - must_be_true(i == 5); - must_pass(git_config_delete(cfg, "section.tmp")); - git_config_free(cfg); - - /* As the section wasn't removed, owerwrite the file */ - must_pass(git_filebuf_open(&buf, CONFIG_BASE "/config10", 0)); - must_pass(git_filebuf_write(&buf, "[empty]\n", strlen("[empty]\n"))); - must_pass(git_filebuf_commit(&buf, 0666)); -END_TEST - -BEGIN_TEST(config17, "prefixes aren't broken") - git_config *cfg; - const char *str; - - must_pass(git_config_open_ondisk(&cfg, CONFIG_BASE "/config9")); - must_pass(git_config_get_string(cfg, "remote.ab.url", &str)); - must_be_true(strcmp(str, "http://example.com/git/ab") == 0); - - must_pass(git_config_get_string(cfg, "remote.abba.url", &str)); - must_be_true(strcmp(str, "http://example.com/git/abba") == 0); - - git_config_free(cfg); -END_TEST - -BEGIN_SUITE(config) - ADD_TEST(config0); - ADD_TEST(config1); - ADD_TEST(config2); - ADD_TEST(config3); - ADD_TEST(config4); - ADD_TEST(config5); - ADD_TEST(config6); - ADD_TEST(config7); - ADD_TEST(config8); - ADD_TEST(config9); - ADD_TEST(config10); - ADD_TEST(config11); - ADD_TEST(config12); - ADD_TEST(config13); - ADD_TEST(config14); - ADD_TEST(config15); - ADD_TEST(config16); - ADD_TEST(config17); -END_SUITE diff --git a/tests/t16-remotes.c b/tests/t16-remotes.c deleted file mode 100644 index ac98bdf5e..000000000 --- a/tests/t16-remotes.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * This file is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License, version 2, - * as published by the Free Software Foundation. - * - * In addition to the permissions in the GNU General Public License, - * the authors give you unlimited permission to link the compiled - * version of this file into combinations with other programs, - * and to distribute those combinations without any restriction - * coming from the use of this file. (The General Public License - * restrictions do apply in other respects; for example, they cover - * modification of the file, and distribution when not linked into - * a combined executable.) - * - * This file is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; see the file COPYING. If not, write to - * the Free Software Foundation, 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - */ -#include "test_lib.h" -#include "test_helpers.h" - -#include <git2.h> -#include <posix.h> - -BEGIN_TEST(remotes0, "remote parsing works") - git_remote *remote; - git_repository *repo; - git_config *cfg; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, NULL, NULL)); - must_pass(git_remote_get(&remote, cfg, "test")); - must_be_true(!strcmp(git_remote_name(remote), "test")); - must_be_true(!strcmp(git_remote_url(remote), "git://github.com/libgit2/libgit2")); - - git_remote_free(remote); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_TEST(refspec0, "remote with refspec works") - git_remote *remote; - git_repository *repo; - git_config *cfg; - const git_refspec *refspec = NULL; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, NULL, NULL)); - must_pass(git_remote_get(&remote, cfg, "test")); - refspec = git_remote_fetchspec(remote); - must_be_true(refspec != NULL); - must_be_true(!strcmp(git_refspec_src(refspec), "refs/heads/*")); - must_be_true(!strcmp(git_refspec_dst(refspec), "refs/remotes/test/*")); - git_remote_free(remote); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_TEST(refspec1, "remote fnmatch works as expected") - git_remote *remote; - git_repository *repo; - git_config *cfg; - const git_refspec *refspec = NULL; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, NULL, NULL)); - must_pass(git_remote_get(&remote, cfg, "test")); - refspec = git_remote_fetchspec(remote); - must_be_true(refspec != NULL); - must_pass(git_refspec_src_match(refspec, "refs/heads/master")); - must_pass(git_refspec_src_match(refspec, "refs/heads/multi/level/branch")); - git_remote_free(remote); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_TEST(refspec2, "refspec transform") - git_remote *remote; - git_repository *repo; - git_config *cfg; - const git_refspec *refspec = NULL; - char ref[1024] = {0}; - - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_config(&cfg, repo, NULL, NULL)); - must_pass(git_remote_get(&remote, cfg, "test")); - refspec = git_remote_fetchspec(remote); - must_be_true(refspec != NULL); - must_pass(git_refspec_transform(ref, sizeof(ref), refspec, "refs/heads/master")); - must_be_true(!strcmp(ref, "refs/remotes/test/master")); - git_remote_free(remote); - git_config_free(cfg); - git_repository_free(repo); -END_TEST - -BEGIN_SUITE(remotes) - ADD_TEST(remotes0) - ADD_TEST(refspec0) - ADD_TEST(refspec1) - ADD_TEST(refspec2) -END_SUITE diff --git a/tests/test_main.c b/tests/test_main.c index 9961ffd6b..1ebb22299 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -33,7 +33,6 @@ DECLARE_SUITE(core); DECLARE_SUITE(rawobjects); -DECLARE_SUITE(objread); DECLARE_SUITE(objwrite); DECLARE_SUITE(commit); DECLARE_SUITE(revwalk); @@ -44,15 +43,12 @@ DECLARE_SUITE(tree); DECLARE_SUITE(refs); DECLARE_SUITE(repository); DECLARE_SUITE(threads); -DECLARE_SUITE(config); -DECLARE_SUITE(remotes); DECLARE_SUITE(buffers); DECLARE_SUITE(status); static libgit2_suite suite_methods[]= { SUITE_NAME(core), SUITE_NAME(rawobjects), - SUITE_NAME(objread), SUITE_NAME(objwrite), SUITE_NAME(commit), SUITE_NAME(revwalk), @@ -63,8 +59,6 @@ static libgit2_suite suite_methods[]= { SUITE_NAME(refs), SUITE_NAME(repository), SUITE_NAME(threads), - SUITE_NAME(config), - SUITE_NAME(remotes), SUITE_NAME(buffers), SUITE_NAME(status), }; |