diff --git a/.travis.yml b/.travis.yml index b9a08dc59..2713651a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,8 @@ language: erlang # Settings to try env: - OPTIONS="-DTHREADSAFE=ON -DCMAKE_BUILD_TYPE=Release" - - OPTIONS="-DBUILD_CLAR=ON" + - OPTIONS="-DBUILD_CLAR=ON -DBUILD_EXAMPLES=ON" + - CC=i586-mingw32msvc-gcc OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON" # Make sure CMake is installed install: diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc222d5c..8018ea72d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,9 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.") OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF) OPTION (BUILD_CLAR "Build Tests using the Clar suite" ON) +OPTION (BUILD_EXAMPLES "Build library usage example apps" OFF) OPTION (TAGS "Generate tags" OFF) +OPTION (PROFILE "Generate profiling information" OFF) # Platform specific compilation flags IF (MSVC) @@ -71,8 +73,14 @@ IF (MSVC) ELSE () SET(CMAKE_C_FLAGS "-O2 -g -D_GNU_SOURCE -Wall -Wextra -Wno-missing-field-initializers -Wstrict-aliasing=2 -Wstrict-prototypes -Wmissing-prototypes ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS_DEBUG "-O0 -g") - IF (NOT MINGW) # MinGW always does PIC and complains if we tell it to - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC") + IF (MINGW) # MinGW always does PIC and complains if we tell it to + STRING(REGEX REPLACE "-fPIC" "" CMAKE_SHARED_LIBRARY_C_FLAGS "${CMAKE_SHARED_LIBRARY_C_FLAGS}") + ELSE () + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden -fPIC") + ENDIF () + IF (PROFILE) + SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}") + SET(CMAKE_EXE_LINKER_FLAGS "-pg ${CMAKE_EXE_LINKER_FLAGS}") ENDIF () ENDIF() @@ -97,7 +105,9 @@ FILE(GLOB SRC_H include/git2/*.h) # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) ADD_DEFINITIONS(-DWIN32 -D_DEBUG -D_WIN32_WINNT=0x0501) - FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/win32/*.c) + FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/win32/*.c src/compat/*.c) +ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") + FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/unix/*.c src/compat/*.c) ELSE() FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/unix/*.c) ENDIF () @@ -176,3 +186,18 @@ IF (TAGS) DEPENDS tags ) ENDIF () + +IF (BUILD_EXAMPLES) + FILE(GLOB_RECURSE EXAMPLE_SRC examples/network/*.c) + ADD_EXECUTABLE(cgit2 ${EXAMPLE_SRC}) + TARGET_LINK_LIBRARIES(cgit2 git2 pthread) + + ADD_EXECUTABLE(git-diff examples/diff.c) + TARGET_LINK_LIBRARIES(git-diff git2) + + ADD_EXECUTABLE(git-general examples/general.c) + TARGET_LINK_LIBRARIES(git-general git2) + + ADD_EXECUTABLE(git-showindex examples/showindex.c) + TARGET_LINK_LIBRARIES(git-showindex git2) +ENDIF () diff --git a/CONVENTIONS b/CONVENTIONS index 575cdc563..f082d8e6c 100644 --- a/CONVENTIONS +++ b/CONVENTIONS @@ -49,7 +49,7 @@ Functions should prefer to return a 'int' to indicate success or failure and supply any output through the first argument (or first few arguments if multiple outputs are supplied). -int status codes are 0 for GIT_SUCCESS and < 0 for an error. +int status codes are 0 for GIT_OK and < 0 for an error. This permits common POSIX result testing: ---- @@ -58,7 +58,7 @@ This permits common POSIX result testing: ---- Functions returning a pointer may return NULL instead of an int -if there is only one type of failure (ENOMEM). +if there is only one type of failure (GIT_ENOMEM). Functions returning a pointer may also return NULL if the common case needed by the application is strictly success/failure and a diff --git a/Makefile.embed b/Makefile.embed index fb6b01bee..65f13b9b6 100644 --- a/Makefile.embed +++ b/Makefile.embed @@ -6,10 +6,10 @@ LIBNAME=libgit2.a INCLUDES= -I. -Isrc -Iinclude -Ideps/http-parser -Ideps/zlib -DEFINES= $(INCLUDES) -DNO_VIZ -DSTDC -DNO_GZIP -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE -CFLAGS= -g $(DEFINES) -Wall -Wextra -fPIC -O2 +DEFINES= $(INCLUDES) -DNO_VIZ -DSTDC -DNO_GZIP -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(EXTRA_DEFINES) +CFLAGS= -g $(DEFINES) -Wall -Wextra -fPIC -O2 $(EXTRA_CFLAGS) -SRCS = $(wildcard src/*.c) $(wildcard src/transports/*.c) $(wildcard src/unix/*.c) $(wildcard deps/http-parser/*.c) $(wildcard deps/zlib/*.c) +SRCS = $(wildcard src/*.c) $(wildcard src/transports/*.c) $(wildcard src/unix/*.c) $(wildcard src/xdiff/*.c) $(wildcard deps/http-parser/*.c) $(wildcard deps/zlib/*.c) OBJS = $(patsubst %.c,%.o,$(SRCS)) %.c.o: diff --git a/README.md b/README.md index b0c0db194..29b800100 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,9 @@ How Can I Contribute? ================================== Fork libgit2/libgit2 on GitHub, add your improvement, push it to a branch -in your fork named for the topic, send a pull request. +in your fork named for the topic, send a pull request. If you change the +API or make other large changes, make a note of it in docs/rel-notes/ in a +file named after the next release. You can also file bugs or feature requests under the libgit2 project on GitHub, or join us on the mailing list by sending an email to: diff --git a/docs/error-handling.md b/docs/error-handling.md index 04c855fbc..655afeba8 100644 --- a/docs/error-handling.md +++ b/docs/error-handling.md @@ -29,7 +29,7 @@ The simple error API - `void giterr_set(git_error **, int, const char *, ...)`: the main function used to set an error. It allocates a new error object and stores it in the passed error pointer. It has no return value. The arguments for `giterr_set` are as follows: - `git_error **error_ptr`: the pointer where the error will be created. - - `int error_class`: the class for the error. This is **not** an error code: this is an speficic enum that specifies the error family. The point is to map these families 1-1 with Exception types on higher level languages (e.g. GitRepositoryException) + - `int error_class`: the class for the error. This is **not** an error code: this is an specific enum that specifies the error family. The point is to map these families 1-1 with Exception types on higher level languages (e.g. GitRepositoryException) - `const char *error_str, ...`: the error string, with optional formatting arguments - `void giterr_free(git_error *)`: takes an error and frees it. This function is available in the external API. @@ -56,7 +56,7 @@ Here are some guidelines when writing error messages: - Use short, direct and objective messages. **One line, max**. libgit2 is a low level library: think that all the messages reported will be thrown as Ruby or Python exceptions. Think how long are common exception messages in those languages. -- **Do not add redundant information to the error message**, specially information that can be infered from the context. +- **Do not add redundant information to the error message**, specially information that can be inferred from the context. E.g. in `git_repository_open`, do not report a message like "Failed to open repository: path not found". Somebody is calling that function. If it fails, he already knows that the repository failed to open! diff --git a/examples/diff.c b/examples/diff.c index 20e14e511..1b4ab549b 100644 --- a/examples/diff.c +++ b/examples/diff.c @@ -61,7 +61,13 @@ char *colors[] = { "\033[36m" /* cyan */ }; -int printer(void *data, char usage, const char *line) +int printer( + void *data, + git_diff_delta *delta, + git_diff_range *range, + char usage, + const char *line, + size_t line_len) { int *last_color = data, color = 0; diff --git a/examples/general.c b/examples/general.c index 0a908bc48..5269785f2 100644 --- a/examples/general.c +++ b/examples/general.c @@ -273,7 +273,7 @@ int main (int argc, char** argv) // Once you have the entry object, you can access the content or subtree (or commit, in the case // of submodules) that it points to. You can also get the mode if you want. - git_tree_entry_2object(&objt, repo, entry); // blob + git_tree_entry_to_object(&objt, repo, entry); // blob // Remember to close the looked-up object once you are done using it git_object_free(objt); @@ -335,7 +335,7 @@ int main (int argc, char** argv) // We can then lookup and parse the commited pointed at by the returned OID; // note that this operation is specially fast since the raw contents of the commit object will // be cached in memory - while ((git_revwalk_next(&oid, walk)) == GIT_SUCCESS) { + while ((git_revwalk_next(&oid, walk)) == 0) { error = git_commit_lookup(&wcommit, repo, &oid); cmsg = git_commit_message(wcommit); cauth = git_commit_author(wcommit); @@ -392,7 +392,7 @@ int main (int argc, char** argv) // Here we will implement something like `git for-each-ref` simply listing out all available // references and the object SHA they resolve to. git_strarray ref_list; - git_reference_listall(&ref_list, repo, GIT_REF_LISTALL); + git_reference_list(&ref_list, repo, GIT_REF_LISTALL); const char *refname; git_reference *ref; diff --git a/examples/network/fetch.c b/examples/network/fetch.c index f4a044984..8dcb81b1f 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -60,54 +60,54 @@ int update_cb(const char *refname, const git_oid *a, const git_oid *b) int fetch(git_repository *repo, int argc, char **argv) { - git_remote *remote = NULL; - git_off_t bytes = 0; - git_indexer_stats stats; - pthread_t worker; - struct dl_data data; + git_remote *remote = NULL; + git_off_t bytes = 0; + git_indexer_stats stats; + pthread_t worker; + struct dl_data data; - // Figure out whether it's a named remote or a URL - printf("Fetching %s\n", argv[1]); - if (git_remote_load(&remote, repo, argv[1]) < 0) { - if (git_remote_new(&remote, repo, NULL, argv[1], NULL) < 0) - return -1; - } + // Figure out whether it's a named remote or a URL + printf("Fetching %s\n", argv[1]); + if (git_remote_load(&remote, repo, argv[1]) < 0) { + if (git_remote_new(&remote, repo, NULL, argv[1], NULL) < 0) + return -1; + } - // Set up the information for the background worker thread - data.remote = remote; - data.bytes = &bytes; - data.stats = &stats; - data.ret = 0; - data.finished = 0; - memset(&stats, 0, sizeof(stats)); + // Set up the information for the background worker thread + data.remote = remote; + data.bytes = &bytes; + data.stats = &stats; + data.ret = 0; + data.finished = 0; + memset(&stats, 0, sizeof(stats)); - pthread_create(&worker, NULL, download, &data); + pthread_create(&worker, NULL, download, &data); - // Loop while the worker thread is still running. Here we show processed - // and total objects in the pack and the amount of received - // data. Most frontends will probably want to show a percentage and - // the download rate. - do { - usleep(10000); - printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes); - } while (!data.finished); - printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes); + // Loop while the worker thread is still running. Here we show processed + // and total objects in the pack and the amount of received + // data. Most frontends will probably want to show a percentage and + // the download rate. + do { + usleep(10000); + printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes); + } while (!data.finished); + printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes); - // Disconnect the underlying connection to prevent from idling. - git_remote_disconnect(remote); + // Disconnect the underlying connection to prevent from idling. + git_remote_disconnect(remote); - // Update the references in the remote's namespace to point to the - // right commits. This may be needed even if there was no packfile - // to download, which can happen e.g. when the branches have been - // changed but all the neede objects are available locally. - if (git_remote_update_tips(remote, update_cb) < 0) - return -1; + // Update the references in the remote's namespace to point to the + // right commits. This may be needed even if there was no packfile + // to download, which can happen e.g. when the branches have been + // changed but all the neede objects are available locally. + if (git_remote_update_tips(remote, update_cb) < 0) + return -1; - git_remote_free(remote); + git_remote_free(remote); - return 0; + return 0; -on_error: - git_remote_free(remote); - return -1; + on_error: + git_remote_free(remote); + return -1; } diff --git a/examples/network/git2.c b/examples/network/git2.c index c694762a2..7c02305c4 100644 --- a/examples/network/git2.c +++ b/examples/network/git2.c @@ -25,16 +25,17 @@ int run_command(git_cb fn, int argc, char **argv) // repository and pass it to the function. error = git_repository_open(&repo, ".git"); - if (error < GIT_SUCCESS) + if (error < 0) repo = NULL; // Run the command. If something goes wrong, print the error message to stderr error = fn(repo, argc, argv); - if (error < GIT_SUCCESS) { + if (error < 0) { if (giterr_last() == NULL) fprintf(stderr, "Error without message"); else fprintf(stderr, "Bad news:\n %s\n", giterr_last()->message); + } if(repo) git_repository_free(repo); diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c index 881c1493f..5824fc555 100644 --- a/examples/network/index-pack.c +++ b/examples/network/index-pack.c @@ -8,95 +8,95 @@ // the indexing to finish in a worker thread int index_cb(const git_indexer_stats *stats, void *data) { - printf("\rProcessing %d of %d", stats->processed, stats->total); + printf("\rProcessing %d of %d", stats->processed, stats->total); } int index_pack(git_repository *repo, int argc, char **argv) { - git_indexer_stream *idx; - git_indexer_stats stats = {0, 0}; - int error, fd; - char hash[GIT_OID_HEXSZ + 1] = {0}; - ssize_t read_bytes; - char buf[512]; + git_indexer_stream *idx; + git_indexer_stats stats = {0, 0}; + int error, fd; + char hash[GIT_OID_HEXSZ + 1] = {0}; + ssize_t read_bytes; + char buf[512]; - if (argc < 2) { - fprintf(stderr, "I need a packfile\n"); - return EXIT_FAILURE; - } + if (argc < 2) { + fprintf(stderr, "I need a packfile\n"); + return EXIT_FAILURE; + } - if (git_indexer_stream_new(&idx, ".git") < 0) { - puts("bad idx"); - return -1; - } + if (git_indexer_stream_new(&idx, ".git") < 0) { + puts("bad idx"); + return -1; + } - if ((fd = open(argv[1], 0)) < 0) { - perror("open"); - return -1; - } + if ((fd = open(argv[1], 0)) < 0) { + perror("open"); + return -1; + } - do { - read_bytes = read(fd, buf, sizeof(buf)); - if (read_bytes < 0) - break; + do { + read_bytes = read(fd, buf, sizeof(buf)); + if (read_bytes < 0) + break; - if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0) - goto cleanup; + if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0) + goto cleanup; - printf("\rIndexing %d of %d", stats.processed, stats.total); - } while (read_bytes > 0); + printf("\rIndexing %d of %d", stats.processed, stats.total); + } while (read_bytes > 0); - if (read_bytes < 0) { - error = -1; - perror("failed reading"); - goto cleanup; - } + if (read_bytes < 0) { + error = -1; + perror("failed reading"); + goto cleanup; + } - if ((error = git_indexer_stream_finalize(idx, &stats)) < 0) - goto cleanup; + if ((error = git_indexer_stream_finalize(idx, &stats)) < 0) + goto cleanup; - printf("\rIndexing %d of %d\n", stats.processed, stats.total); + printf("\rIndexing %d of %d\n", stats.processed, stats.total); - git_oid_fmt(hash, git_indexer_stream_hash(idx)); - puts(hash); + git_oid_fmt(hash, git_indexer_stream_hash(idx)); + puts(hash); -cleanup: - close(fd); - git_indexer_stream_free(idx); - return error; + cleanup: + close(fd); + git_indexer_stream_free(idx); + return error; } int index_pack_old(git_repository *repo, int argc, char **argv) { - git_indexer *indexer; - git_indexer_stats stats; - int error; - char hash[GIT_OID_HEXSZ + 1] = {0}; + git_indexer *indexer; + git_indexer_stats stats; + int error; + char hash[GIT_OID_HEXSZ + 1] = {0}; - if (argc < 2) { - fprintf(stderr, "I need a packfile\n"); - return EXIT_FAILURE; - } + if (argc < 2) { + fprintf(stderr, "I need a packfile\n"); + return EXIT_FAILURE; + } - // Create a new indexer - error = git_indexer_new(&indexer, argv[1]); - if (error < GIT_SUCCESS) - return error; + // Create a new indexer + error = git_indexer_new(&indexer, argv[1]); + if (error < 0) + return error; - // Index the packfile. This function can take a very long time and - // should be run in a worker thread. - error = git_indexer_run(indexer, &stats); - if (error < GIT_SUCCESS) - return error; + // Index the packfile. This function can take a very long time and + // should be run in a worker thread. + error = git_indexer_run(indexer, &stats); + if (error < 0) + return error; - // Write the information out to an index file - error = git_indexer_write(indexer); + // Write the information out to an index file + error = git_indexer_write(indexer); - // Get the packfile's hash (which should become it's filename) - git_oid_fmt(hash, git_indexer_hash(indexer)); - puts(hash); + // Get the packfile's hash (which should become it's filename) + git_oid_fmt(hash, git_indexer_hash(indexer)); + puts(hash); - git_indexer_free(indexer); + git_indexer_free(indexer); - return GIT_SUCCESS; + return 0; } diff --git a/examples/network/ls-remote.c b/examples/network/ls-remote.c index 958a88651..39cc64725 100644 --- a/examples/network/ls-remote.c +++ b/examples/network/ls-remote.c @@ -9,7 +9,7 @@ static int show_ref__cb(git_remote_head *head, void *payload) char oid[GIT_OID_HEXSZ + 1] = {0}; git_oid_fmt(oid, &head->oid); printf("%s\t%s\n", oid, head->name); - return GIT_SUCCESS; + return 0; } int use_unnamed(git_repository *repo, const char *url) @@ -20,13 +20,13 @@ int use_unnamed(git_repository *repo, const char *url) // Create an instance of a remote from the URL. The transport to use // is detected from the URL error = git_remote_new(&remote, repo, NULL, url, NULL); - if (error < GIT_SUCCESS) + if (error < 0) goto cleanup; // When connecting, the underlying code needs to know wether we // want to push or fetch error = git_remote_connect(remote, GIT_DIR_FETCH); - if (error < GIT_SUCCESS) + if (error < 0) goto cleanup; // With git_remote_ls we can retrieve the advertised heads @@ -44,11 +44,11 @@ int use_remote(git_repository *repo, char *name) // Find the remote by name error = git_remote_load(&remote, repo, name); - if (error < GIT_SUCCESS) + if (error < 0) goto cleanup; error = git_remote_connect(remote, GIT_DIR_FETCH); - if (error < GIT_SUCCESS) + if (error < 0) goto cleanup; error = git_remote_ls(remote, &show_ref__cb, NULL); diff --git a/include/git2/attr.h b/include/git2/attr.h index 6a05496dc..8f5a1268d 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -65,8 +65,8 @@ GIT_BEGIN_DECL #define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_attr__unset) /** - * GIT_ATTR_SET_TO_VALUE checks if an attribute is set to a value (as - * opposied to TRUE, FALSE or UNSPECIFIED). This would be the case if + * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as + * opposed to TRUE, FALSE or UNSPECIFIED). This would be the case if * for a file with something like: * * *.txt eol=lf @@ -74,7 +74,7 @@ GIT_BEGIN_DECL * Given this, looking up "eol" for `onefile.txt` will give back the * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true. */ -#define GIT_ATTR_SET_TO_VALUE(attr) \ +#define GIT_ATTR_HAS_VALUE(attr) \ ((attr) && (attr) != git_attr__unset && \ (attr) != git_attr__true && (attr) != git_attr__false) @@ -111,6 +111,10 @@ GIT_EXTERN(const char *) git_attr__unset; /** * Look up the value of one git attribute for path. * + * @param value_out Output of the value of the attribute. Use the GIT_ATTR_... + * macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just + * use the string value for attributes set to a value. You + * should NOT modify or free this value. * @param repo The repository containing the path. * @param flags A combination of GIT_ATTR_CHECK... flags. * @param path The path to check for attributes. Relative paths are @@ -118,17 +122,13 @@ GIT_EXTERN(const char *) git_attr__unset; * not have to exist, but if it does not, then it will be * treated as a plain file (not a directory). * @param name The name of the attribute to look up. - * @param value Output of the value of the attribute. Use the GIT_ATTR_... - * macros to test for TRUE, FALSE, UNSPECIFIED, etc. or just - * use the string value for attributes set to a value. You - * should NOT modify or free this value. */ GIT_EXTERN(int) git_attr_get( + const char **value_out, git_repository *repo, uint32_t flags, const char *path, - const char *name, - const char **value); + const char *name); /** * Look up a list of git attributes for path. @@ -141,11 +141,16 @@ GIT_EXTERN(int) git_attr_get( * * const char *attrs[] = { "crlf", "diff", "foo" }; * const char **values[3]; - * git_attr_get_many(repo, 0, "my/fun/file.c", 3, attrs, values); + * git_attr_get_many(values, repo, 0, "my/fun/file.c", 3, attrs); * * Then you could loop through the 3 values to get the settings for * the three attributes you asked about. * + * @param values An array of num_attr entries that will have string + * pointers written into it for the values of the attributes. + * You should not modify or free the values that are written + * into this array (although of course, you should free the + * array itself if you allocated it). * @param repo The repository containing the path. * @param flags A combination of GIT_ATTR_CHECK... flags. * @param path The path inside the repo to check attributes. This @@ -153,19 +158,14 @@ GIT_EXTERN(int) git_attr_get( * it will be treated as a plain file (i.e. not a directory). * @param num_attr The number of attributes being looked up * @param names An array of num_attr strings containing attribute names. - * @param values An array of num_attr entries that will have string - * pointers written into it for the values of the attributes. - * You should not modify or free the values that are written - * into this array (although of course, you should free the - * array itself if you allocated it). */ GIT_EXTERN(int) git_attr_get_many( + const char **values_out, git_repository *repo, uint32_t flags, const char *path, size_t num_attr, - const char **names, - const char **values); + const char **names); /** * Loop over all the git attributes for a path. diff --git a/include/git2/blob.h b/include/git2/blob.h index 44b29d7eb..551770678 100644 --- a/include/git2/blob.h +++ b/include/git2/blob.h @@ -27,7 +27,7 @@ GIT_BEGIN_DECL * @param blob pointer to the looked up blob * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id) { @@ -44,7 +44,7 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git * @param repo the repo to use when locating the blob. * @param id identity of the blob to locate. * @param len the length of the short identifier - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_blob_lookup_prefix(git_blob **blob, git_repository *repo, const git_oid *id, unsigned int len) { @@ -99,10 +99,22 @@ GIT_EXTERN(size_t) git_blob_rawsize(git_blob *blob); * this repository cannot be bare * @param path file from which the blob will be created, * relative to the repository's working dir - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path); +/** + * Read a file from the filesystem and write its content + * to the Object Database as a loose blob + * + * @param oid return the id of the written blob + * @param repo repository where the blob will be written. + * this repository can be bare or not + * @param path file from which the blob will be created + * @return 0 or an error code + */ +GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path); + /** * Write an in-memory buffer to the ODB as a blob @@ -111,7 +123,7 @@ GIT_EXTERN(int) git_blob_create_fromfile(git_oid *oid, git_repository *repo, con * @param repo repository where to blob will be written * @param buffer data to be written into the blob * @param len length of the data - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *buffer, size_t len); diff --git a/include/git2/branch.h b/include/git2/branch.h index f4681dc09..e2432bcfc 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -41,7 +41,7 @@ GIT_BEGIN_DECL * * @param force Overwrite existing branch. * - * @return GIT_SUCCESS or an error code. + * @return 0 or an error code. * A proper reference is written in the refs/heads namespace * pointing to the provided target commit. */ @@ -63,13 +63,13 @@ GIT_EXTERN(int) git_branch_create( * @param branch_type Type of the considered branch. This should * be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE. * - * @return GIT_SUCCESS on success, GIT_ENOTFOUND if the branch + * @return 0 on success, GIT_ENOTFOUND if the branch * doesn't exist or an error code. */ GIT_EXTERN(int) git_branch_delete( git_repository *repo, const char *branch_name, - git_branch_type branch_type); + git_branch_t branch_type); /** * Fill a list with all the branches in the Repository @@ -88,7 +88,7 @@ GIT_EXTERN(int) git_branch_delete( * listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE * or a combination of the two. * - * @return GIT_SUCCESS or an error code. + * @return 0 or an error code. */ GIT_EXTERN(int) git_branch_list( git_strarray *branch_names, @@ -108,7 +108,7 @@ GIT_EXTERN(int) git_branch_list( * * @param force Overwrite existing branch. * - * @return GIT_SUCCESS on success, GIT_ENOTFOUND if the branch + * @return 0 on success, GIT_ENOTFOUND if the branch * doesn't exist or an error code. */ GIT_EXTERN(int) git_branch_move( diff --git a/include/git2/commit.h b/include/git2/commit.h index e519bc128..a6d9bb0e3 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -28,7 +28,7 @@ GIT_BEGIN_DECL * @param repo the repo to use when locating the commit. * @param id identity of the commit to locate. If the object is * an annotated tag it will be peeled back to the commit. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id) { @@ -46,7 +46,7 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con * @param id identity of the commit to locate. If the object is * an annotated tag it will be peeled back to the commit. * @param len the length of the short identifier - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, unsigned len) { @@ -135,7 +135,7 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit); * * @param tree_out pointer where to store the tree object * @param commit a previously loaded commit. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit); @@ -163,7 +163,7 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit); * @param parent Pointer where to store the parent commit * @param commit a previously loaded commit. * @param n the position of the parent (from 0 to `parentcount`) - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n); @@ -221,7 +221,7 @@ GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned i * array may be NULL if `parent_count` is 0 (root commit). All the * given commits must be owned by the `repo`. * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code * The created commit will be written to the Object Database and * the given reference will be updated to point to it */ diff --git a/include/git2/common.h b/include/git2/common.h index a8f8d8e1e..0e9379804 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -77,7 +77,7 @@ GIT_BEGIN_DECL #endif /** - * The maximum length of a git valid git path. + * The maximum length of a valid git path. */ #define GIT_PATH_MAX 4096 diff --git a/include/git2/config.h b/include/git2/config.h index acc45b018..36946c4a5 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -62,10 +62,10 @@ typedef struct { * global configuration file. * * @param global_config_path Buffer of GIT_PATH_MAX length to store the path - * @return GIT_SUCCESS if a global configuration file has been + * @return 0 if a global configuration file has been * found. Its path will be stored in `buffer`. */ -GIT_EXTERN(int) git_config_find_global(char *global_config_path); +GIT_EXTERN(int) git_config_find_global(char *global_config_path, size_t length); /** * Locate the path to the system configuration file @@ -74,10 +74,10 @@ GIT_EXTERN(int) git_config_find_global(char *global_config_path); * %PROGRAMFILES%\Git\etc\gitconfig. * @param system_config_path Buffer of GIT_PATH_MAX length to store the path - * @return GIT_SUCCESS if a system configuration file has been + * @return 0 if a system configuration file has been * found. Its path will be stored in `buffer`. */ -GIT_EXTERN(int) git_config_find_system(char *system_config_path); +GIT_EXTERN(int) git_config_find_system(char *system_config_path, size_t length); /** * Open the global configuration file @@ -86,7 +86,7 @@ GIT_EXTERN(int) git_config_find_system(char *system_config_path); * and opens the located file, if it exists. * * @param out Pointer to store the config instance - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_open_global(git_config **out); @@ -110,7 +110,7 @@ GIT_EXTERN(int) git_config_file__ondisk(struct git_config_file **out, const char * can do anything with it. * * @param out pointer to the new configuration - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_new(git_config **out); @@ -127,7 +127,7 @@ GIT_EXTERN(int) git_config_new(git_config **out); * @param cfg the configuration to add the file to * @param file the configuration file (backend) to add * @param priority the priority the backend should have - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_add_file(git_config *cfg, git_config_file *file, int priority); @@ -148,7 +148,7 @@ GIT_EXTERN(int) git_config_add_file(git_config *cfg, git_config_file *file, int * @param cfg the configuration to add the file to * @param path path to the configuration file (backend) to add * @param priority the priority the backend should have - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_add_file_ondisk(git_config *cfg, const char *path, int priority); @@ -163,7 +163,7 @@ GIT_EXTERN(int) git_config_add_file_ondisk(git_config *cfg, const char *path, in * * @param cfg The configuration instance to create * @param path Path to the on-disk file to open - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_open_ondisk(git_config **cfg, const char *path); @@ -177,22 +177,22 @@ GIT_EXTERN(void) git_config_free(git_config *cfg); /** * Get the value of an integer config variable. * + * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name - * @param out pointer to the variable where the value should be stored - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_config_get_int32(git_config *cfg, const char *name, int32_t *out); +GIT_EXTERN(int) git_config_get_int32(int32_t *out, git_config *cfg, const char *name); /** * Get the value of a long integer config variable. * + * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name - * @param out pointer to the variable where the value should be stored - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_config_get_int64(git_config *cfg, const char *name, int64_t *out); +GIT_EXTERN(int) git_config_get_int64(int64_t *out, git_config *cfg, const char *name); /** * Get the value of a boolean config variable. @@ -200,12 +200,12 @@ GIT_EXTERN(int) git_config_get_int64(git_config *cfg, const char *name, int64_t * This function uses the usual C convention of 0 being false and * anything else true. * + * @param out pointer to the variable where the value should be stored * @param cfg where to look for the variable * @param name the variable's name - * @param out pointer to the variable where the value should be stored - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_config_get_bool(git_config *cfg, const char *name, int *out); +GIT_EXTERN(int) git_config_get_bool(int *out, git_config *cfg, const char *name); /** * Get the value of a string config variable. @@ -213,12 +213,12 @@ GIT_EXTERN(int) git_config_get_bool(git_config *cfg, const char *name, int *out) * The string is owned by the variable and should not be freed by the * user. * + * @param out pointer to the variable's value * @param cfg where to look for the variable * @param name the variable's name - * @param out pointer to the variable's value - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_config_get_string(git_config *cfg, const char *name, const char **out); +GIT_EXTERN(int) git_config_get_string(const char **out, git_config *cfg, const char *name); /** * Get each value of a multivar. @@ -240,7 +240,7 @@ GIT_EXTERN(int) git_config_get_multivar(git_config *cfg, const char *name, const * @param cfg where to look for the variable * @param name the variable's name * @param value Integer value for the variable - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_int32(git_config *cfg, const char *name, int32_t value); @@ -250,7 +250,7 @@ GIT_EXTERN(int) git_config_set_int32(git_config *cfg, const char *name, int32_t * @param cfg where to look for the variable * @param name the variable's name * @param value Long integer value for the variable - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_int64(git_config *cfg, const char *name, int64_t value); @@ -260,7 +260,7 @@ GIT_EXTERN(int) git_config_set_int64(git_config *cfg, const char *name, int64_t * @param cfg where to look for the variable * @param name the variable's name * @param value the value to store - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value); @@ -273,7 +273,7 @@ GIT_EXTERN(int) git_config_set_bool(git_config *cfg, const char *name, int value * @param cfg where to look for the variable * @param name the variable's name * @param value the string to store. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_config_set_string(git_config *cfg, const char *name, const char *value); @@ -307,7 +307,7 @@ GIT_EXTERN(int) git_config_delete(git_config *cfg, const char *name); * @param cfg where to get the variables from * @param callback the function to call on each variable * @param payload the data to pass to the callback - * @return GIT_SUCCESS or the return value of the callback which didn't return 0 + * @return 0 or the return value of the callback which didn't return 0 */ GIT_EXTERN(int) git_config_foreach( git_config *cfg, @@ -342,14 +342,14 @@ GIT_EXTERN(int) git_config_foreach( * If not a single match can be made to store in `out`, an error code will be * returned. * + * @param out place to store the result of the mapping * @param cfg config file to get the variables from * @param name name of the config variable to lookup * @param maps array of `git_cvar_map` objects specifying the possible mappings * @param map_n number of mapping objects in `maps` - * @param out place to store the result of the mapping - * @return GIT_SUCCESS on success, error code otherwise + * @return 0 on success, error code otherwise */ -GIT_EXTERN(int) git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out); +GIT_EXTERN(int) git_config_get_mapped(int *out, git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n); /** @} */ GIT_END_DECL diff --git a/include/git2/diff.h b/include/git2/diff.h index bafe6268c..a0e8ad6d2 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -155,7 +155,7 @@ typedef int (*git_diff_hunk_fn)( * * These values describe where a line came from and will be passed to * the git_diff_data_fn when iterating over a diff. There are some - * special origin contants at the end that are used for the text + * special origin constants at the end that are used for the text * output callbacks to demarcate lines that are actually part of * the file or hunk headers. */ diff --git a/include/git2/errors.h b/include/git2/errors.h index 0406c165a..fb6670004 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -17,30 +17,55 @@ */ GIT_BEGIN_DECL -typedef enum { +#ifdef GIT_OLD_ERRORS +enum { GIT_SUCCESS = 0, - GIT_ERROR = -1, - - /** Input does not exist in the scope searched. */ + GIT_ENOTOID = -2, GIT_ENOTFOUND = -3, - - /** A reference with this name already exists */ + GIT_ENOMEM = -4, + GIT_EOSERR = -5, + GIT_EOBJTYPE = -6, + GIT_ENOTAREPO = -7, + GIT_EINVALIDTYPE = -8, + GIT_EMISSINGOBJDATA = -9, + GIT_EPACKCORRUPTED = -10, + GIT_EFLOCKFAIL = -11, + GIT_EZLIB = -12, + GIT_EBUSY = -13, + GIT_EBAREINDEX = -14, + GIT_EINVALIDREFNAME = -15, + GIT_EREFCORRUPTED = -16, + GIT_ETOONESTEDSYMREF = -17, + GIT_EPACKEDREFSCORRUPTED = -18, + GIT_EINVALIDPATH = -19, + GIT_EREVWALKOVER = -20, + GIT_EINVALIDREFSTATE = -21, + GIT_ENOTIMPLEMENTED = -22, GIT_EEXISTS = -23, - - /** The given integer literal is too large to be parsed */ GIT_EOVERFLOW = -24, - - /** The given short oid is ambiguous */ + GIT_ENOTNUM = -25, + GIT_ESTREAM = -26, + GIT_EINVALIDARGS = -27, + GIT_EOBJCORRUPTED = -28, GIT_EAMBIGUOUS = -29, - - /** Skip and passthrough the given ODB backend */ GIT_EPASSTHROUGH = -30, - - /** The buffer is too short to satisfy the request */ + GIT_ENOMATCH = -31, GIT_ESHORTBUFFER = -32, +}; +#endif - GIT_EREVWALKOVER = -33, -} git_error_t; +/** Generic return codes */ +enum { + GIT_OK = 0, + GIT_ERROR = -1, + GIT_ENOTFOUND = -3, + GIT_EEXISTS = -4, + GIT_EAMBIGUOUS = -5, + GIT_EBUFS = -6, + + GIT_PASSTHROUGH = -30, + GIT_REVWALKOVER = -31, +}; typedef struct { char *message; @@ -62,7 +87,8 @@ typedef enum { GITERR_NET, GITERR_TAG, GITERR_TREE, -} git_error_class; + GITERR_INDEXER, +} git_error_t; /** * Return the last `git_error` object that was generated for the diff --git a/include/git2/index.h b/include/git2/index.h index ae727c59f..0fb0f955a 100644 --- a/include/git2/index.h +++ b/include/git2/index.h @@ -106,7 +106,7 @@ typedef struct git_index_entry_unmerged { * * @param index the pointer for the new index * @param index_path the path to the index file in disk - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_open(git_index **index, const char *index_path); @@ -131,7 +131,7 @@ GIT_EXTERN(void) git_index_free(git_index *index); * by reading from the hard disk. * * @param index an existing index object - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_read(git_index *index); @@ -140,7 +140,7 @@ GIT_EXTERN(int) git_index_read(git_index *index); * using an atomic file lock. * * @param index an existing index object - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_write(git_index *index); @@ -176,7 +176,7 @@ GIT_EXTERN(void) git_index_uniq(git_index *index); * @param index an existing index object * @param path filename to add * @param stage stage for the entry - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage); @@ -188,7 +188,7 @@ GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage); * * @param index an existing index object * @param source_entry new entry object - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_add2(git_index *index, const git_index_entry *source_entry); @@ -207,7 +207,7 @@ GIT_EXTERN(int) git_index_add2(git_index *index, const git_index_entry *source_e * @param index an existing index object * @param path filename to add * @param stage stage for the entry - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage); @@ -224,7 +224,7 @@ GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage); * * @param index an existing index object * @param source_entry new entry object - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *source_entry); @@ -233,7 +233,7 @@ GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *sourc * * @param index an existing index object * @param position position of the entry to remove - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_remove(git_index *index, int position); @@ -295,7 +295,7 @@ GIT_EXTERN(const git_index_entry_unmerged *) git_index_get_unmerged_byindex(git_ /** * Return the stage number from a git index entry * - * This entry is calculated from the entrie's flag + * This entry is calculated from the entry's flag * attribute like this: * * (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT @@ -312,7 +312,7 @@ GIT_EXTERN(int) git_index_entry_stage(const git_index_entry *entry); * * @param index an existing index object * @param tree tree to read - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_index_read_tree(git_index *index, git_tree *tree); diff --git a/include/git2/indexer.h b/include/git2/indexer.h index 14bd0e402..626377701 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -28,7 +28,7 @@ typedef struct git_indexer_stream git_indexer_stream; /** * Create a new streaming indexer instance * - * @param out where to store the inexer instance + * @param out where to store the indexer instance * @param path to the gitdir (metadata directory) */ GIT_EXTERN(int) git_indexer_stream_new(git_indexer_stream **out, const char *gitdir); diff --git a/include/git2/notes.h b/include/git2/notes.h index ecb37f3ab..19073abd1 100644 --- a/include/git2/notes.h +++ b/include/git2/notes.h @@ -28,7 +28,7 @@ GIT_BEGIN_DECL * @param notes_ref OID reference to use (optional); defaults to "refs/notes/commits" * @param oid OID of the object * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_note_read(git_note **note, git_repository *repo, const char *notes_ref, const git_oid *oid); @@ -62,7 +62,7 @@ GIT_EXTERN(const git_oid *) git_note_oid(git_note *note); * @param oid The OID of the object * @param oid The note to add for object oid * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_note_create(git_oid *out, git_repository *repo, git_signature *author, git_signature *committer, @@ -79,7 +79,7 @@ GIT_EXTERN(int) git_note_create(git_oid *out, git_repository *repo, * @param committer signature of the notes commit committer * @param oid the oid which note's to be removed * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_note_remove(git_repository *repo, const char *notes_ref, git_signature *author, git_signature *committer, @@ -98,10 +98,42 @@ GIT_EXTERN(void) git_note_free(git_note *note); * @param out Pointer to the default notes reference * @param repo The Git repository * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_note_default_ref(const char **out, git_repository *repo); +/** + * Basic components of a note + * + * - Oid of the blob containing the message + * - Oid of the git object being annotated + */ +typedef struct { + git_oid blob_oid; + git_oid annotated_object_oid; +} git_note_data; + +/** + * Loop over all the notes within a specified namespace + * and issue a callback for each one. + * + * @param repo Repository where to find the notes. + * + * @param notes_ref OID reference to read from (optional); defaults to "refs/notes/commits". + * + * @param note_cb Callback to invoke per found annotation. + * + * @param payload Extra parameter to callback function. + * + * @return 0 or an error code. + */ +GIT_EXTERN(int) git_note_foreach( + git_repository *repo, + const char *notes_ref, + int (*note_cb)(git_note_data *note_data, void *payload), + void *payload +); + /** @} */ GIT_END_DECL #endif diff --git a/include/git2/object.h b/include/git2/object.h index 859d0c4a4..414325121 100644 --- a/include/git2/object.h +++ b/include/git2/object.h @@ -21,7 +21,7 @@ GIT_BEGIN_DECL /** - * Lookup a reference to one of the objects in a repostory. + * Lookup a reference to one of the objects in a repository. * * The generated reference is owned by the repository and * should be closed with the `git_object_free` method @@ -45,7 +45,7 @@ GIT_EXTERN(int) git_object_lookup( git_otype type); /** - * Lookup a reference to one of the objects in a repostory, + * Lookup a reference to one of the objects in a repository, * given a prefix of its identifier (short id). * * The object obtained will be so that its identifier @@ -69,7 +69,7 @@ GIT_EXTERN(int) git_object_lookup( * @param id a short identifier for the object * @param len the length of the short identifier * @param type the type of the object - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_object_lookup_prefix( git_object **object_out, @@ -114,7 +114,7 @@ GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); * This method instructs the library to close an existing * object; note that git_objects are owned and cached by the repository * so the object may or may not be freed after this library call, - * depending on how agressive is the caching mechanism used + * depending on how aggressive is the caching mechanism used * by the repository. * * IMPORTANT: diff --git a/include/git2/odb.h b/include/git2/odb.h index 87d70a60b..e2443178c 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -29,7 +29,7 @@ GIT_BEGIN_DECL * * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_odb_new(git_odb **out); @@ -47,7 +47,7 @@ GIT_EXTERN(int) git_odb_new(git_odb **out); * @param out location to store the database pointer, if opened. * Set to NULL if the open failed. * @param objects_dir path of the backends' "objects" directory. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); @@ -62,7 +62,7 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance * @param priority Value for ordering the backends queue - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); @@ -83,7 +83,7 @@ GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int * @param odb database to add the backend to * @param backend pointer to a git_odb_backend instance * @param priority Value for ordering the backends queue - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); @@ -108,7 +108,7 @@ GIT_EXTERN(void) git_odb_free(git_odb *db); * @param db database to search for the object in. * @param id identity of the object to read. * @return - * - GIT_SUCCESS if the object was read; + * - 0 if the object was read; * - GIT_ENOTFOUND if the object is not in the database. */ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id); @@ -135,7 +135,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i * @param db database to search for the object in. * @param short_id a prefix of the id of the object to read. * @param len the length of the prefix - * @return GIT_SUCCESS if the object was read; + * @return 0 if the object was read; * GIT_ENOTFOUND if the object is not in the database. * GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix) */ @@ -156,7 +156,7 @@ GIT_EXTERN(int) git_odb_read_prefix(git_odb_object **out, git_odb *db, const git * @param db database to search for the object in. * @param id identity of the object to read. * @return - * - GIT_SUCCESS if the object was read; + * - 0 if the object was read; * - GIT_ENOTFOUND if the object is not in the database. */ GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git_oid *id); @@ -185,10 +185,10 @@ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id); * * @param oid pointer to store the OID result of the write * @param odb object database where to store the object - * @param data buffer with the data to storr + * @param data buffer with the data to store * @param len size of the buffer * @param type type of the data to store - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_odb_write(git_oid *oid, git_odb *odb, const void *data, size_t len, git_otype type); @@ -250,14 +250,14 @@ GIT_EXTERN(int) git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const /** * Determine the object-ID (sha1 hash) of a data buffer * - * The resulting SHA-1 OID will the itentifier for the data + * The resulting SHA-1 OID will be the identifier for the data * buffer as if the data buffer it were to written to the ODB. * * @param id the resulting object-ID. * @param data data to hash * @param len size of the data * @param type of the data to hash - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type); @@ -270,7 +270,7 @@ GIT_EXTERN(int) git_odb_hash(git_oid *id, const void *data, size_t len, git_otyp * @param out oid structure the result is written into. * @param path file to read and determine object id for * @param type the type of the object that will be hashed - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_otype type); diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index 9a0133f37..f4620f5f4 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -74,6 +74,13 @@ struct git_odb_backend { void (* free)(struct git_odb_backend *); }; +/** Streaming mode */ +enum { + GIT_STREAM_RDONLY = (1 << 1), + GIT_STREAM_WRONLY = (1 << 2), + GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY), +}; + /** A stream to read/write from a backend */ struct git_odb_stream { struct git_odb_backend *backend; @@ -85,13 +92,6 @@ struct git_odb_stream { void (*free)(struct git_odb_stream *stream); }; -/** Streaming mode */ -typedef enum { - GIT_STREAM_RDONLY = (1 << 1), - GIT_STREAM_WRONLY = (1 << 2), - GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY), -} git_odb_streammode; - GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir); GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir, int compression_level, int do_fsync); diff --git a/include/git2/oid.h b/include/git2/oid.h index 566d13ac1..a05b40a37 100644 --- a/include/git2/oid.h +++ b/include/git2/oid.h @@ -43,7 +43,7 @@ struct _git_oid { * @param str input hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes * needed for an oid encoded in hex (40 bytes). - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); @@ -56,7 +56,7 @@ GIT_EXTERN(int) git_oid_fromstr(git_oid *out, const char *str); * @param out oid structure the result is written into. * @param str input hex string of at least size `length` * @param length length of the input string - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_oid_fromstrn(git_oid *out, const char *str, size_t length); @@ -84,7 +84,7 @@ GIT_EXTERN(void) git_oid_fmt(char *str, const git_oid *oid); * Format a git_oid into a loose-object path string. * * The resulting string is "aa/...", where "aa" is the first two - * hex digitis of the oid and "..." is the remaining 38 digits. + * hex digits of the oid and "..." is the remaining 38 digits. * * @param str output hex string; must be pointing at the start of * the hex sequence and have at least the number of bytes @@ -155,7 +155,7 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, unsigned int le * @param a oid structure. * @param str input hex string of an object id. * @return GIT_ENOTOID if str is not a valid hex string, - * GIT_SUCCESS in case of a match, GIT_ERROR otherwise. + * 0 in case of a match, GIT_ERROR otherwise. */ GIT_EXTERN(int) git_oid_streq(const git_oid *a, const char *str); @@ -183,7 +183,7 @@ typedef struct git_oid_shorten git_oid_shorten; * be unique. * @return a `git_oid_shorten` instance, NULL if OOM */ -git_oid_shorten *git_oid_shorten_new(size_t min_length); +GIT_EXTERN(git_oid_shorten *) git_oid_shorten_new(size_t min_length); /** * Add a new OID to set of shortened OIDs and calculate @@ -209,14 +209,14 @@ git_oid_shorten *git_oid_shorten_new(size_t min_length); * added so far to the set; or an error code (<0) if an * error occurs. */ -int git_oid_shorten_add(git_oid_shorten *os, const char *text_oid); +GIT_EXTERN(int) git_oid_shorten_add(git_oid_shorten *os, const char *text_oid); /** * Free an OID shortener instance * * @param os a `git_oid_shorten` instance */ -void git_oid_shorten_free(git_oid_shorten *os); +GIT_EXTERN(void) git_oid_shorten_free(git_oid_shorten *os); /** @} */ GIT_END_DECL diff --git a/include/git2/reflog.h b/include/git2/reflog.h index d622abcad..f490e29de 100644 --- a/include/git2/reflog.h +++ b/include/git2/reflog.h @@ -28,7 +28,7 @@ GIT_BEGIN_DECL * * @param reflog pointer to reflog * @param ref reference to read the reflog for - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_read(git_reflog **reflog, git_reference *ref); @@ -46,7 +46,7 @@ GIT_EXTERN(int) git_reflog_read(git_reflog **reflog, git_reference *ref); * @param oid_old the OID the reference was pointing to * @param committer the signature of the committer * @param msg the reflog message - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_write(git_reference *ref, const git_oid *oid_old, const git_signature *committer, const char *msg); @@ -55,7 +55,7 @@ GIT_EXTERN(int) git_reflog_write(git_reference *ref, const git_oid *oid_old, con * * @param ref the reference * @param new_name the new name of the reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_rename(git_reference *ref, const char *new_name); @@ -63,7 +63,7 @@ GIT_EXTERN(int) git_reflog_rename(git_reference *ref, const char *new_name); * Delete the reflog for the given reference * * @param ref the reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reflog_delete(git_reference *ref); diff --git a/include/git2/refs.h b/include/git2/refs.h index 2073aabc5..2918215aa 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -28,7 +28,7 @@ GIT_BEGIN_DECL * @param reference_out pointer to the looked-up reference * @param repo the repository to look up the reference * @param name the long name for the reference (e.g. HEAD, ref/heads/master, refs/tags/v0.1.0, ...) - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_repository *repo, const char *name); @@ -59,7 +59,7 @@ GIT_EXTERN(int) git_reference_name_to_oid( * @param name The name of the reference * @param target The target of the reference * @param force Overwrite existing references - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force); @@ -79,7 +79,7 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos * @param name The name of the reference * @param id The object id pointed to by the reference. * @param force Overwrite existing references - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force); @@ -111,7 +111,7 @@ GIT_EXTERN(const char *) git_reference_target(git_reference *ref); * @param ref The reference * @return the type */ -GIT_EXTERN(git_rtype) git_reference_type(git_reference *ref); +GIT_EXTERN(git_ref_t) git_reference_type(git_reference *ref); /** * Get the full name of a reference @@ -124,7 +124,7 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref); /** * Resolve a symbolic reference * - * Thie method iteratively peels a symbolic reference + * This method iteratively peels a symbolic reference * until it resolves to a direct reference to an OID. * * The peeled reference is returned in the `resolved_ref` @@ -137,7 +137,7 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref); * * @param resolved_ref Pointer to the peeled reference * @param ref The reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_resolve(git_reference **resolved_ref, git_reference *ref); @@ -160,7 +160,7 @@ GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref); * * @param ref The reference * @param target The new target for the reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target); @@ -175,7 +175,7 @@ GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target) * * @param ref The reference * @param id The new target OID for the reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); @@ -202,7 +202,7 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); * @param ref The reference to rename * @param new_name The new name for the reference * @param force Overwrite an existing reference - * @return GIT_SUCCESS or an error code + * @return 0 or an error code * */ GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name, int force); @@ -216,7 +216,7 @@ GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name, i * memory. The given reference pointer will no longer be valid. * * @param ref The reference to remove - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_delete(git_reference *ref); @@ -231,7 +231,7 @@ GIT_EXTERN(int) git_reference_delete(git_reference *ref); * the loose references will be removed from disk. * * @param repo Repository where the loose refs will be packed - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_packall(git_repository *repo); @@ -254,9 +254,9 @@ GIT_EXTERN(int) git_reference_packall(git_repository *repo); * @param repo Repository where to find the refs * @param list_flags Filtering flags for the reference * listing. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags); +GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo, unsigned int list_flags); /** @@ -276,7 +276,7 @@ GIT_EXTERN(int) git_reference_listall(git_strarray *array, git_repository *repo, * listing. * @param callback Function which will be called for every listed ref * @param payload Additional data to pass to the callback - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload); @@ -293,7 +293,7 @@ GIT_EXTERN(int) git_reference_is_packed(git_reference *ref); * * Reference pointers may become outdated if the Git * repository is accessed simultaneously by other clients - * whilt the library is open. + * while the library is open. * * This method forces a reload of the reference from disk, * to ensure that the provided information is still @@ -304,7 +304,7 @@ GIT_EXTERN(int) git_reference_is_packed(git_reference *ref); * returned and the reference pointer will be invalidated. * * @param ref The reference to reload - * @return GIT_SUCCESS on success, or an error code + * @return 0 on success, or an error code */ GIT_EXTERN(int) git_reference_reload(git_reference *ref); @@ -320,7 +320,7 @@ GIT_EXTERN(void) git_reference_free(git_reference *ref); * * @param ref1 The first git_reference * @param ref2 The second git_reference - * @return GIT_SUCCESS if the same, else a stable but meaningless ordering. + * @return 0 if the same, else a stable but meaningless ordering. */ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2); diff --git a/include/git2/refspec.h b/include/git2/refspec.h index 28afe652d..1100e9022 100644 --- a/include/git2/refspec.h +++ b/include/git2/refspec.h @@ -25,7 +25,7 @@ GIT_BEGIN_DECL * @param refspec the refspec * @return the refspec's source specifier */ -const char *git_refspec_src(const git_refspec *refspec); +GIT_EXTERN(const char *) git_refspec_src(const git_refspec *refspec); /** * Get the destination specifier @@ -33,7 +33,15 @@ const char *git_refspec_src(const git_refspec *refspec); * @param refspec the refspec * @return the refspec's destination specifier */ -const char *git_refspec_dst(const git_refspec *refspec); +GIT_EXTERN(const char *) git_refspec_dst(const git_refspec *refspec); + +/** + * Get the force update setting + * + * @param refspec the refspec + * @return 1 if force update has been set, 0 otherwise + */ +GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); /** * Check if a refspec's source descriptor matches a reference @@ -42,7 +50,7 @@ const char *git_refspec_dst(const git_refspec *refspec); * @param refname the name of the reference to check * @return 1 if the refspec matches, 0 otherwise */ -int git_refspec_src_matches(const git_refspec *refspec, const char *refname); +GIT_EXTERN(int) git_refspec_src_matches(const git_refspec *refspec, const char *refname); /** * Transform a reference to its target following the refspec's rules @@ -51,9 +59,9 @@ int git_refspec_src_matches(const git_refspec *refspec, const char *refname); * @param outlen the size ouf the `out` buffer * @param spec the refspec * @param name the name of the reference to transform - * @return GIT_SUCCESS, GIT_ESHORTBUFFER or another error + * @return 0, GIT_EBUFS or another error */ -int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name); +GIT_EXTERN(int) git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name); GIT_END_DECL diff --git a/include/git2/remote.h b/include/git2/remote.h index 6550cd20b..7a032dbce 100644 --- a/include/git2/remote.h +++ b/include/git2/remote.h @@ -37,11 +37,11 @@ GIT_BEGIN_DECL * this when you have a URL instead of a remote's name. * * @param out pointer to the new remote object - * @param repo the associtated repository + * @param repo the associated repository * @param name the remote's name * @param url the remote repository's URL * @param fetch the fetch refspec to use for this remote - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_new(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch); @@ -51,7 +51,7 @@ GIT_EXTERN(int) git_remote_new(git_remote **out, git_repository *repo, const cha * @param out pointer to the new remote object * @param cfg the repository's configuration * @param name the remote's name - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const char *name); @@ -59,7 +59,7 @@ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const ch * Save a remote to its repository's configuration * * @param remote the remote to save to config - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_save(const git_remote *remote); @@ -84,7 +84,7 @@ GIT_EXTERN(const char *) git_remote_url(git_remote *remote); * * @param remote the remote * @apram spec the new fetch refspec - * @return GIT_SUCCESS or an error value + * @return 0 or an error value */ GIT_EXTERN(int) git_remote_set_fetchspec(git_remote *remote, const char *spec); @@ -100,8 +100,8 @@ GIT_EXTERN(const git_refspec *) git_remote_fetchspec(git_remote *remote); * Set the remote's push refspec * * @param remote the remote - * @apram spec the new push refspec - * @return GIT_SUCCESS or an error value + * @param spec the new push refspec + * @return 0 or an error value */ GIT_EXTERN(int) git_remote_set_pushspec(git_remote *remote, const char *spec); @@ -123,7 +123,7 @@ GIT_EXTERN(const git_refspec *) git_remote_pushspec(git_remote *remote); * * @param remote the remote to connect to * @param direction whether you want to receive or send data - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction); @@ -135,7 +135,7 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, int direction); * * @param refs where to store the refs * @param remote the remote - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload); @@ -149,8 +149,8 @@ GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void * filename will be NULL and the function will return success. * * @param remote the remote to download from - * @param filename where to store the temproray filename - * @return GIT_SUCCESS or an error code + * @param filename where to store the temporary filename + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_download(git_remote *remote, git_off_t *bytes, git_indexer_stats *stats); @@ -195,7 +195,7 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote, int (*cb)(const char /** * Return whether a string is a valid remote URL * - * @param tranport the url to check + * @param url the url to check * @param 1 if the url is valid, 0 otherwise */ GIT_EXTERN(int) git_remote_valid_url(const char *url); @@ -215,7 +215,7 @@ GIT_EXTERN(int) git_remote_supported_url(const char* url); * * @param remotes_list a string array with the names of the remotes * @param repo the repository to query - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_remote_list(git_strarray *remotes_list, git_repository *repo); diff --git a/include/git2/repository.h b/include/git2/repository.h index d760c23b7..0b56a0870 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -31,7 +31,7 @@ GIT_BEGIN_DECL * * @param repository pointer to the repo which will be opened * @param path the path to the repository - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *path); @@ -61,7 +61,7 @@ GIT_EXTERN(int) git_repository_open(git_repository **repository, const char *pat * 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 + * @return 0 or an error code */ GIT_EXTERN(int) git_repository_discover( char *repository_path, @@ -109,7 +109,7 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); * at the pointed path. If false, provided path will be considered as the working * directory into which the .git directory will be created. * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare); @@ -130,7 +130,7 @@ GIT_EXTERN(int) git_repository_head(git_reference **head_out, git_repository *re * instead of a branch. * * @param repo Repo to test - * @return 1 if HEAD is detached, 0 if i'ts not; error code if there + * @return 1 if HEAD is detached, 0 if it's not; error code if there * was an error. */ GIT_EXTERN(int) git_repository_head_detached(git_repository *repo); @@ -143,7 +143,7 @@ GIT_EXTERN(int) git_repository_head_detached(git_repository *repo); * * @param repo Repo to test * @return 1 if the current branch is an orphan, 0 if it's not; error - * code if therewas an error + * code if there was an error */ GIT_EXTERN(int) git_repository_head_orphan(git_repository *repo); @@ -194,7 +194,7 @@ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); * * @param repo A repository object * @param workdir The path to a working directory - * @return GIT_SUCCESS, or an error code + * @return 0, or an error code */ GIT_EXTERN(int) git_repository_set_workdir(git_repository *repo, const char *workdir); @@ -218,7 +218,7 @@ GIT_EXTERN(int) git_repository_is_bare(git_repository *repo); * * @param out Pointer to store the loaded config file * @param repo A repository object - * @return GIT_SUCCESS, or an error code + * @return 0, or an error code */ GIT_EXTERN(int) git_repository_config(git_config **out, git_repository *repo); @@ -249,7 +249,7 @@ GIT_EXTERN(void) git_repository_set_config(git_repository *repo, git_config *con * * @param out Pointer to store the loaded ODB * @param repo A repository object - * @return GIT_SUCCESS, or an error code + * @return 0, or an error code */ GIT_EXTERN(int) git_repository_odb(git_odb **out, git_repository *repo); @@ -280,7 +280,7 @@ GIT_EXTERN(void) git_repository_set_odb(git_repository *repo, git_odb *odb); * * @param out Pointer to store the loaded index * @param repo A repository object - * @return GIT_SUCCESS, or an error code + * @return 0, or an error code */ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 632c67588..2e9dc421a 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -65,7 +65,7 @@ GIT_BEGIN_DECL * * @param walker pointer to the new revision walker * @param repo the repo to walk through - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_new(git_revwalk **walker, git_repository *repo); @@ -97,14 +97,14 @@ GIT_EXTERN(void) git_revwalk_reset(git_revwalk *walker); * * @param walk the walker being used for the traversal. * @param oid the oid of the commit to start from. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid); /** * Push matching references * - * The OIDs pinted to by the references that match the given glob + * The OIDs pointed to by the references that match the given glob * pattern will be pushed to the revision walker. * * A leading 'refs/' is implied it not present as well as a trailing @@ -112,7 +112,7 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid); * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_glob(git_revwalk *walk, const char *glob); @@ -120,7 +120,7 @@ GIT_EXTERN(int) git_revwalk_push_glob(git_revwalk *walk, const char *glob); * Push the repository's HEAD * * @param walk the walker being used for the traversal - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk); @@ -135,14 +135,14 @@ GIT_EXTERN(int) git_revwalk_push_head(git_revwalk *walk); * * @param walk the walker being used for the traversal. * @param oid the oid of commit that will be ignored during the traversal - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid); /** * Hide matching references. * - * The OIDs pinted to by the references that match the given glob + * The OIDs pointed to by the references that match the given glob * pattern and their ancestors will be hidden from the output on the * revision walk. * @@ -151,7 +151,7 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid); * * @param walk the walker being used for the traversal * @param glob the glob pattern references should match - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_glob(git_revwalk *walk, const char *glob); @@ -159,7 +159,7 @@ GIT_EXTERN(int) git_revwalk_hide_glob(git_revwalk *walk, const char *glob); * Hide the repository's HEAD * * @param walk the walker being used for the traversal - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk); @@ -169,8 +169,8 @@ GIT_EXTERN(int) git_revwalk_hide_head(git_revwalk *walk); * The reference must point to a commit. * * @param walk the walker being used for the traversal - * @param refname the referece to push - * @return GIT_SUCCESS or an error code + * @param refname the reference to push + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname); @@ -180,8 +180,8 @@ GIT_EXTERN(int) git_revwalk_push_ref(git_revwalk *walk, const char *refname); * The reference must point to a commit. * * @param walk the walker being used for the traversal - * @param refname the referece to hide - * @return GIT_SUCCESS or an error code + * @param refname the reference to hide + * @return 0 or an error code */ GIT_EXTERN(int) git_revwalk_hide_ref(git_revwalk *walk, const char *refname); @@ -200,8 +200,8 @@ GIT_EXTERN(int) git_revwalk_hide_ref(git_revwalk *walk, const char *refname); * * @param oid Pointer where to store the oid of the next commit * @param walk the walker to pop the commit from. - * @return GIT_SUCCESS if the next commit was found; - * GIT_EREVWALKOVER if there are no commits left to iterate + * @return 0 if the next commit was found; + * GIT_REVWALKOVER if there are no commits left to iterate */ GIT_EXTERN(int) git_revwalk_next(git_oid *oid, git_revwalk *walk); diff --git a/include/git2/signature.h b/include/git2/signature.h index e26a6c88f..cbf94269f 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -28,7 +28,7 @@ GIT_BEGIN_DECL * @param email email of the person * @param time time when the action happened * @param offset timezone offset in minutes for the time - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset); @@ -39,7 +39,7 @@ GIT_EXTERN(int) git_signature_new(git_signature **sig_out, const char *name, con * @param sig_out new signature, in case of error NULL * @param name name of the person * @param email email of the person - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_signature_now(git_signature **sig_out, const char *name, const char *email); diff --git a/include/git2/status.h b/include/git2/status.h index f5fc95f0a..6a424dfd6 100644 --- a/include/git2/status.h +++ b/include/git2/status.h @@ -19,32 +19,35 @@ */ GIT_BEGIN_DECL -#define GIT_STATUS_CURRENT 0 +enum { + GIT_STATUS_CURRENT = 0, -/** Flags for index status */ -#define GIT_STATUS_INDEX_NEW (1 << 0) -#define GIT_STATUS_INDEX_MODIFIED (1 << 1) -#define GIT_STATUS_INDEX_DELETED (1 << 2) + GIT_STATUS_INDEX_NEW = (1 << 0), + GIT_STATUS_INDEX_MODIFIED = (1 << 1), + GIT_STATUS_INDEX_DELETED = (1 << 2), -/** Flags for worktree status */ -#define GIT_STATUS_WT_NEW (1 << 3) -#define GIT_STATUS_WT_MODIFIED (1 << 4) -#define GIT_STATUS_WT_DELETED (1 << 5) + GIT_STATUS_WT_NEW = (1 << 3), + GIT_STATUS_WT_MODIFIED = (1 << 4), + GIT_STATUS_WT_DELETED = (1 << 5), -#define GIT_STATUS_IGNORED (1 << 6) + GIT_STATUS_IGNORED = (1 << 6), +}; /** * Gather file statuses and run a callback for each one. * - * The callback is passed the path of the file, the status and the data pointer - * passed to this function. If the callback returns something other than - * GIT_SUCCESS, this function will return that value. + * The callback is passed the path of the file, the status and the data + * pointer passed to this function. If the callback returns something other + * than 0, this function will return that value. * * @param repo a repository object * @param callback the function to call on each file - * @return GIT_SUCCESS or the return value of the callback which did not return GIT_SUCCESS + * @return 0 on success or the return value of the callback that was non-zero */ -GIT_EXTERN(int) git_status_foreach(git_repository *repo, int (*callback)(const char *, unsigned int, void *), void *payload); +GIT_EXTERN(int) git_status_foreach( + git_repository *repo, + int (*callback)(const char *, unsigned int, void *), + void *payload); /** * Select the files on which to report status. @@ -94,11 +97,14 @@ typedef enum { * slash on the entry name). Given this flag, the directory * itself will not be included, but all the files in it will. */ -#define GIT_STATUS_OPT_INCLUDE_UNTRACKED (1 << 0) -#define GIT_STATUS_OPT_INCLUDE_IGNORED (1 << 1) -#define GIT_STATUS_OPT_INCLUDE_UNMODIFIED (1 << 2) -#define GIT_STATUS_OPT_EXCLUDE_SUBMODULES (1 << 3) -#define GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS (1 << 4) + +enum { + GIT_STATUS_OPT_INCLUDE_UNTRACKED = (1 << 0), + GIT_STATUS_OPT_INCLUDE_IGNORED = (1 << 1), + GIT_STATUS_OPT_INCLUDE_UNMODIFIED = (1 << 2), + GIT_STATUS_OPT_EXCLUDE_SUBMODULED = (1 << 3), + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS = (1 << 4), +}; /** * Options to control how callbacks will be made by @@ -115,7 +121,7 @@ typedef struct { */ GIT_EXTERN(int) git_status_foreach_ext( git_repository *repo, - git_status_options *opts, + const git_status_options *opts, int (*callback)(const char *, unsigned int, void *), void *payload); @@ -127,9 +133,12 @@ GIT_EXTERN(int) git_status_foreach_ext( * @param path the file to retrieve status for, rooted at the repo's workdir * @return GIT_EINVALIDPATH when `path` points at a folder, GIT_ENOTFOUND when * the file doesn't exist in any of HEAD, the index or the worktree, - * GIT_SUCCESS otherwise + * 0 otherwise */ -GIT_EXTERN(int) git_status_file(unsigned int *status_flags, git_repository *repo, const char *path); +GIT_EXTERN(int) git_status_file( + unsigned int *status_flags, + git_repository *repo, + const char *path); /** * Test if the ignore rules apply to a given file. @@ -139,13 +148,16 @@ GIT_EXTERN(int) git_status_file(unsigned int *status_flags, git_repository *repo * would be ignored regardless of whether the file is already in the index * or in the repository. * - * @param repo a repository object - * @param path the file to check ignores for, rooted at the repo's workdir * @param ignored boolean returning 0 if the file is not ignored, 1 if it is - * @return GIT_SUCCESS if the ignore rules could be processed for the file - * (regardless of whether it exists or not), or an error < 0 if they could not. + * @param repo a repository object + * @param path the file to check ignores for, rooted at the repo's workdir. + * @return 0 if ignore rules could be processed for the file (regardless + * of whether it exists or not), or an error < 0 if they could not. */ -GIT_EXTERN(int) git_status_should_ignore(git_repository *repo, const char *path, int *ignored); +GIT_EXTERN(int) git_status_should_ignore( + int *ignored, + git_repository *repo, + const char *path); /** @} */ GIT_END_DECL diff --git a/include/git2/submodule.h b/include/git2/submodule.h index 930168275..f65911a3b 100644 --- a/include/git2/submodule.h +++ b/include/git2/submodule.h @@ -83,7 +83,7 @@ GIT_EXTERN(int) git_submodule_foreach( /** * Lookup submodule information by name or path. * - * Given either the submodule name or path (they are ususally the same), + * Given either the submodule name or path (they are usually the same), * this returns a structure describing the submodule. If the submodule * does not exist, this will return GIT_ENOTFOUND and set the submodule * pointer to NULL. diff --git a/include/git2/tag.h b/include/git2/tag.h index 8224edfea..13dc145b6 100644 --- a/include/git2/tag.h +++ b/include/git2/tag.h @@ -27,7 +27,7 @@ GIT_BEGIN_DECL * @param tag pointer to the looked up tag * @param repo the repo to use when locating the tag. * @param id identity of the tag to locate. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oid *id) { @@ -44,7 +44,7 @@ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oi * @param repo the repo to use when locating the tag. * @param id identity of the tag to locate. * @param len the length of the short identifier - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_tag_lookup_prefix(git_tag **tag, git_repository *repo, const git_oid *id, unsigned int len) { @@ -85,7 +85,7 @@ GIT_EXTERN(const git_oid *) git_tag_id(git_tag *tag); * * @param target pointer where to store the target * @param tag a previously loaded tag. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tag_target(git_object **target, git_tag *tag); @@ -161,7 +161,7 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *tag); * * @param force Overwrite existing references * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code * A tag object is written to the ODB, and a proper reference * is written in the /refs/tags folder, pointing to it */ @@ -181,7 +181,7 @@ GIT_EXTERN(int) git_tag_create( * @param repo Repository where to store the tag * @param buffer Raw tag data * @param force Overwrite existing tags - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_tag_create_frombuffer( git_oid *oid, @@ -212,7 +212,7 @@ GIT_EXTERN(int) git_tag_create_frombuffer( * * @param force Overwrite existing references * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code * A proper reference is written in the /refs/tags folder, * pointing to the provided target object */ @@ -231,7 +231,7 @@ GIT_EXTERN(int) git_tag_create_lightweight( * @param tag_name Name of the tag to be deleted; * this name is validated for consistency. * - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tag_delete( git_repository *repo, @@ -248,7 +248,7 @@ GIT_EXTERN(int) git_tag_delete( * @param tag_names Pointer to a git_strarray structure where * the tag names will be stored * @param repo Repository where to find the tags - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tag_list( git_strarray *tag_names, @@ -270,7 +270,7 @@ GIT_EXTERN(int) git_tag_list( * the tag names will be stored * @param pattern Standard fnmatch pattern * @param repo Repository where to find the tags - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tag_list_match( git_strarray *tag_names, @@ -286,7 +286,7 @@ GIT_EXTERN(int) git_tag_list_match( * * @param tag_target Pointer to the peeled git_object * @param tag The tag to be processed - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tag_peel( git_object **tag_target, diff --git a/include/git2/tree.h b/include/git2/tree.h index 972c3795c..8f62e752a 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -27,7 +27,7 @@ GIT_BEGIN_DECL * @param tree pointer to the looked up tree * @param repo the repo to use when locating the tree. * @param id identity of the tree to locate. - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git_oid *id) { @@ -44,7 +44,7 @@ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git * @param repo the repo to use when locating the tree. * @param id identity of the tree to locate. * @param len the length of the short identifier - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_INLINE(int) git_tree_lookup_prefix(git_tree **tree, git_repository *repo, const git_oid *id, unsigned int len) { @@ -141,9 +141,9 @@ GIT_EXTERN(git_otype) git_tree_entry_type(const git_tree_entry *entry); * @param object pointer to the converted object * @param repo repository where to lookup the pointed object * @param entry a tree entry - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ -GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, const git_tree_entry *entry); +GIT_EXTERN(int) git_tree_entry_to_object(git_object **object_out, git_repository *repo, const git_tree_entry *entry); /** * Write a tree to the ODB from the index file @@ -159,7 +159,7 @@ GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository * * * @param oid Pointer where to store the written tree * @param index Index to write - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tree_create_fromindex(git_oid *oid, git_index *index); @@ -178,7 +178,7 @@ GIT_EXTERN(int) git_tree_create_fromindex(git_oid *oid, git_index *index); * * @param builder_p Pointer where to store the tree builder * @param source Source tree to initialize the builder (optional) - * @return 0 on sucess; error code otherwise + * @return 0 on success; error code otherwise */ GIT_EXTERN(int) git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source); @@ -229,7 +229,7 @@ GIT_EXTERN(const git_tree_entry *) git_treebuilder_get(git_treebuilder *bld, con * @param filename Filename of the entry * @param id SHA1 oid of the entry * @param attributes Folder attributes of the entry - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes); @@ -264,7 +264,7 @@ GIT_EXTERN(void) git_treebuilder_filter(git_treebuilder *bld, int (*filter)(cons * @param oid Pointer where to store the written OID * @param repo Repository where to store the object * @param bld Tree builder to write - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld); @@ -278,8 +278,7 @@ GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_tr * @param subtree Pointer where to store the subtree * @param root A previously loaded tree which will be the root of the relative path * @param subtree_path Path to the contained subtree - * @return GIT_SUCCESS on success; GIT_ENOTFOUND if the path does not lead to a - * subtree, GIT_EINVALIDPATH or an error code + * @return 0 on success; GIT_ENOTFOUND if the path does not lead to a subtree */ GIT_EXTERN(int) git_tree_get_subtree(git_tree **subtree, git_tree *root, const char *subtree_path); @@ -303,50 +302,16 @@ enum git_treewalk_mode { * data itself. * * If the callback returns a negative value, the passed entry - * will be skiped on the traversal. + * will be skipped on the traversal. * * @param tree The tree to walk * @param callback Function to call on each tree entry * @param mode Traversal mode (pre or post-order) * @param payload Opaque pointer to be passed on each callback - * @return GIT_SUCCESS or an error code + * @return 0 or an error code */ GIT_EXTERN(int) git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload); -typedef enum { - GIT_STATUS_ADDED = 1, - GIT_STATUS_DELETED = 2, - GIT_STATUS_MODIFIED = 3, -} git_status_t; - -typedef struct { - unsigned int old_attr; - unsigned int new_attr; - git_oid old_oid; - git_oid new_oid; - git_status_t status; - const char *path; -} git_tree_diff_data; - -typedef int (*git_tree_diff_cb)(const git_tree_diff_data *ptr, void *data); - -/** - * Diff two trees - * - * Compare two trees. For each difference in the trees, the callback - * will be called with a git_tree_diff_data filled with the relevant - * information. - * - * @param old the "old" tree - * @param newer the "newer" tree - * @param cb callback - * @param data data to give to the callback - * @return GIT_SUCCESS or an error code - */ -int git_tree_diff(git_tree *old, git_tree *newer, git_tree_diff_cb cb, void *data); - -int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data); - /** @} */ GIT_END_DECL diff --git a/include/git2/types.h b/include/git2/types.h index 98eea5374..cfb0acf33 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -158,13 +158,13 @@ typedef enum { GIT_REF_PACKED = 4, GIT_REF_HAS_PEEL = 8, GIT_REF_LISTALL = GIT_REF_OID|GIT_REF_SYMBOLIC|GIT_REF_PACKED, -} git_rtype; +} git_ref_t; /** Basic type of any Git branch. */ typedef enum { GIT_BRANCH_LOCAL = 1, GIT_BRANCH_REMOTE = 2, -} git_branch_type; +} git_branch_t; typedef struct git_refspec git_refspec; typedef struct git_remote git_remote; diff --git a/include/git2/version.h b/include/git2/version.h index 785a912fa..8edbe323c 100644 --- a/include/git2/version.h +++ b/include/git2/version.h @@ -7,9 +7,9 @@ #ifndef INCLUDE_git_version_h__ #define INCLUDE_git_version_h__ -#define LIBGIT2_VERSION "0.16.0" +#define LIBGIT2_VERSION "0.17.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 16 +#define LIBGIT2_VER_MINOR 17 #define LIBGIT2_VER_REVISION 0 #endif diff --git a/src/attr.c b/src/attr.c index 616cec6ff..fb6651196 100644 --- a/src/attr.c +++ b/src/attr.c @@ -13,11 +13,11 @@ static int collect_attr_files( int git_attr_get( + const char **value, git_repository *repo, uint32_t flags, const char *pathname, - const char *name, - const char **value) + const char *name) { int error; git_attr_path path; @@ -64,12 +64,12 @@ typedef struct { } attr_get_many_info; int git_attr_get_many( + const char **values, git_repository *repo, uint32_t flags, const char *pathname, size_t num_attr, - const char **names, - const char **values) + const char **names) { int error; git_attr_path path; @@ -235,31 +235,91 @@ bool git_attr_cache__is_cached( return rval; } -static int load_attr_file(const char *filename, const char **data) +static int load_attr_file( + const char **data, + git_attr_file_stat_sig *sig, + const char *filename) { int error; git_buf content = GIT_BUF_INIT; + struct stat st; - error = git_futils_readbuffer(&content, filename); - *data = error ? NULL : git_buf_detach(&content); + if (p_stat(filename, &st) < 0) + return GIT_ENOTFOUND; - return error; + if (sig != NULL && + (git_time_t)st.st_mtime == sig->seconds && + (git_off_t)st.st_size == sig->size && + (unsigned int)st.st_ino == sig->ino) + return GIT_ENOTFOUND; + + error = git_futils_readbuffer_updated(&content, filename, NULL, NULL); + if (error < 0) + return error; + + if (sig != NULL) { + sig->seconds = (git_time_t)st.st_mtime; + sig->size = (git_off_t)st.st_size; + sig->ino = (unsigned int)st.st_ino; + } + + *data = git_buf_detach(&content); + + return 0; } static int load_attr_blob_from_index( - git_repository *repo, const char *filename, git_blob **blob) + const char **content, + git_blob **blob, + git_repository *repo, + const git_oid *old_oid, + const char *relfile) { int error; git_index *index; git_index_entry *entry; if ((error = git_repository_index__weakptr(&index, repo)) < 0 || - (error = git_index_find(index, filename)) < 0) + (error = git_index_find(index, relfile)) < 0) return error; entry = git_index_get(index, error); - return git_blob_lookup(blob, repo, &entry->oid); + if (old_oid && git_oid_cmp(old_oid, &entry->oid) == 0) + return GIT_ENOTFOUND; + + if ((error = git_blob_lookup(blob, repo, &entry->oid)) < 0) + return error; + + *content = git_blob_rawcontent(*blob); + return 0; +} + +static int load_attr_from_cache( + git_attr_file **file, + git_attr_cache *cache, + git_attr_file_source source, + const char *relative_path) +{ + git_buf cache_key = GIT_BUF_INIT; + khiter_t cache_pos; + + *file = NULL; + + if (!cache || !cache->files) + return 0; + + if (git_buf_printf(&cache_key, "%d#%s", (int)source, relative_path) < 0) + return -1; + + cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr); + + git_buf_free(&cache_key); + + if (git_strmap_valid_index(cache->files, cache_pos)) + *file = git_strmap_value_at(cache->files, cache_pos); + + return 0; } int git_attr_cache__internal_file( @@ -301,6 +361,7 @@ int git_attr_cache__push_file( git_attr_cache *cache = git_repository_attr_cache(repo); git_attr_file *file = NULL; git_blob *blob = NULL; + git_attr_file_stat_sig st; assert(filename && stack); @@ -316,29 +377,22 @@ int git_attr_cache__push_file( relfile += strlen(workdir); /* check cache */ - if (cache && cache->files) { - git_buf cache_key = GIT_BUF_INIT; - khiter_t cache_pos; - - if (git_buf_printf(&cache_key, "%d#%s", (int)source, relfile) < 0) - return -1; - - cache_pos = git_strmap_lookup_index(cache->files, cache_key.ptr); - - git_buf_free(&cache_key); - - if (git_strmap_valid_index(cache->files, cache_pos)) { - file = git_strmap_value_at(cache->files, cache_pos); - goto finish; - } - } + if (load_attr_from_cache(&file, cache, source, relfile) < 0) + return -1; /* if not in cache, load data, parse, and cache */ - if (source == GIT_ATTR_FILE_FROM_FILE) - error = load_attr_file(filename, &content); - else - error = load_attr_blob_from_index(repo, relfile, &blob); + if (source == GIT_ATTR_FILE_FROM_FILE) { + if (file) + memcpy(&st, &file->cache_data.st, sizeof(st)); + else + memset(&st, 0, sizeof(st)); + + error = load_attr_file(&content, &st, filename); + } else { + error = load_attr_blob_from_index(&content, &blob, + repo, file ? &file->cache_data.oid : NULL, relfile); + } if (error) { /* not finding a file is not an error for this function */ @@ -349,11 +403,14 @@ int git_attr_cache__push_file( goto finish; } - if (blob) - content = git_blob_rawcontent(blob); - - if ((error = git_attr_file__new(&file, source, relfile, &cache->pool)) < 0) - goto finish; + /* if we got here, we have to parse and/or reparse the file */ + if (file) + git_attr_file__clear_rules(file); + else { + error = git_attr_file__new(&file, source, relfile, &cache->pool); + if (error < 0) + goto finish; + } if (parse && (error = parse(repo, content, file)) < 0) goto finish; @@ -362,6 +419,12 @@ int git_attr_cache__push_file( if (error > 0) error = 0; + /* remember "cache buster" file signature */ + if (blob) + git_oid_cpy(&file->cache_data.oid, git_object_id((git_object *)blob)); + else + memcpy(&file->cache_data.st, &st, sizeof(st)); + finish: /* push file onto vector if we found one*/ if (!error && file != NULL) @@ -518,11 +581,11 @@ int git_attr_cache__init(git_repository *repo) if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; - ret = git_config_get_string(cfg, GIT_ATTR_CONFIG, &cache->cfg_attr_file); + ret = git_config_get_string(&cache->cfg_attr_file, cfg, GIT_ATTR_CONFIG); if (ret < 0 && ret != GIT_ENOTFOUND) return ret; - ret = git_config_get_string(cfg, GIT_IGNORE_CONFIG, &cache->cfg_excl_file); + ret = git_config_get_string(&cache->cfg_excl_file, cfg, GIT_IGNORE_CONFIG); if (ret < 0 && ret != GIT_ENOTFOUND) return ret; diff --git a/src/attr_file.c b/src/attr_file.c index 49ff7319f..ca2f8fb58 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -139,18 +139,23 @@ int git_attr_file__new_and_load( return error; } -void git_attr_file__free(git_attr_file *file) +void git_attr_file__clear_rules(git_attr_file *file) { unsigned int i; git_attr_rule *rule; - if (!file) - return; - git_vector_foreach(&file->rules, i, rule) git_attr_rule__free(rule); git_vector_free(&file->rules); +} + +void git_attr_file__free(git_attr_file *file) +{ + if (!file) + return; + + git_attr_file__clear_rules(file); if (file->pool_is_allocated) { git_pool_clear(file->pool); @@ -338,10 +343,13 @@ int git_attr_fnmatch__parse( const char **base) { const char *pattern, *scan; - int slash_count; + int slash_count, allow_space; assert(spec && base && *base); + spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE); + allow_space = (spec->flags != 0); + pattern = *base; while (git__isspace(*pattern)) pattern++; @@ -350,8 +358,6 @@ int git_attr_fnmatch__parse( return GIT_ENOTFOUND; } - spec->flags = 0; - if (*pattern == '[') { if (strncmp(pattern, "[attr]", 6) == 0) { spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO; @@ -368,8 +374,10 @@ int git_attr_fnmatch__parse( slash_count = 0; for (scan = pattern; *scan != '\0'; ++scan) { /* scan until (non-escaped) white space */ - if (git__isspace(*scan) && *(scan - 1) != '\\') - break; + if (git__isspace(*scan) && *(scan - 1) != '\\') { + if (!allow_space || (*scan != ' ' && *scan != '\t')) + break; + } if (*scan == '/') { spec->flags = spec->flags | GIT_ATTR_FNMATCH_FULLPATH; @@ -378,7 +386,7 @@ int git_attr_fnmatch__parse( pattern++; } /* remember if we see an unescaped wildcard in pattern */ - else if ((*scan == '*' || *scan == '.' || *scan == '[') && + else if (git__iswildcard(*scan) && (scan == pattern || (*(scan - 1) != '\\'))) spec->flags = spec->flags | GIT_ATTR_FNMATCH_HASWILD; } diff --git a/src/attr_file.h b/src/attr_file.h index ec488c4dc..7939f838a 100644 --- a/src/attr_file.h +++ b/src/attr_file.h @@ -22,6 +22,7 @@ #define GIT_ATTR_FNMATCH_MACRO (1U << 3) #define GIT_ATTR_FNMATCH_IGNORE (1U << 4) #define GIT_ATTR_FNMATCH_HASWILD (1U << 5) +#define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6) typedef struct { char *pattern; @@ -47,11 +48,21 @@ typedef struct { const char *value; } git_attr_assignment; +typedef struct { + git_time_t seconds; + git_off_t size; + unsigned int ino; +} git_attr_file_stat_sig; + typedef struct { char *key; /* cache "source#path" this was loaded from */ git_vector rules; /* vector of or */ git_pool *pool; bool pool_is_allocated; + union { + git_oid oid; + git_attr_file_stat_sig st; + } cache_data; } git_attr_file; typedef struct { @@ -78,6 +89,8 @@ extern int git_attr_file__new_and_load( extern void git_attr_file__free(git_attr_file *file); +extern void git_attr_file__clear_rules(git_attr_file *file); + extern int git_attr_file__parse_buffer( git_repository *repo, const char *buf, git_attr_file *file); diff --git a/src/blob.c b/src/blob.c index 36571c70a..e25944b91 100644 --- a/src/blob.c +++ b/src/blob.c @@ -148,30 +148,20 @@ static int write_symlink( return error; } -int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path) +static int blob_create_internal(git_oid *oid, git_repository *repo, const char *path) { int error; - git_buf full_path = GIT_BUF_INIT; - git_off_t size; struct stat st; - const char *workdir; git_odb *odb = NULL; + git_off_t size; - workdir = git_repository_workdir(repo); - assert(workdir); /* error to call this on bare repo */ - - if ((error = git_buf_joinpath(&full_path, workdir, path)) < 0 || - (error = git_path_lstat(full_path.ptr, &st)) < 0 || - (error = git_repository_odb__weakptr(&odb, repo)) < 0) - { - git_buf_free(&full_path); + if ((error = git_path_lstat(path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0) return error; - } size = st.st_size; if (S_ISLNK(st.st_mode)) { - error = write_symlink(oid, odb, full_path.ptr, (size_t)size); + error = write_symlink(oid, odb, path, (size_t)size); } else { git_vector write_filters = GIT_VECTOR_INIT; int filter_count; @@ -186,10 +176,10 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat } else if (filter_count == 0) { /* No filters need to be applied to the document: we can stream * directly from disk */ - error = write_file_stream(oid, odb, full_path.ptr, size); + error = write_file_stream(oid, odb, path, size); } else { /* We need to apply one or more filters */ - error = write_file_filtered(oid, odb, full_path.ptr, &write_filters); + error = write_file_filtered(oid, odb, path, &write_filters); } git_filters_free(&write_filters); @@ -209,7 +199,41 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat */ } + return error; +} + +int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *path) +{ + git_buf full_path = GIT_BUF_INIT; + const char *workdir; + int error; + + workdir = git_repository_workdir(repo); + assert(workdir); /* error to call this on bare repo */ + + if (git_buf_joinpath(&full_path, workdir, path) < 0) { + git_buf_free(&full_path); + return -1; + } + + error = blob_create_internal(oid, repo, git_buf_cstr(&full_path)); + git_buf_free(&full_path); return error; } +int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path) +{ + int error; + git_buf full_path = GIT_BUF_INIT; + + if ((error = git_path_prettify(&full_path, path, NULL)) < 0) { + git_buf_free(&full_path); + return error; + } + + error = blob_create_internal(oid, repo, git_buf_cstr(&full_path)); + + git_buf_free(&full_path); + return error; +} diff --git a/src/branch.c b/src/branch.c index c980cf08c..5d5a24038 100644 --- a/src/branch.c +++ b/src/branch.c @@ -105,7 +105,7 @@ cleanup: return error; } -int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_type branch_type) +int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_t branch_type) { git_reference *branch = NULL; git_reference *head = NULL; @@ -114,7 +114,7 @@ int git_branch_delete(git_repository *repo, const char *branch_name, git_branch_ assert((branch_type == GIT_BRANCH_LOCAL) || (branch_type == GIT_BRANCH_REMOTE)); if ((error = retrieve_branch_reference(&branch, repo, branch_name, branch_type == GIT_BRANCH_REMOTE)) < 0) - goto on_error; + return error; if (git_reference_lookup(&head, repo, GIT_HEAD_FILE) < 0) { giterr_set(GITERR_REFERENCE, "Cannot locate HEAD."); @@ -170,7 +170,7 @@ int git_branch_list(git_strarray *branch_names, git_repository *repo, unsigned i filter.branchlist = &branchlist; filter.branch_type = list_flags; - error = git_reference_foreach(repo, GIT_REF_OID|GIT_REF_PACKED, &branch_list_cb, (void *)&filter); + error = git_reference_foreach(repo, GIT_REF_LISTALL, &branch_list_cb, (void *)&filter); if (error < 0) { git_vector_free(&branchlist); return -1; diff --git a/src/buffer.c b/src/buffer.c index 2ecb088f8..783a36eb8 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -12,9 +12,9 @@ /* Used as default value for git_buf->ptr so that people can always * assume ptr is non-NULL and zero terminated even for new git_bufs. */ -char git_buf_initbuf[1]; +char git_buf__initbuf[1]; -static char git_buf__oom; +char git_buf__oom[1]; #define ENSURE_SIZE(b, d) \ if ((d) > buf->asize && git_buf_grow(b, (d)) < 0)\ @@ -25,7 +25,7 @@ void git_buf_init(git_buf *buf, size_t initial_size) { buf->asize = 0; buf->size = 0; - buf->ptr = git_buf_initbuf; + buf->ptr = git_buf__initbuf; if (initial_size) git_buf_grow(buf, initial_size); @@ -35,7 +35,7 @@ int git_buf_grow(git_buf *buf, size_t target_size) { int error = git_buf_try_grow(buf, target_size); if (error != 0) - buf->ptr = &git_buf__oom; + buf->ptr = git_buf__oom; return error; } @@ -44,7 +44,7 @@ int git_buf_try_grow(git_buf *buf, size_t target_size) char *new_ptr; size_t new_size; - if (buf->ptr == &git_buf__oom) + if (buf->ptr == git_buf__oom) return -1; if (target_size <= buf->asize) @@ -85,7 +85,7 @@ void git_buf_free(git_buf *buf) { if (!buf) return; - if (buf->ptr != git_buf_initbuf && buf->ptr != &git_buf__oom) + if (buf->ptr != git_buf__initbuf && buf->ptr != git_buf__oom) git__free(buf->ptr); git_buf_init(buf, 0); @@ -98,11 +98,6 @@ void git_buf_clear(git_buf *buf) buf->ptr[0] = '\0'; } -bool git_buf_oom(const git_buf *buf) -{ - return (buf->ptr == &git_buf__oom); -} - int git_buf_set(git_buf *buf, const char *data, size_t len) { if (len == 0 || data == NULL) { @@ -164,7 +159,7 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) if (len < 0) { git__free(buf->ptr); - buf->ptr = &git_buf__oom; + buf->ptr = git_buf__oom; return -1; } @@ -244,7 +239,7 @@ char *git_buf_detach(git_buf *buf) { char *data = buf->ptr; - if (buf->asize == 0 || buf->ptr == &git_buf__oom) + if (buf->asize == 0 || buf->ptr == git_buf__oom) return NULL; git_buf_init(buf, 0); @@ -415,3 +410,52 @@ int git_buf_cmp(const git_buf *a, const git_buf *b) return (result != 0) ? result : (a->size < b->size) ? -1 : (a->size > b->size) ? 1 : 0; } + +int git_buf_common_prefix(git_buf *buf, const git_strarray *strings) +{ + size_t i; + const char *str, *pfx; + + git_buf_clear(buf); + + if (!strings || !strings->count) + return 0; + + /* initialize common prefix to first string */ + if (git_buf_sets(buf, strings->strings[0]) < 0) + return -1; + + /* go through the rest of the strings, truncating to shared prefix */ + for (i = 1; i < strings->count; ++i) { + + for (str = strings->strings[i], pfx = buf->ptr; + *str && *str == *pfx; str++, pfx++) + /* scanning */; + + git_buf_truncate(buf, pfx - buf->ptr); + + if (!buf->size) + break; + } + + return 0; +} + +bool git_buf_is_binary(const git_buf *buf) +{ + size_t i; + int printable = 0, nonprintable = 0; + + for (i = 0; i < buf->size; i++) { + unsigned char c = buf->ptr[i]; + if (c > 0x1F && c < 0x7F) + printable++; + else if (c == '\0') + return true; + else if (!git__isspace(c)) + nonprintable++; + } + + return ((printable >> 7) < nonprintable); +} + diff --git a/src/buffer.h b/src/buffer.h index 1f0ec1c15..50c75f64e 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -15,9 +15,10 @@ typedef struct { size_t asize, size; } git_buf; -extern char git_buf_initbuf[]; +extern char git_buf__initbuf[]; +extern char git_buf__oom[]; -#define GIT_BUF_INIT { git_buf_initbuf, 0, 0 } +#define GIT_BUF_INIT { git_buf__initbuf, 0, 0 } /** * Initialize a git_buf structure. @@ -61,7 +62,10 @@ void git_buf_attach(git_buf *buf, char *ptr, size_t asize); * * @return false if no error, true if allocation error */ -bool git_buf_oom(const git_buf *buf); +GIT_INLINE(bool) git_buf_oom(const git_buf *buf) +{ + return (buf->ptr == git_buf__oom); +} /* * Functions below that return int value error codes will return 0 on @@ -122,4 +126,10 @@ void git_buf_rtrim(git_buf *buf); int git_buf_cmp(const git_buf *a, const git_buf *b); +/* Fill buf with the common prefix of a array of strings */ +int git_buf_common_prefix(git_buf *buf, const git_strarray *strings); + +/* Check if buffer looks like it contains binary data */ +bool git_buf_is_binary(const git_buf *buf); + #endif diff --git a/src/commit.c b/src/commit.c index 2bf12f3a5..2f40dc67d 100644 --- a/src/commit.c +++ b/src/commit.c @@ -18,15 +18,6 @@ #include -#define COMMIT_BASIC_PARSE 0x0 -#define COMMIT_FULL_PARSE 0x1 - -#define COMMIT_PRINT(commit) {\ - char oid[41]; oid[40] = 0;\ - git_oid_fmt(oid, &commit->object.id);\ - printf("Oid: %s | In degree: %d | Time: %u\n", oid, commit->in_degree, commit->commit_time);\ -} - static void clear_parents(git_commit *commit) { unsigned int i; diff --git a/src/win32/fnmatch.c b/src/compat/fnmatch.c similarity index 100% rename from src/win32/fnmatch.c rename to src/compat/fnmatch.c diff --git a/src/win32/fnmatch.h b/src/compat/fnmatch.h similarity index 91% rename from src/win32/fnmatch.h rename to src/compat/fnmatch.h index eb7c5f6f7..7faef09b3 100644 --- a/src/win32/fnmatch.h +++ b/src/compat/fnmatch.h @@ -4,8 +4,8 @@ * 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_fnmatch__w32_h__ -#define INCLUDE_fnmatch__w32_h__ +#ifndef INCLUDE_fnmatch__compat_h__ +#define INCLUDE_fnmatch__compat_h__ #include "common.h" diff --git a/src/config.c b/src/config.c index 0ab0cd424..618202c34 100644 --- a/src/config.c +++ b/src/config.c @@ -199,30 +199,6 @@ int git_config_set_string(git_config *cfg, const char *name, const char *value) return file->set(file, name, value); } -int git_config_parse_bool(int *out, const char *value) -{ - /* A missing value means true */ - if (value == NULL) { - *out = 1; - return 0; - } - - if (!strcasecmp(value, "true") || - !strcasecmp(value, "yes") || - !strcasecmp(value, "on")) { - *out = 1; - return 0; - } - if (!strcasecmp(value, "false") || - !strcasecmp(value, "no") || - !strcasecmp(value, "off")) { - *out = 0; - return 0; - } - - return -1; -} - static int parse_int64(int64_t *out, const char *value) { const char *num_end; @@ -297,7 +273,7 @@ int git_config_lookup_map_value( case GIT_CVAR_TRUE: { int bool_val; - if (git_config_parse_bool(&bool_val, value) == 0 && + if (git__parse_bool(&bool_val, value) == 0 && bool_val == (int)m->cvar_type) { *out = m->map_value; return 0; @@ -322,12 +298,17 @@ int git_config_lookup_map_value( return GIT_ENOTFOUND; } -int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, size_t map_n, int *out) +int git_config_get_mapped( + int *out, + git_config *cfg, + const char *name, + git_cvar_map *maps, + size_t map_n) { const char *value; int ret; - ret = git_config_get_string(cfg, name, &value); + ret = git_config_get_string(&value, cfg, name); if (ret < 0) return ret; @@ -339,12 +320,12 @@ int git_config_get_mapped(git_config *cfg, const char *name, git_cvar_map *maps, return -1; } -int git_config_get_int64(git_config *cfg, const char *name, int64_t *out) +int git_config_get_int64(int64_t *out, git_config *cfg, const char *name) { const char *value; int ret; - ret = git_config_get_string(cfg, name, &value); + ret = git_config_get_string(&value, cfg, name); if (ret < 0) return ret; @@ -356,12 +337,12 @@ int git_config_get_int64(git_config *cfg, const char *name, int64_t *out) return 0; } -int git_config_get_int32(git_config *cfg, const char *name, int32_t *out) +int git_config_get_int32(int32_t *out, git_config *cfg, const char *name) { const char *value; int ret; - ret = git_config_get_string(cfg, name, &value); + ret = git_config_get_string(&value, cfg, name); if (ret < 0) return ret; @@ -373,16 +354,16 @@ int git_config_get_int32(git_config *cfg, const char *name, int32_t *out) return 0; } -int git_config_get_bool(git_config *cfg, const char *name, int *out) +int git_config_get_bool(int *out, git_config *cfg, const char *name) { const char *value; int ret; - ret = git_config_get_string(cfg, name, &value); + ret = git_config_get_string(&value, cfg, name); if (ret < 0) return ret; - if (git_config_parse_bool(out, value) == 0) + if (git__parse_bool(out, value) == 0) return 0; if (parse_int32(out, value) == 0) { @@ -394,7 +375,7 @@ int git_config_get_bool(git_config *cfg, const char *name, int *out) return -1; } -int git_config_get_string(git_config *cfg, const char *name, const char **out) +int git_config_get_string(const char **out, git_config *cfg, const char *name) { file_internal *internal; unsigned int i; @@ -462,7 +443,7 @@ int git_config_find_global_r(git_buf *path) return git_futils_find_global_file(path, GIT_CONFIG_FILENAME); } -int git_config_find_global(char *global_config_path) +int git_config_find_global(char *global_config_path, size_t length) { git_buf path = GIT_BUF_INIT; int ret = git_config_find_global_r(&path); @@ -472,14 +453,14 @@ int git_config_find_global(char *global_config_path) return ret; } - if (path.size > GIT_PATH_MAX) { + if (path.size >= length) { git_buf_free(&path); giterr_set(GITERR_NOMEMORY, "Path is to long to fit on the given buffer"); return -1; } - git_buf_copy_cstr(global_config_path, GIT_PATH_MAX, &path); + git_buf_copy_cstr(global_config_path, length, &path); git_buf_free(&path); return 0; } @@ -489,7 +470,7 @@ int git_config_find_system_r(git_buf *path) return git_futils_find_system_file(path, GIT_CONFIG_FILENAME_SYSTEM); } -int git_config_find_system(char *system_config_path) +int git_config_find_system(char *system_config_path, size_t length) { git_buf path = GIT_BUF_INIT; int ret = git_config_find_system_r(&path); @@ -499,14 +480,14 @@ int git_config_find_system(char *system_config_path) return ret; } - if (path.size > GIT_PATH_MAX) { + if (path.size >= length) { git_buf_free(&path); giterr_set(GITERR_NOMEMORY, "Path is to long to fit on the given buffer"); return -1; } - git_buf_copy_cstr(system_config_path, GIT_PATH_MAX, &path); + git_buf_copy_cstr(system_config_path, length, &path); git_buf_free(&path); return 0; } @@ -514,11 +495,14 @@ int git_config_find_system(char *system_config_path) int git_config_open_global(git_config **out) { int error; - char global_path[GIT_PATH_MAX]; + git_buf path = GIT_BUF_INIT; - if ((error = git_config_find_global(global_path)) < 0) + if ((error = git_config_find_global_r(&path)) < 0) return error; - return git_config_open_ondisk(out, global_path); + error = git_config_open_ondisk(out, git_buf_cstr(&path)); + git_buf_free(&path); + + return error; } diff --git a/src/config_cache.c b/src/config_cache.c index 3679a9646..ca9602e56 100644 --- a/src/config_cache.c +++ b/src/config_cache.c @@ -66,22 +66,22 @@ int git_repository__cvar(int *out, git_repository *repo, git_cvar_cached cvar) int error; error = git_repository_config__weakptr(&config, repo); - if (error < GIT_SUCCESS) + if (error < 0) return error; - error = git_config_get_mapped( - config, data->cvar_name, data->maps, data->map_count, out); + error = git_config_get_mapped(out, + config, data->cvar_name, data->maps, data->map_count); if (error == GIT_ENOTFOUND) *out = data->default_value; - else if (error < GIT_SUCCESS) + else if (error < 0) return error; repo->cvar_cache[(int)cvar] = *out; } - return GIT_SUCCESS; + return 0; } void git_repository__cvar_cache_clear(git_repository *repo) diff --git a/src/config_file.c b/src/config_file.c index cbc48bcd9..1c748fad1 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -443,8 +443,10 @@ static int config_delete(git_config_file *cfg, const char *name) pos = git_strmap_lookup_index(b->values, key); git__free(key); - if (!git_strmap_valid_index(b->values, pos)) + if (!git_strmap_valid_index(b->values, pos)) { + giterr_set(GITERR_CONFIG, "Could not find key '%s' to delete", name); return GIT_ENOTFOUND; + } var = git_strmap_value_at(b->values, pos); diff --git a/src/crlf.c b/src/crlf.c index 5d09a1f40..303a46d3b 100644 --- a/src/crlf.c +++ b/src/crlf.c @@ -82,8 +82,8 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con const char *attr_vals[NUM_CONV_ATTRS]; int error; - error = git_attr_get_many( - repo, 0, path, NUM_CONV_ATTRS, attr_names, attr_vals); + error = git_attr_get_many(attr_vals, + repo, 0, path, NUM_CONV_ATTRS, attr_names); if (error == GIT_ENOTFOUND) { ca->crlf_action = GIT_CRLF_GUESS; @@ -91,7 +91,7 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con return 0; } - if (error == GIT_SUCCESS) { + if (error == 0) { ca->crlf_action = check_crlf(attr_vals[2]); /* text */ if (ca->crlf_action == GIT_CRLF_GUESS) ca->crlf_action = check_crlf(attr_vals[0]); /* clrf */ @@ -100,7 +100,7 @@ static int crlf_load_attributes(struct crlf_attrs *ca, git_repository *repo, con return 0; } - return error; + return -1; } static int drop_crlf(git_buf *dest, const git_buf *source) @@ -207,7 +207,7 @@ int git_filter_add__crlf_to_odb(git_vector *filters, git_repository *repo, const int auto_crlf; if ((error = git_repository__cvar( - &auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < GIT_SUCCESS) + &auto_crlf, repo, GIT_CVAR_AUTO_CRLF)) < 0) return error; if (auto_crlf == GIT_AUTO_CRLF_FALSE) diff --git a/src/delta-apply.c b/src/delta-apply.c index d3be084e0..815ca8f16 100644 --- a/src/delta-apply.c +++ b/src/delta-apply.c @@ -111,7 +111,7 @@ int git__delta_apply( if (delta != delta_end || res_sz) goto fail; - return GIT_SUCCESS; + return 0; fail: git__free(out->data); diff --git a/src/delta-apply.h b/src/delta-apply.h index e46ef9af4..66fa76d43 100644 --- a/src/delta-apply.h +++ b/src/delta-apply.h @@ -20,7 +20,7 @@ * @param delta the delta to execute copy/insert instructions from. * @param delta_len total number of bytes in the delta. * @return - * - GIT_SUCCESS on a successful delta unpack. + * - 0 on a successful delta unpack. * - GIT_ERROR if the delta is corrupt or doesn't match the base. */ extern int git__delta_apply( diff --git a/src/diff.c b/src/diff.c index fed22f403..90baa9588 100644 --- a/src/diff.c +++ b/src/diff.c @@ -11,6 +11,25 @@ #include "config.h" #include "attr_file.h" +static char *diff_prefix_from_pathspec(const git_strarray *pathspec) +{ + git_buf prefix = GIT_BUF_INIT; + const char *scan; + + if (git_buf_common_prefix(&prefix, pathspec) < 0) + return NULL; + + /* diff prefix will only be leading non-wildcards */ + for (scan = prefix.ptr; *scan && !git__iswildcard(*scan); ++scan); + git_buf_truncate(&prefix, scan - prefix.ptr); + + if (prefix.size > 0) + return git_buf_detach(&prefix); + + git_buf_free(&prefix); + return NULL; +} + static bool diff_pathspec_is_interesting(const git_strarray *pathspec) { const char *str; @@ -251,8 +270,10 @@ static int diff_delta__cmp(const void *a, const void *b) static int config_bool(git_config *cfg, const char *name, int defvalue) { int val = defvalue; - if (git_config_get_bool(cfg, name, &val) < 0) + + if (git_config_get_bool(&val, cfg, name) < 0) giterr_clear(); + return val; } @@ -321,6 +342,7 @@ static git_diff_list *git_diff_list_alloc( git_attr_fnmatch *match = git__calloc(1, sizeof(git_attr_fnmatch)); if (!match) goto fail; + match->flags = GIT_ATTR_FNMATCH_ALLOWSPACE; ret = git_attr_fnmatch__parse(match, &diff->pool, NULL, &pattern); if (ret == GIT_ENOTFOUND) { git__free(match); @@ -532,29 +554,27 @@ static int diff_from_iterators( * matched in old (and/or descend into directories as needed) */ else if (nitem && (!oitem || strcmp(oitem->path, nitem->path) > 0)) { - int is_ignored; - git_delta_t delta_type = GIT_DELTA_ADDED; + git_delta_t delta_type = GIT_DELTA_UNTRACKED; - /* contained in ignored parent directory, so this can be skipped. */ + /* check if contained in ignored parent directory */ if (git_buf_len(&ignore_prefix) && git__prefixcmp(nitem->path, git_buf_cstr(&ignore_prefix)) == 0) - { - if (git_iterator_advance(new_iter, &nitem) < 0) - goto fail; - - continue; - } - - is_ignored = git_iterator_current_is_ignored(new_iter); + delta_type = GIT_DELTA_IGNORED; if (S_ISDIR(nitem->mode)) { - /* recurse into directory if explicitly requested or - * if there are tracked items inside the directory + /* recurse into directory only if there are tracked items in + * it or if the user requested the contents of untracked + * directories and it is not under an ignored directory. */ - if ((diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) || - (oitem && git__prefixcmp(oitem->path, nitem->path) == 0)) + if ((oitem && git__prefixcmp(oitem->path, nitem->path) == 0) || + (delta_type == GIT_DELTA_UNTRACKED && + (diff->opts.flags & GIT_DIFF_RECURSE_UNTRACKED_DIRS) != 0)) { - if (is_ignored) + /* if this directory is ignored, remember it as the + * "ignore_prefix" for processing contained items + */ + if (delta_type == GIT_DELTA_UNTRACKED && + git_iterator_current_is_ignored(new_iter)) git_buf_sets(&ignore_prefix, nitem->path); if (git_iterator_advance_into_directory(new_iter, &nitem) < 0) @@ -562,12 +582,34 @@ static int diff_from_iterators( continue; } - delta_type = GIT_DELTA_UNTRACKED; } - else if (is_ignored) + + /* In core git, the next two "else if" clauses are effectively + * reversed -- i.e. when an untracked file contained in an + * ignored directory is individually ignored, it shows up as an + * ignored file in the diff list, even though other untracked + * files in the same directory are skipped completely. + * + * To me, this is odd. If the directory is ignored and the file + * is untracked, we should skip it consistently, regardless of + * whether it happens to match a pattern in the ignore file. + * + * To match the core git behavior, just reverse the following + * two "else if" cases so that individual file ignores are + * checked before container directory exclusions are used to + * skip the file. + */ + else if (delta_type == GIT_DELTA_IGNORED) { + if (git_iterator_advance(new_iter, &nitem) < 0) + goto fail; + continue; /* ignored parent directory, so skip completely */ + } + + else if (git_iterator_current_is_ignored(new_iter)) delta_type = GIT_DELTA_IGNORED; - else if (new_iter->type == GIT_ITERATOR_WORKDIR) - delta_type = GIT_DELTA_UNTRACKED; + + else if (new_iter->type != GIT_ITERATOR_WORKDIR) + delta_type = GIT_DELTA_ADDED; if (diff_delta__from_one(diff, delta_type, nitem) < 0 || git_iterator_advance(new_iter, &nitem) < 0) @@ -613,13 +655,16 @@ int git_diff_tree_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && old_tree && new_tree && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_tree(repo, new_tree, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_tree_range(&b, repo, new_tree, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -630,13 +675,16 @@ int git_diff_index_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_index(repo, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_index_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -646,13 +694,16 @@ int git_diff_workdir_to_index( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && diff); - if (git_iterator_for_index(repo, &a) < 0 || - git_iterator_for_workdir(repo, &b) < 0) + if (git_iterator_for_index_range(&a, repo, prefix, prefix) < 0 || + git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } @@ -664,13 +715,16 @@ int git_diff_workdir_to_tree( git_diff_list **diff) { git_iterator *a = NULL, *b = NULL; + char *prefix = opts ? diff_prefix_from_pathspec(&opts->pathspec) : NULL; assert(repo && old_tree && diff); - if (git_iterator_for_tree(repo, old_tree, &a) < 0 || - git_iterator_for_workdir(repo, &b) < 0) + if (git_iterator_for_tree_range(&a, repo, old_tree, prefix, prefix) < 0 || + git_iterator_for_workdir_range(&b, repo, prefix, prefix) < 0) return -1; + git__free(prefix); + return diff_from_iterators(repo, opts, a, b, diff); } diff --git a/src/diff_output.c b/src/diff_output.c index 9c8e07972..5ffa641c4 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -103,7 +103,7 @@ static int diff_output_cb(void *priv, mmbuffer_t *bufs, int len) static int update_file_is_binary_by_attr(git_repository *repo, git_diff_file *file) { const char *value; - if (git_attr_get(repo, 0, file->path, "diff", &value) < 0) + if (git_attr_get(&value, repo, 0, file->path, "diff") < 0) return -1; if (GIT_ATTR_FALSE(value)) @@ -174,15 +174,12 @@ static int file_is_binary_by_content( git_map *new_data) { git_buf search; - git_text_stats stats; if ((delta->old_file.flags & BINARY_DIFF_FLAGS) == 0) { search.ptr = old_data->data; search.size = min(old_data->len, 4000); - git_text_gather_stats(&stats, &search); - - if (git_text_is_binary(&stats)) + if (git_buf_is_binary(&search)) delta->old_file.flags |= GIT_DIFF_FILE_BINARY; else delta->old_file.flags |= GIT_DIFF_FILE_NOT_BINARY; @@ -192,9 +189,7 @@ static int file_is_binary_by_content( search.ptr = new_data->data; search.size = min(new_data->len, 4000); - git_text_gather_stats(&stats, &search); - - if (git_text_is_binary(&stats)) + if (git_buf_is_binary(&search)) delta->new_file.flags |= GIT_DIFF_FILE_BINARY; else delta->new_file.flags |= GIT_DIFF_FILE_NOT_BINARY; @@ -392,7 +387,7 @@ int git_diff_foreach( if (error < 0) goto cleanup; - if ((delta->new_file.flags | GIT_DIFF_FILE_VALID_OID) == 0) { + if ((delta->new_file.flags & GIT_DIFF_FILE_VALID_OID) == 0) { error = git_odb_hash( &delta->new_file.oid, new_data.data, new_data.len, GIT_OBJ_BLOB); diff --git a/src/fetch.c b/src/fetch.c index 08c789ddb..c92cf4ef5 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -165,7 +165,7 @@ int git_fetch_setup_walk(git_revwalk **out, git_repository *repo) unsigned int i; git_reference *ref; - if (git_reference_listall(&refs, repo, GIT_REF_LISTALL) < 0) + if (git_reference_list(&refs, repo, GIT_REF_LISTALL) < 0) return -1; if (git_revwalk_new(&walk, repo) < 0) diff --git a/src/fileops.c b/src/fileops.c index bf95f769c..95a65893c 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -185,9 +185,6 @@ int git_futils_readbuffer_updated(git_buf *buf, const char *path, time_t *mtime, p_close(fd); - if (mtime != NULL) - *mtime = st.st_mtime; - if (updated != NULL) *updated = 1; @@ -244,28 +241,36 @@ void git_futils_mmap_free(git_map *out) int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode) { - int root_path_offset; git_buf make_path = GIT_BUF_INIT; - size_t start; + size_t start = 0; char *pp, *sp; bool failed = false; if (base != NULL) { + /* + * when a base is being provided, it is supposed to already exist. + * Therefore, no attempt is being made to recursively create this leading path + * segment. It's just skipped. */ start = strlen(base); if (git_buf_joinpath(&make_path, base, path) < 0) return -1; } else { - start = 0; + int root_path_offset; + if (git_buf_puts(&make_path, path) < 0) return -1; + + root_path_offset = git_path_root(make_path.ptr); + if (root_path_offset > 0) { + /* + * On Windows, will skip the drive name (eg. C: or D:) + * or the leading part of a network path (eg. //computer_name ) */ + start = root_path_offset; + } } pp = make_path.ptr + start; - root_path_offset = git_path_root(make_path.ptr); - if (root_path_offset > 0) - pp += root_path_offset; /* On Windows, will skip the drive name (eg. C: or D:) */ - while (!failed && (sp = strchr(pp, '/')) != NULL) { if (sp != pp && git_path_isdir(make_path.ptr) == false) { *sp = 0; @@ -309,7 +314,7 @@ static int _rmdir_recurs_foreach(void *opaque, git_buf *path) return -1; if (p_rmdir(path->ptr) < 0) { - if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && errno == ENOTEMPTY) + if (removal_type == GIT_DIRREMOVAL_ONLY_EMPTY_DIRS && (errno == ENOTEMPTY || errno == EEXIST)) return 0; giterr_set(GITERR_OS, "Could not remove directory '%s'", path->ptr); @@ -348,72 +353,23 @@ int git_futils_rmdir_r(const char *path, git_directory_removal_type removal_type return error; } -int git_futils_find_global_file(git_buf *path, const char *filename) -{ - const char *home = getenv("HOME"); - #ifdef GIT_WIN32 - if (home == NULL) - home = getenv("USERPROFILE"); -#endif - - if (home == NULL) { - giterr_set(GITERR_OS, "Global file lookup failed. " - "Cannot locate the user's home directory"); - return -1; - } - - if (git_buf_joinpath(path, home, filename) < 0) - return -1; - - if (git_path_exists(path->ptr) == false) { - git_buf_clear(path); - return GIT_ENOTFOUND; - } - - return 0; -} - -#ifdef GIT_WIN32 -typedef struct { - wchar_t *path; +struct win32_path { + wchar_t path[MAX_PATH]; DWORD len; -} win32_path; +}; -static const win32_path *win32_system_root(void) +static int win32_expand_path(struct win32_path *s_root, const wchar_t *templ) { - static win32_path s_root = { 0, 0 }; - - if (s_root.path == NULL) { - const wchar_t *root_tmpl = L"%PROGRAMFILES%\\Git\\etc\\"; - - s_root.len = ExpandEnvironmentStringsW(root_tmpl, NULL, 0); - if (s_root.len <= 0) { - giterr_set(GITERR_OS, "Failed to expand environment strings"); - return NULL; - } - - s_root.path = git__calloc(s_root.len, sizeof(wchar_t)); - if (s_root.path == NULL) - return NULL; - - if (ExpandEnvironmentStringsW(root_tmpl, s_root.path, s_root.len) != s_root.len) { - giterr_set(GITERR_OS, "Failed to expand environment strings"); - git__free(s_root.path); - s_root.path = NULL; - return NULL; - } - } - - return &s_root; + s_root->len = ExpandEnvironmentStringsW(templ, s_root->path, MAX_PATH); + return s_root->len ? 0 : -1; } -static int win32_find_system_file(git_buf *path, const char *filename) +static int win32_find_file(git_buf *path, const struct win32_path *root, const char *filename) { int error = 0; - const win32_path *root = win32_system_root(); size_t len; - wchar_t *file_utf16 = NULL, *scan; + wchar_t *file_utf16 = NULL; char *file_utf8 = NULL; if (!root || !filename || (len = strlen(filename)) == 0) @@ -435,10 +391,6 @@ static int win32_find_system_file(git_buf *path, const char *filename) goto cleanup; } - for (scan = file_utf16; *scan; scan++) - if (*scan == L'/') - *scan = L'\\'; - /* check access */ if (_waccess(file_utf16, F_OK) < 0) { error = GIT_ENOTFOUND; @@ -455,13 +407,30 @@ static int win32_find_system_file(git_buf *path, const char *filename) cleanup: git__free(file_utf16); - return error; } #endif int git_futils_find_system_file(git_buf *path, const char *filename) { +#ifdef GIT_WIN32 + struct win32_path root; + + if (win32_expand_path(&root, L"%PROGRAMFILES%\\Git\\etc\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the system's Program Files directory"); + return -1; + } + + if (win32_find_file(path, &root, filename) < 0) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } + + return 0; + +#else if (git_buf_joinpath(path, "/etc", filename) < 0) return -1; @@ -469,10 +438,45 @@ int git_futils_find_system_file(git_buf *path, const char *filename) return 0; git_buf_clear(path); - -#ifdef GIT_WIN32 - return win32_find_system_file(path, filename); -#else return GIT_ENOTFOUND; #endif } + +int git_futils_find_global_file(git_buf *path, const char *filename) +{ +#ifdef GIT_WIN32 + struct win32_path root; + + if (win32_expand_path(&root, L"%USERPROFILE%\\") < 0 || + root.path[0] == L'%') /* i.e. no expansion happened */ + { + giterr_set(GITERR_OS, "Cannot locate the user's profile directory"); + return -1; + } + + if (win32_find_file(path, &root, filename) < 0) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } + + return 0; +#else + const char *home = getenv("HOME"); + + if (home == NULL) { + giterr_set(GITERR_OS, "Global file lookup failed. " + "Cannot locate the user's home directory"); + return -1; + } + + if (git_buf_joinpath(path, home, filename) < 0) + return -1; + + if (git_path_exists(path->ptr) == false) { + git_buf_clear(path); + return GIT_ENOTFOUND; + } + + return 0; +#endif +} diff --git a/src/fileops.h b/src/fileops.h index be619d620..b0c5779e5 100644 --- a/src/fileops.h +++ b/src/fileops.h @@ -49,6 +49,9 @@ extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmo /** * Create a path recursively + * + * If a base parameter is being passed, it's expected to be valued with a path pointing to an already + * exisiting directory. */ extern int git_futils_mkdir_r(const char *path, const char *base, const mode_t mode); diff --git a/src/filter.c b/src/filter.c index 73fe83e61..8fa3eb684 100644 --- a/src/filter.c +++ b/src/filter.c @@ -129,7 +129,7 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters) if (git_buf_len(source) == 0) { git_buf_clear(dest); - return GIT_SUCCESS; + return 0; } /* Pre-grow the destination buffer to more or less the size @@ -160,6 +160,6 @@ int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters) if (src != 1) git_buf_swap(dest, source); - return GIT_SUCCESS; + return 0; } diff --git a/src/filter.h b/src/filter.h index 5a77f25c6..66e370aef 100644 --- a/src/filter.h +++ b/src/filter.h @@ -75,7 +75,7 @@ extern int git_filters_load(git_vector *filters, git_repository *repo, const cha * @param dest Buffer to store the result of the filtering * @param source Buffer containing the document to filter * @param filters A non-empty vector of filters as supplied by `git_filters_load` - * @return GIT_SUCCESS on success, an error code otherwise + * @return 0 on success, an error code otherwise */ extern int git_filters_apply(git_buf *dest, git_buf *source, git_vector *filters); diff --git a/src/index.c b/src/index.c index 216ede777..f1ae9a710 100644 --- a/src/index.c +++ b/src/index.c @@ -502,6 +502,15 @@ int git_index_find(git_index *index, const char *path) return git_vector_bsearch2(&index->entries, index_srch, path); } +unsigned int git_index__prefix_position(git_index *index, const char *path) +{ + unsigned int pos; + + git_vector_bsearch3(&pos, &index->entries, index_srch, path); + + return pos; +} + void git_index_uniq(git_index *index) { git_vector_uniq(&index->entries); @@ -930,7 +939,7 @@ static int read_tree_cb(const char *root, git_tree_entry *tentry, void *data) git_index_entry *entry = NULL; git_buf path = GIT_BUF_INIT; - if (entry_is_tree(tentry)) + if (git_tree_entry__is_tree(tentry)) return 0; if (git_buf_joinpath(&path, root, tentry->filename) < 0) diff --git a/src/index.h b/src/index.h index e745c8f69..8515f4fcb 100644 --- a/src/index.h +++ b/src/index.h @@ -33,4 +33,6 @@ struct git_index { extern void git_index__init_entry_from_stat(struct stat *st, git_index_entry *entry); +extern unsigned int git_index__prefix_position(git_index *index, const char *path); + #endif diff --git a/src/indexer.c b/src/indexer.c index 0baa194d6..f0e0a6381 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -110,12 +110,12 @@ static int parse_header(struct git_pack_header *hdr, struct git_pack_file *pack) } if (hdr->hdr_signature != ntohl(PACK_SIGNATURE)) { - giterr_set(GITERR_INVALID, "Wrong pack signature"); + giterr_set(GITERR_INDEXER, "Wrong pack signature"); return -1; } if (!pack_version_ok(hdr->hdr_version)) { - giterr_set(GITERR_INVALID, "Wrong pack version"); + giterr_set(GITERR_INDEXER, "Wrong pack version"); return -1; } @@ -205,9 +205,9 @@ static int store_delta(git_indexer_stream *idx) } error = packfile_unpack_compressed(&obj, idx->pack, &w, &idx->off, entry_size, type); - if (error == GIT_ESHORTBUFFER) { + if (error == GIT_EBUFS) { idx->off = entry_start; - return GIT_ESHORTBUFFER; + return GIT_EBUFS; } else if (error < 0){ return -1; } @@ -248,7 +248,7 @@ static int hash_and_save(git_indexer_stream *idx, git_rawobj *obj, git_off_t ent /* FIXME: Parse the object instead of hashing it */ if (git_odb__hashobj(&oid, obj) < 0) { - giterr_set(GITERR_INVALID, "Failed to hash object"); + giterr_set(GITERR_INDEXER, "Failed to hash object"); return -1; } @@ -355,7 +355,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz return 0; error = git_packfile_unpack(&obj, idx->pack, &idx->off); - if (error == GIT_ESHORTBUFFER) { + if (error == GIT_EBUFS) { idx->off = entry_start; return 0; } @@ -363,7 +363,7 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz if (error < 0) { idx->off = entry_start; error = store_delta(idx); - if (error == GIT_ESHORTBUFFER) + if (error == GIT_EBUFS) return 0; if (error < 0) return error; @@ -441,10 +441,21 @@ int git_indexer_stream_finalize(git_indexer_stream *idx, git_indexer_stats *stat git_oid file_hash; SHA_CTX ctx; + /* Test for this before resolve_deltas(), as it plays with idx->off */ + if (idx->off < idx->pack->mwf.size - GIT_OID_RAWSZ) { + giterr_set(GITERR_INDEXER, "Indexing error: junk at the end of the pack"); + return -1; + } + if (idx->deltas.length > 0) if (resolve_deltas(idx, stats) < 0) return -1; + if (stats->processed != stats->total) { + giterr_set(GITERR_INDEXER, "Indexing error: early EOF"); + return -1; + } + git_vector_sort(&idx->objects); git_buf_sets(&filename, idx->pack->pack_name); @@ -583,7 +594,7 @@ int git_indexer_new(git_indexer **out, const char *packname) assert(out && packname); if (git_path_root(packname) < 0) { - giterr_set(GITERR_INVALID, "Path is not absolute"); + giterr_set(GITERR_INDEXER, "Path is not absolute"); return -1; } @@ -815,7 +826,7 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) /* FIXME: Parse the object instead of hashing it */ error = git_odb__hashobj(&oid, &obj); if (error < 0) { - giterr_set(GITERR_INVALID, "Failed to hash object"); + giterr_set(GITERR_INDEXER, "Failed to hash object"); goto cleanup; } @@ -828,7 +839,6 @@ int git_indexer_run(git_indexer *idx, git_indexer_stats *stats) git_oid_cpy(&pentry->sha1, &oid); pentry->offset = entry_start; git_oid_fmt(fmt, &oid); - printf("adding %s to cache\n", fmt); error = git_vector_insert(&idx->pack->cache, pentry); if (error < 0) goto cleanup; diff --git a/src/iterator.c b/src/iterator.c index 646990d3f..819b0e22a 100644 --- a/src/iterator.c +++ b/src/iterator.c @@ -11,6 +11,23 @@ #include "buffer.h" #include "git2/submodule.h" +#define ITERATOR_BASE_INIT(P,NAME_LC,NAME_UC) do { \ + (P) = git__calloc(1, sizeof(NAME_LC ## _iterator)); \ + GITERR_CHECK_ALLOC(P); \ + (P)->base.type = GIT_ITERATOR_ ## NAME_UC; \ + (P)->base.start = start ? git__strdup(start) : NULL; \ + (P)->base.end = end ? git__strdup(end) : NULL; \ + (P)->base.current = NAME_LC ## _iterator__current; \ + (P)->base.at_end = NAME_LC ## _iterator__at_end; \ + (P)->base.advance = NAME_LC ## _iterator__advance; \ + (P)->base.seek = NAME_LC ## _iterator__seek; \ + (P)->base.reset = NAME_LC ## _iterator__reset; \ + (P)->base.free = NAME_LC ## _iterator__free; \ + if ((start && !(P)->base.start) || (end && !(P)->base.end)) \ + return -1; \ + } while (0) + + static int empty_iterator__no_item( git_iterator *iter, const git_index_entry **entry) { @@ -31,6 +48,13 @@ static int empty_iterator__noop(git_iterator *iter) return 0; } +static int empty_iterator__seek(git_iterator *iter, const char *prefix) +{ + GIT_UNUSED(iter); + GIT_UNUSED(prefix); + return -1; +} + static void empty_iterator__free(git_iterator *iter) { GIT_UNUSED(iter); @@ -45,6 +69,7 @@ int git_iterator_for_nothing(git_iterator **iter) i->current = empty_iterator__no_item; i->at_end = empty_iterator__at_end; i->advance = empty_iterator__no_item; + i->seek = empty_iterator__seek; i->reset = empty_iterator__noop; i->free = empty_iterator__free; @@ -53,10 +78,12 @@ int git_iterator_for_nothing(git_iterator **iter) return 0; } + typedef struct tree_iterator_frame tree_iterator_frame; struct tree_iterator_frame { tree_iterator_frame *next; git_tree *tree; + char *start; unsigned int index; }; @@ -66,6 +93,7 @@ typedef struct { tree_iterator_frame *stack; git_index_entry entry; git_buf path; + bool path_has_filename; } tree_iterator; static const git_tree_entry *tree_iterator__tree_entry(tree_iterator *ti) @@ -74,66 +102,16 @@ static const git_tree_entry *tree_iterator__tree_entry(tree_iterator *ti) git_tree_entry_byindex(ti->stack->tree, ti->stack->index); } -static int tree_iterator__current( - git_iterator *self, const git_index_entry **entry) +static char *tree_iterator__current_filename( + tree_iterator *ti, const git_tree_entry *te) { - tree_iterator *ti = (tree_iterator *)self; - const git_tree_entry *te = tree_iterator__tree_entry(ti); - - *entry = NULL; - - if (te == NULL) - return 0; - - ti->entry.mode = te->attr; - git_oid_cpy(&ti->entry.oid, &te->oid); - if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) - return -1; - - ti->entry.path = ti->path.ptr; - - *entry = &ti->entry; - - return 0; -} - -static int tree_iterator__at_end(git_iterator *self) -{ - return (tree_iterator__tree_entry((tree_iterator *)self) == NULL); -} - -static tree_iterator_frame *tree_iterator__alloc_frame(git_tree *tree) -{ - tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame)); - if (tf != NULL) - tf->tree = tree; - return tf; -} - -static int tree_iterator__expand_tree(tree_iterator *ti) -{ - int error; - git_tree *subtree; - const git_tree_entry *te = tree_iterator__tree_entry(ti); - tree_iterator_frame *tf; - - while (te != NULL && entry_is_tree(te)) { - if ((error = git_tree_lookup(&subtree, ti->repo, &te->oid)) < 0) - return error; - - if ((tf = tree_iterator__alloc_frame(subtree)) == NULL) - return -1; - - tf->next = ti->stack; - ti->stack = tf; - + if (!ti->path_has_filename) { if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) - return -1; - - te = tree_iterator__tree_entry(ti); + return NULL; + ti->path_has_filename = true; } - return 0; + return ti->path.ptr; } static void tree_iterator__pop_frame(tree_iterator *ti) @@ -145,6 +123,110 @@ static void tree_iterator__pop_frame(tree_iterator *ti) git__free(tf); } +static int tree_iterator__to_end(tree_iterator *ti) +{ + while (ti->stack && ti->stack->next) + tree_iterator__pop_frame(ti); + + if (ti->stack) + ti->stack->index = git_tree_entrycount(ti->stack->tree); + + return 0; +} + +static int tree_iterator__current( + git_iterator *self, const git_index_entry **entry) +{ + tree_iterator *ti = (tree_iterator *)self; + const git_tree_entry *te = tree_iterator__tree_entry(ti); + + if (entry) + *entry = NULL; + + if (te == NULL) + return 0; + + ti->entry.mode = te->attr; + git_oid_cpy(&ti->entry.oid, &te->oid); + + ti->entry.path = tree_iterator__current_filename(ti, te); + if (ti->entry.path == NULL) + return -1; + + if (ti->base.end && git__prefixcmp(ti->entry.path, ti->base.end) > 0) + return tree_iterator__to_end(ti); + + if (entry) + *entry = &ti->entry; + + return 0; +} + +static int tree_iterator__at_end(git_iterator *self) +{ + return (tree_iterator__tree_entry((tree_iterator *)self) == NULL); +} + +static tree_iterator_frame *tree_iterator__alloc_frame( + git_tree *tree, char *start) +{ + tree_iterator_frame *tf = git__calloc(1, sizeof(tree_iterator_frame)); + if (!tf) + return NULL; + + tf->tree = tree; + + if (start && *start) { + tf->start = start; + tf->index = git_tree__prefix_position(tree, start); + } + + return tf; +} + +static int tree_iterator__expand_tree(tree_iterator *ti) +{ + int error; + git_tree *subtree; + const git_tree_entry *te = tree_iterator__tree_entry(ti); + tree_iterator_frame *tf; + char *relpath; + + while (te != NULL && git_tree_entry__is_tree(te)) { + if (git_buf_joinpath(&ti->path, ti->path.ptr, te->filename) < 0) + return -1; + + /* check that we have not passed the range end */ + if (ti->base.end != NULL && + git__prefixcmp(ti->path.ptr, ti->base.end) > 0) + return tree_iterator__to_end(ti); + + if ((error = git_tree_lookup(&subtree, ti->repo, &te->oid)) < 0) + return error; + + relpath = NULL; + + /* apply range start to new frame if relevant */ + if (ti->stack->start && + git__prefixcmp(ti->stack->start, te->filename) == 0) + { + size_t namelen = strlen(te->filename); + if (ti->stack->start[namelen] == '/') + relpath = ti->stack->start + namelen + 1; + } + + if ((tf = tree_iterator__alloc_frame(subtree, relpath)) == NULL) + return -1; + + tf->next = ti->stack; + ti->stack = tf; + + te = tree_iterator__tree_entry(ti); + } + + return 0; +} + static int tree_iterator__advance( git_iterator *self, const git_index_entry **entry) { @@ -155,26 +237,40 @@ static int tree_iterator__advance( if (entry != NULL) *entry = NULL; - while (ti->stack != NULL) { - /* remove old entry filename */ + if (ti->path_has_filename) { git_buf_rtruncate_at_char(&ti->path, '/'); + ti->path_has_filename = false; + } + while (ti->stack != NULL) { te = git_tree_entry_byindex(ti->stack->tree, ++ti->stack->index); if (te != NULL) break; tree_iterator__pop_frame(ti); + + git_buf_rtruncate_at_char(&ti->path, '/'); } - if (te && entry_is_tree(te)) + if (te && git_tree_entry__is_tree(te)) error = tree_iterator__expand_tree(ti); - if (!error && entry != NULL) + if (!error) error = tree_iterator__current(self, entry); return error; } +static int tree_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* pop stack until matches prefix */ + /* seek item in current frame matching prefix */ + /* push stack which matches prefix */ + return -1; +} + static void tree_iterator__free(git_iterator *self) { tree_iterator *ti = (tree_iterator *)self; @@ -186,15 +282,25 @@ static void tree_iterator__free(git_iterator *self) static int tree_iterator__reset(git_iterator *self) { tree_iterator *ti = (tree_iterator *)self; + while (ti->stack && ti->stack->next) tree_iterator__pop_frame(ti); + if (ti->stack) - ti->stack->index = 0; + ti->stack->index = + git_tree__prefix_position(ti->stack->tree, ti->base.start); + + git_buf_clear(&ti->path); + return tree_iterator__expand_tree(ti); } -int git_iterator_for_tree( - git_repository *repo, git_tree *tree, git_iterator **iter) +int git_iterator_for_tree_range( + git_iterator **iter, + git_repository *repo, + git_tree *tree, + const char *start, + const char *end) { int error; tree_iterator *ti; @@ -202,22 +308,16 @@ int git_iterator_for_tree( if (tree == NULL) return git_iterator_for_nothing(iter); - ti = git__calloc(1, sizeof(tree_iterator)); - GITERR_CHECK_ALLOC(ti); + ITERATOR_BASE_INIT(ti, tree, TREE); - ti->base.type = GIT_ITERATOR_TREE; - ti->base.current = tree_iterator__current; - ti->base.at_end = tree_iterator__at_end; - ti->base.advance = tree_iterator__advance; - ti->base.reset = tree_iterator__reset; - ti->base.free = tree_iterator__free; - ti->repo = repo; - ti->stack = tree_iterator__alloc_frame(tree); + ti->repo = repo; + ti->stack = tree_iterator__alloc_frame(tree, ti->base.start); if ((error = tree_iterator__expand_tree(ti)) < 0) git_iterator_free((git_iterator *)ti); else *iter = (git_iterator *)ti; + return error; } @@ -232,7 +332,19 @@ static int index_iterator__current( git_iterator *self, const git_index_entry **entry) { index_iterator *ii = (index_iterator *)self; - *entry = git_index_get(ii->index, ii->current); + git_index_entry *ie = git_index_get(ii->index, ii->current); + + if (ie != NULL && + ii->base.end != NULL && + git__prefixcmp(ie->path, ii->base.end) > 0) + { + ii->current = git_index_entrycount(ii->index); + ie = NULL; + } + + if (entry) + *entry = ie; + return 0; } @@ -246,11 +358,19 @@ static int index_iterator__advance( git_iterator *self, const git_index_entry **entry) { index_iterator *ii = (index_iterator *)self; + if (ii->current < git_index_entrycount(ii->index)) ii->current++; - if (entry) - *entry = git_index_get(ii->index, ii->current); - return 0; + + return index_iterator__current(self, entry); +} + +static int index_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* find last item before prefix */ + return -1; } static int index_iterator__reset(git_iterator *self) @@ -267,24 +387,24 @@ static void index_iterator__free(git_iterator *self) ii->index = NULL; } -int git_iterator_for_index(git_repository *repo, git_iterator **iter) +int git_iterator_for_index_range( + git_iterator **iter, + git_repository *repo, + const char *start, + const char *end) { int error; - index_iterator *ii = git__calloc(1, sizeof(index_iterator)); - GITERR_CHECK_ALLOC(ii); + index_iterator *ii; - ii->base.type = GIT_ITERATOR_INDEX; - ii->base.current = index_iterator__current; - ii->base.at_end = index_iterator__at_end; - ii->base.advance = index_iterator__advance; - ii->base.reset = index_iterator__reset; - ii->base.free = index_iterator__free; - ii->current = 0; + ITERATOR_BASE_INIT(ii, index, INDEX); if ((error = git_repository_index(&ii->index, repo)) < 0) git__free(ii); - else + else { + ii->current = start ? git_index__prefix_position(ii->index, start) : 0; *iter = (git_iterator *)ii; + } + return error; } @@ -294,6 +414,7 @@ struct workdir_iterator_frame { workdir_iterator_frame *next; git_vector entries; unsigned int index; + char *start; }; typedef struct { @@ -332,6 +453,12 @@ static void workdir_iterator__free_frame(workdir_iterator_frame *wf) static int workdir_iterator__update_entry(workdir_iterator *wi); +static int workdir_iterator__entry_cmp(const void *prefix, const void *item) +{ + const git_path_with_stat *ps = item; + return git__prefixcmp((const char *)prefix, ps->path); +} + static int workdir_iterator__expand_dir(workdir_iterator *wi) { int error; @@ -345,6 +472,17 @@ static int workdir_iterator__expand_dir(workdir_iterator *wi) } git_vector_sort(&wf->entries); + + if (!wi->stack) + wf->start = wi->base.start; + else if (wi->stack->start && + git__prefixcmp(wi->stack->start, wi->path.ptr + wi->root_len) == 0) + wf->start = wi->stack->start; + + if (wf->start) + git_vector_bsearch3( + &wf->index, &wf->entries, workdir_iterator__entry_cmp, wf->start); + wf->next = wi->stack; wi->stack = wf; @@ -412,6 +550,16 @@ static int workdir_iterator__advance( return error; } +static int workdir_iterator__seek(git_iterator *self, const char *prefix) +{ + GIT_UNUSED(self); + GIT_UNUSED(prefix); + /* pop stack until matching prefix */ + /* find prefix item in current frame */ + /* push subdirectories as deep as possible while matching */ + return 0; +} + static int workdir_iterator__reset(git_iterator *self) { workdir_iterator *wi = (workdir_iterator *)self; @@ -445,10 +593,18 @@ static int workdir_iterator__update_entry(workdir_iterator *wi) git_path_with_stat *ps = git_vector_get(&wi->stack->entries, wi->stack->index); git_buf_truncate(&wi->path, wi->root_len); + memset(&wi->entry, 0, sizeof(wi->entry)); + + if (!ps) + return 0; + if (git_buf_put(&wi->path, ps->path, ps->path_len) < 0) return -1; - memset(&wi->entry, 0, sizeof(wi->entry)); + if (wi->base.end && + git__prefixcmp(wi->path.ptr + wi->root_len, wi->base.end) > 0) + return 0; + wi->entry.path = ps->path; /* skip over .git directory */ @@ -495,19 +651,26 @@ static int workdir_iterator__update_entry(workdir_iterator *wi) return 0; } -int git_iterator_for_workdir(git_repository *repo, git_iterator **iter) +int git_iterator_for_workdir_range( + git_iterator **iter, + git_repository *repo, + const char *start, + const char *end) { int error; - workdir_iterator *wi = git__calloc(1, sizeof(workdir_iterator)); - GITERR_CHECK_ALLOC(wi); + workdir_iterator *wi; - wi->base.type = GIT_ITERATOR_WORKDIR; - wi->base.current = workdir_iterator__current; - wi->base.at_end = workdir_iterator__at_end; - wi->base.advance = workdir_iterator__advance; - wi->base.reset = workdir_iterator__reset; - wi->base.free = workdir_iterator__free; - wi->repo = repo; + assert(iter && repo); + + if (git_repository_is_bare(repo)) { + giterr_set(GITERR_INVALID, + "Cannot scan working directory for bare repo"); + return -1; + } + + ITERATOR_BASE_INIT(wi, workdir, WORKDIR); + + wi->repo = repo; if (git_buf_sets(&wi->path, git_repository_workdir(repo)) < 0 || git_path_to_dir(&wi->path) < 0 || @@ -519,10 +682,16 @@ int git_iterator_for_workdir(git_repository *repo, git_iterator **iter) wi->root_len = wi->path.size; - if ((error = workdir_iterator__expand_dir(wi)) < 0) - git_iterator_free((git_iterator *)wi); - else - *iter = (git_iterator *)wi; + if ((error = workdir_iterator__expand_dir(wi)) < 0) { + if (error == GIT_ENOTFOUND) + error = 0; + else { + git_iterator_free((git_iterator *)wi); + wi = NULL; + } + } + + *iter = (git_iterator *)wi; return error; } @@ -559,3 +728,21 @@ int git_iterator_advance_into_directory( return entry ? git_iterator_current(iter, entry) : 0; } + +int git_iterator_cmp( + git_iterator *iter, const char *path_prefix) +{ + const git_index_entry *entry; + + /* a "done" iterator is after every prefix */ + if (git_iterator_current(iter, &entry) < 0 || + entry == NULL) + return 1; + + /* a NULL prefix is after any valid iterator */ + if (!path_prefix) + return -1; + + return git__prefixcmp(entry->path, path_prefix); +} + diff --git a/src/iterator.h b/src/iterator.h index 12eb96bb0..b916a9080 100644 --- a/src/iterator.h +++ b/src/iterator.h @@ -21,23 +21,48 @@ typedef enum { struct git_iterator { git_iterator_type_t type; + char *start; + char *end; int (*current)(git_iterator *, const git_index_entry **); int (*at_end)(git_iterator *); int (*advance)(git_iterator *, const git_index_entry **); + int (*seek)(git_iterator *, const char *prefix); int (*reset)(git_iterator *); void (*free)(git_iterator *); }; -int git_iterator_for_nothing(git_iterator **iter); +extern int git_iterator_for_nothing(git_iterator **iter); -int git_iterator_for_tree( - git_repository *repo, git_tree *tree, git_iterator **iter); +extern int git_iterator_for_tree_range( + git_iterator **iter, git_repository *repo, git_tree *tree, + const char *start, const char *end); -int git_iterator_for_index( - git_repository *repo, git_iterator **iter); +GIT_INLINE(int) git_iterator_for_tree( + git_iterator **iter, git_repository *repo, git_tree *tree) +{ + return git_iterator_for_tree_range(iter, repo, tree, NULL, NULL); +} + +extern int git_iterator_for_index_range( + git_iterator **iter, git_repository *repo, + const char *start, const char *end); + +GIT_INLINE(int) git_iterator_for_index( + git_iterator **iter, git_repository *repo) +{ + return git_iterator_for_index_range(iter, repo, NULL, NULL); +} + +extern int git_iterator_for_workdir_range( + git_iterator **iter, git_repository *repo, + const char *start, const char *end); + +GIT_INLINE(int) git_iterator_for_workdir( + git_iterator **iter, git_repository *repo) +{ + return git_iterator_for_workdir_range(iter, repo, NULL, NULL); +} -int git_iterator_for_workdir( - git_repository *repo, git_iterator **iter); /* Entry is not guaranteed to be fully populated. For a tree iterator, * we will only populate the mode, oid and path, for example. For a workdir @@ -64,6 +89,12 @@ GIT_INLINE(int) git_iterator_advance( return iter->advance(iter, entry); } +GIT_INLINE(int) git_iterator_seek( + git_iterator *iter, const char *prefix) +{ + return iter->seek(iter, prefix); +} + GIT_INLINE(int) git_iterator_reset(git_iterator *iter) { return iter->reset(iter); @@ -71,7 +102,16 @@ GIT_INLINE(int) git_iterator_reset(git_iterator *iter) GIT_INLINE(void) git_iterator_free(git_iterator *iter) { + if (iter == NULL) + return; + iter->free(iter); + + git__free(iter->start); + git__free(iter->end); + + memset(iter, 0, sizeof(*iter)); + git__free(iter); } @@ -105,4 +145,7 @@ extern int git_iterator_current_is_ignored(git_iterator *iter); extern int git_iterator_advance_into_directory( git_iterator *iter, const git_index_entry **entry); +extern int git_iterator_cmp( + git_iterator *iter, const char *path_prefix); + #endif diff --git a/src/mwindow.c b/src/mwindow.c index b59c4d2f7..57adabd48 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -89,7 +89,6 @@ void git_mwindow_scan_lru( { git_mwindow *w, *w_l; - puts("LRU"); for (w_l = NULL, w = mwf->windows; w; w = w->next) { if (!w->inuse_cnt) { /* @@ -247,7 +246,6 @@ unsigned char *git_mwindow_open( if (left) *left = (unsigned int)(w->window_map.len - offset); - fflush(stdout); return (unsigned char *) w->window_map.data + offset; } diff --git a/src/netops.c b/src/netops.c index 4d461a049..e16cae8e6 100644 --- a/src/netops.c +++ b/src/netops.c @@ -12,9 +12,9 @@ # include #else # include -# include +# include # ifdef _MSC_VER -# pragma comment(lib, "Ws2_32.lib") +# pragma comment(lib, "ws2_32.lib") # endif #endif diff --git a/src/notes.c b/src/notes.c index 4afdac0bd..84ad94087 100644 --- a/src/notes.c +++ b/src/notes.c @@ -10,6 +10,7 @@ #include "git2.h" #include "refs.h" #include "config.h" +#include "iterator.h" static int find_subtree(git_tree **subtree, const git_oid *root, git_repository *repo, const char *target, int *fanout) @@ -273,7 +274,7 @@ static int note_get_default_ref(const char **out, git_repository *repo) if (git_repository_config__weakptr(&cfg, repo) < 0) return -1; - ret = git_config_get_string(cfg, "core.notesRef", out); + ret = git_config_get_string(out, cfg, "core.notesRef"); if (ret == GIT_ENOTFOUND) { *out = GIT_NOTES_DEFAULT_REF; return 0; @@ -282,41 +283,54 @@ static int note_get_default_ref(const char **out, git_repository *repo) return ret; } +static int normalize_namespace(const char **notes_ref, git_repository *repo) +{ + if (*notes_ref) + return 0; + + return note_get_default_ref(notes_ref, repo); +} + +static int retrieve_note_tree_oid(git_oid *tree_oid_out, git_repository *repo, const char *notes_ref) +{ + int error = -1; + git_commit *commit = NULL; + git_oid oid; + + if ((error = git_reference_name_to_oid(&oid, repo, notes_ref)) < 0) + goto cleanup; + + if (git_commit_lookup(&commit, repo, &oid) < 0) + goto cleanup; + + git_oid_cpy(tree_oid_out, git_commit_tree_oid(commit)); + + error = 0; + +cleanup: + git_commit_free(commit); + return error; +} + int git_note_read(git_note **out, git_repository *repo, const char *notes_ref, const git_oid *oid) { int error; char *target; - git_reference *ref; - git_commit *commit; - const git_oid *sha; + git_oid sha; *out = NULL; - if (!notes_ref && note_get_default_ref(¬es_ref, repo) < 0) + if (normalize_namespace(¬es_ref, repo) < 0) return -1; - error = git_reference_lookup(&ref, repo, notes_ref); - if (error < 0) + if ((error = retrieve_note_tree_oid(&sha, repo, notes_ref)) < 0) return error; - assert(git_reference_type(ref) == GIT_REF_OID); - - sha = git_reference_oid(ref); - error = git_commit_lookup(&commit, repo, sha); - - git_reference_free(ref); - - if (error < 0) - return error; - - sha = git_commit_tree_oid(commit); - git_commit_free(commit); - target = git_oid_allocfmt(oid); GITERR_CHECK_ALLOC(target); - error = note_lookup(out, repo, sha, target); + error = note_lookup(out, repo, &sha, target); git__free(target); return error; @@ -334,7 +348,7 @@ int git_note_create( git_commit *commit = NULL; git_reference *ref; - if (!notes_ref && note_get_default_ref(¬es_ref, repo) < 0) + if (normalize_namespace(¬es_ref, repo) < 0) return -1; error = git_reference_lookup(&ref, repo, notes_ref); @@ -379,8 +393,7 @@ int git_note_remove(git_repository *repo, const char *notes_ref, git_commit *commit; git_reference *ref; - - if (!notes_ref && note_get_default_ref(¬es_ref, repo) < 0) + if (normalize_namespace(¬es_ref, repo) < 0) return -1; error = git_reference_lookup(&ref, repo, notes_ref); @@ -435,3 +448,101 @@ void git_note_free(git_note *note) git__free(note->message); git__free(note); } + +static int process_entry_path( + const char* entry_path, + const git_oid *note_oid, + int (*note_cb)(git_note_data *note_data, void *payload), + void *payload) +{ + int i = 0, j = 0, error = -1, len; + git_buf buf = GIT_BUF_INIT; + git_note_data note_data; + + if (git_buf_puts(&buf, entry_path) < 0) + goto cleanup; + + len = git_buf_len(&buf); + + while (i < len) { + if (buf.ptr[i] == '/') { + i++; + continue; + } + + if (git__fromhex(buf.ptr[i]) < 0) { + /* This is not a note entry */ + error = 0; + goto cleanup; + } + + if (i != j) + buf.ptr[j] = buf.ptr[i]; + + i++; + j++; + } + + buf.ptr[j] = '\0'; + buf.size = j; + + if (j != GIT_OID_HEXSZ) { + /* This is not a note entry */ + error = 0; + goto cleanup; + } + + if (git_oid_fromstr(¬e_data.annotated_object_oid, buf.ptr) < 0) + return -1; + + git_oid_cpy(¬e_data.blob_oid, note_oid); + + error = note_cb(¬e_data, payload); + +cleanup: + git_buf_free(&buf); + return error; +} + +int git_note_foreach( + git_repository *repo, + const char *notes_ref, + int (*note_cb)(git_note_data *note_data, void *payload), + void *payload) +{ + int error = -1; + git_oid tree_oid; + git_iterator *iter = NULL; + git_tree *tree = NULL; + const git_index_entry *item; + + if (normalize_namespace(¬es_ref, repo) < 0) + return -1; + + if ((error = retrieve_note_tree_oid(&tree_oid, repo, notes_ref)) < 0) + goto cleanup; + + if (git_tree_lookup(&tree, repo, &tree_oid) < 0) + goto cleanup; + + if (git_iterator_for_tree(&iter, repo, tree) < 0) + goto cleanup; + + if (git_iterator_current(iter, &item) < 0) + goto cleanup; + + while (item) { + if (process_entry_path(item->path, &item->oid, note_cb, payload) < 0) + goto cleanup; + + if (git_iterator_advance(iter, &item) < 0) + goto cleanup; + } + + error = 0; + +cleanup: + git_iterator_free(iter); + git_tree_free(tree); + return error; +} diff --git a/src/object.c b/src/object.c index 02be5dac8..d3673eda0 100644 --- a/src/object.c +++ b/src/object.c @@ -74,7 +74,7 @@ static int create_object(git_object **object_out, git_otype type) object->type = type; *object_out = object; - return GIT_SUCCESS; + return 0; } int git_object_lookup_prefix( @@ -87,7 +87,7 @@ int git_object_lookup_prefix( git_object *object = NULL; git_odb *odb = NULL; git_odb_object *odb_obj; - int error = GIT_SUCCESS; + int error = 0; assert(repo && object_out && id); @@ -95,7 +95,7 @@ int git_object_lookup_prefix( return GIT_EAMBIGUOUS; error = git_repository_odb__weakptr(&odb, repo); - if (error < GIT_SUCCESS) + if (error < 0) return error; if (len > GIT_OID_HEXSZ) @@ -109,8 +109,8 @@ int git_object_lookup_prefix( if (object != NULL) { if (type != GIT_OBJ_ANY && type != object->type) { git_object_free(object); - giterr_set(GITERR_INVALID, "The given type does not match the type in ODB"); - return -1; + giterr_set(GITERR_ODB, "The given type does not match the type in ODB"); + return GIT_ENOTFOUND; } *object_out = object; diff --git a/src/odb.c b/src/odb.c index 934b317ed..a6a18f831 100644 --- a/src/odb.c +++ b/src/odb.c @@ -505,7 +505,7 @@ int git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *db, const git error = b->read_header(len_p, type_p, b, id); } - if (!error || error == GIT_EPASSTHROUGH) + if (!error || error == GIT_PASSTHROUGH) return 0; /* @@ -545,7 +545,7 @@ int git_odb_read(git_odb_object **out, git_odb *db, const git_oid *id) * will never have called giterr_set(). */ - if (error && error != GIT_EPASSTHROUGH) + if (error && error != GIT_PASSTHROUGH) return error; *out = git_cache_try_store(&db->cache, new_odb_object(id, &raw)); @@ -557,9 +557,9 @@ int git_odb_read_prefix( { unsigned int i; int error = GIT_ENOTFOUND; - git_oid full_oid; + git_oid found_full_oid = {{0}}; git_rawobj raw; - int found = 0; + bool found = false; assert(out && db); @@ -575,25 +575,30 @@ int git_odb_read_prefix( return 0; } - for (i = 0; i < db->backends.length && found < 2; ++i) { + for (i = 0; i < db->backends.length; ++i) { backend_internal *internal = git_vector_get(&db->backends, i); git_odb_backend *b = internal->backend; if (b->read != NULL) { + git_oid full_oid; error = b->read_prefix(&full_oid, &raw.data, &raw.len, &raw.type, b, short_id, len); - if (!error) - found++; - else if (error != GIT_ENOTFOUND && error != GIT_EPASSTHROUGH) + if (error == GIT_ENOTFOUND || error == GIT_PASSTHROUGH) + continue; + + if (error) return error; + + if (found && git_oid_cmp(&full_oid, &found_full_oid)) + return git_odb__error_ambiguous("multiple matches for prefix"); + found_full_oid = full_oid; + found = true; } } - if (found == 0) + if (!found) return git_odb__error_notfound("no match for prefix", short_id); - if (found > 1) - return git_odb__error_ambiguous("multiple matches for prefix"); - *out = git_cache_try_store(&db->cache, new_odb_object(&full_oid, &raw)); + *out = git_cache_try_store(&db->cache, new_odb_object(&found_full_oid, &raw)); return 0; } @@ -618,7 +623,7 @@ int git_odb_write( error = b->write(oid, b, data, len, type); } - if (!error || error == GIT_EPASSTHROUGH) + if (!error || error == GIT_PASSTHROUGH) return 0; /* if no backends were able to write the object directly, we try a streaming @@ -657,7 +662,7 @@ int git_odb_open_wstream( error = init_fake_wstream(stream, b, size, type); } - if (error == GIT_EPASSTHROUGH) + if (error == GIT_PASSTHROUGH) error = 0; return error; @@ -678,7 +683,7 @@ int git_odb_open_rstream(git_odb_stream **stream, git_odb *db, const git_oid *oi error = b->readstream(stream, b, oid); } - if (error == GIT_EPASSTHROUGH) + if (error == GIT_PASSTHROUGH) error = 0; return error; diff --git a/src/pack.c b/src/pack.c index 4a6bc6ae8..0db1069de 100644 --- a/src/pack.c +++ b/src/pack.c @@ -222,7 +222,7 @@ static int packfile_unpack_header1( shift = 4; while (c & 0x80) { if (len <= used) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; if (bitsizeof(long) <= shift) { *usedp = 0; @@ -260,11 +260,11 @@ int git_packfile_unpack_header( // base = pack_window_open(p, w_curs, *curpos, &left); base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); - if (ret == GIT_ESHORTBUFFER) + if (ret == GIT_EBUFS) return ret; else if (ret < 0) return packfile_error("header length is zero"); @@ -428,7 +428,7 @@ int packfile_unpack_compressed( if (st == Z_BUF_ERROR && in == NULL) { inflateEnd(&stream); git__free(buffer); - return GIT_ESHORTBUFFER; + return GIT_EBUFS; } *curpos += stream.next_in - in; @@ -467,7 +467,7 @@ git_off_t get_delta_base( base_info = pack_window_open(p, w_curs, *curpos, &left); /* Assumption: the only reason this would fail is because the file is too small */ if (base_info == NULL) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; /* pack_window_open() assured us we have [base_info, base_info + 20) * as a range that we can look at without walking off the * end of the mapped window. Its actually the hash size @@ -480,7 +480,7 @@ git_off_t get_delta_base( base_offset = c & 127; while (c & 128) { if (left <= used) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; base_offset += 1; if (!base_offset || MSB(base_offset, 7)) return 0; /* overflow */ diff --git a/src/path.c b/src/path.c index 9f31676b1..84edf6d89 100644 --- a/src/path.c +++ b/src/path.c @@ -494,7 +494,7 @@ int git_path_direach( { ssize_t wd_len; DIR *dir; - struct dirent de_buf, *de; + struct dirent *de, *de_buf; if (git_path_to_dir(path) < 0) return -1; @@ -506,14 +506,23 @@ int git_path_direach( return -1; } - while (p_readdir_r(dir, &de_buf, &de) == 0 && de != NULL) { +#ifdef __sun + de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); +#else + de_buf = git__malloc(sizeof(struct dirent)); +#endif + + while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) continue; - if (git_buf_puts(path, de->d_name) < 0) + if (git_buf_puts(path, de->d_name) < 0) { + closedir(dir); + git__free(de_buf); return -1; + } result = fn(arg, path); @@ -521,11 +530,13 @@ int git_path_direach( if (result < 0) { closedir(dir); + git__free(de_buf); return -1; } } closedir(dir); + git__free(de_buf); return 0; } @@ -537,7 +548,7 @@ int git_path_dirload( { int error, need_slash; DIR *dir; - struct dirent de_buf, *de; + struct dirent *de, *de_buf; size_t path_len; assert(path != NULL && contents != NULL); @@ -549,11 +560,17 @@ int git_path_dirload( return -1; } +#ifdef __sun + de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); +#else + de_buf = git__malloc(sizeof(struct dirent)); +#endif + path += prefix_len; path_len -= prefix_len; need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0; - while ((error = p_readdir_r(dir, &de_buf, &de)) == 0 && de != NULL) { + while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) { char *entry_path; size_t entry_len; @@ -573,11 +590,15 @@ int git_path_dirload( memcpy(&entry_path[path_len + need_slash], de->d_name, entry_len); entry_path[path_len + need_slash + entry_len] = '\0'; - if (git_vector_insert(contents, entry_path) < 0) + if (git_vector_insert(contents, entry_path) < 0) { + closedir(dir); + git__free(de_buf); return -1; + } } closedir(dir); + git__free(de_buf); if (error != 0) giterr_set(GITERR_OS, "Failed to process directory entry in '%s'", path); diff --git a/src/pkt.c b/src/pkt.c index b9c87f169..95430ddfc 100644 --- a/src/pkt.c +++ b/src/pkt.c @@ -208,7 +208,7 @@ int git_pkt_parse_line( /* Not even enough for the length */ if (bufflen > 0 && bufflen < PKT_LEN_SIZE) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; len = parse_len(line); if (len < 0) { @@ -230,7 +230,7 @@ int git_pkt_parse_line( * enough in the buffer to satisfy this line */ if (bufflen > 0 && bufflen < (size_t)len) - return GIT_ESHORTBUFFER; + return GIT_EBUFS; line += PKT_LEN_SIZE; /* diff --git a/src/protocol.c b/src/protocol.c index a75354121..6b3861796 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -34,7 +34,7 @@ int git_protocol_store_refs(git_protocol *p, const char *data, size_t len) return 0; error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf)); - if (error == GIT_ESHORTBUFFER) + if (error == GIT_EBUFS) return 0; /* Ask for more */ if (error < 0) return p->error = -1; diff --git a/src/refs.c b/src/refs.c index 28e8f786b..1ef3e13a4 100644 --- a/src/refs.c +++ b/src/refs.c @@ -194,10 +194,10 @@ corrupt: return -1; } -static git_rtype loose_guess_rtype(const git_buf *full_path) +static git_ref_t loose_guess_rtype(const git_buf *full_path) { git_buf ref_file = GIT_BUF_INIT; - git_rtype type; + git_ref_t type; type = GIT_REF_INVALID; @@ -1153,7 +1153,7 @@ int git_reference_lookup_resolved( /** * Getters */ -git_rtype git_reference_type(git_reference *ref) +git_ref_t git_reference_type(git_reference *ref) { assert(ref); @@ -1518,7 +1518,7 @@ static int cb__reflist_add(const char *ref, void *data) return git_vector_insert((git_vector *)data, git__strdup(ref)); } -int git_reference_listall( +int git_reference_list( git_strarray *array, git_repository *repo, unsigned int list_flags) diff --git a/src/refspec.c b/src/refspec.c index ee4d3a158..b6b1158b7 100644 --- a/src/refspec.c +++ b/src/refspec.c @@ -53,6 +53,13 @@ const char *git_refspec_dst(const git_refspec *refspec) return refspec == NULL ? NULL : refspec->dst; } +int git_refspec_force(const git_refspec *refspec) +{ + assert(refspec); + + return refspec->force; +} + int git_refspec_src_matches(const git_refspec *refspec, const char *refname) { if (refspec == NULL || refspec->src == NULL) @@ -68,7 +75,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con baselen = strlen(spec->dst); if (outlen <= baselen) { giterr_set(GITERR_INVALID, "Reference name too long"); - return GIT_ESHORTBUFFER; + return GIT_EBUFS; } /* @@ -90,7 +97,7 @@ int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, con if (outlen <= baselen + namelen) { giterr_set(GITERR_INVALID, "Reference name too long"); - return GIT_ESHORTBUFFER; + return GIT_EBUFS; } memcpy(out, spec->dst, baselen); diff --git a/src/refspec.h b/src/refspec.h index 64c0ded0c..2db504910 100644 --- a/src/refspec.h +++ b/src/refspec.h @@ -28,7 +28,7 @@ int git_refspec_parse(struct git_refspec *refspec, const char *str); * @param out where to store the target name * @param spec the refspec * @param name the name of the reference to transform - * @return GIT_SUCCESS or error if buffer allocation fails + * @return 0 or error if buffer allocation fails */ int git_refspec_transform_r(git_buf *out, const git_refspec *spec, const char *name); diff --git a/src/remote.c b/src/remote.c index a5cfc822e..5993ad02b 100644 --- a/src/remote.c +++ b/src/remote.c @@ -48,7 +48,7 @@ static int parse_remote_refspec(git_config *cfg, git_refspec *refspec, const cha int error; const char *val; - if ((error = git_config_get_string(cfg, var, &val)) < 0) + if ((error = git_config_get_string(&val, cfg, var)) < 0) return error; return refspec_parse(refspec, val); @@ -121,7 +121,7 @@ int git_remote_load(git_remote **out, git_repository *repo, const char *name) goto cleanup; } - if ((error = git_config_get_string(config, git_buf_cstr(&buf), &val)) < 0) + if ((error = git_config_get_string(&val, config, git_buf_cstr(&buf))) < 0) goto cleanup; remote->repo = repo; @@ -189,6 +189,8 @@ int git_remote_save(const git_remote *remote) git_buf_clear(&buf); git_buf_clear(&value); git_buf_printf(&buf, "remote.%s.fetch", remote->name); + if (remote->fetch.force) + git_buf_putc(&value, '+'); git_buf_printf(&value, "%s:%s", remote->fetch.src, remote->fetch.dst); if (git_buf_oom(&buf) || git_buf_oom(&value)) return -1; @@ -201,6 +203,8 @@ int git_remote_save(const git_remote *remote) git_buf_clear(&buf); git_buf_clear(&value); git_buf_printf(&buf, "remote.%s.push", remote->name); + if (remote->push.force) + git_buf_putc(&value, '+'); git_buf_printf(&value, "%s:%s", remote->push.src, remote->push.dst); if (git_buf_oom(&buf) || git_buf_oom(&value)) return -1; @@ -338,7 +342,7 @@ int git_remote_update_tips(git_remote *remote, int (*cb)(const char *refname, co assert(remote); if (refs->length == 0) - return GIT_SUCCESS; + return 0; /* HEAD is only allowed to be the first in the list */ head = refs->contents[0]; @@ -490,7 +494,7 @@ int git_remote_add(git_remote **out, git_repository *repo, const char *name, con { git_buf buf = GIT_BUF_INIT; - if (git_buf_printf(&buf, "refs/heads/*:refs/remotes/%s/*", name) < 0) + if (git_buf_printf(&buf, "+refs/heads/*:refs/remotes/%s/*", name) < 0) return -1; if (git_remote_new(out, repo, name, url, git_buf_cstr(&buf)) < 0) diff --git a/src/repository.c b/src/repository.c index 886de5806..5120356bf 100644 --- a/src/repository.c +++ b/src/repository.c @@ -25,8 +25,7 @@ #define GIT_BRANCH_MASTER "master" -#define GIT_CONFIG_CORE_REPOSITORYFORMATVERSION "core.repositoryformatversion" -#define GIT_REPOSITORYFORMATVERSION 0 +#define GIT_REPO_VERSION 0 static void drop_odb(git_repository *repo) { @@ -125,11 +124,12 @@ static int load_config_data(git_repository *repo) if (git_repository_config__weakptr(&config, repo) < 0) return -1; - if (git_config_get_bool(config, "core.bare", &is_bare) < 0) - return -1; /* FIXME: We assume that a missing core.bare - variable is an error. Is this right? */ + /* Try to figure out if it's bare, default to non-bare if it's not set */ + if (git_config_get_bool(&is_bare, config, "core.bare") < 0) + repo->is_bare = 0; + else + repo->is_bare = is_bare; - repo->is_bare = is_bare; return 0; } @@ -146,7 +146,7 @@ static int load_workdir(git_repository *repo, git_buf *parent_path) if (git_repository_config__weakptr(&config, repo) < 0) return -1; - error = git_config_get_string(config, "core.worktree", &worktree); + error = git_config_get_string(&worktree, config, "core.worktree"); if (!error && worktree != NULL) repo->workdir = git__strdup(worktree); else if (error != GIT_ENOTFOUND) @@ -607,13 +607,13 @@ static int check_repositoryformatversion(git_repository *repo) if (git_repository_config__weakptr(&config, repo) < 0) return -1; - if (git_config_get_int32(config, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, &version) < 0) + if (git_config_get_int32(&version, config, "core.repositoryformatversion") < 0) return -1; - if (GIT_REPOSITORYFORMATVERSION < version) { + if (GIT_REPO_VERSION < version) { giterr_set(GITERR_REPOSITORY, "Unsupported repository version %d. Only versions up to %d are supported.", - version, GIT_REPOSITORYFORMATVERSION); + version, GIT_REPO_VERSION); return -1; } @@ -676,7 +676,7 @@ static int repo_init_config(const char *git_dir, int is_bare) } SET_REPO_CONFIG(bool, "core.bare", is_bare); - SET_REPO_CONFIG(int32, GIT_CONFIG_CORE_REPOSITORYFORMATVERSION, GIT_REPOSITORYFORMATVERSION); + SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION); /* TODO: what other defaults? */ git_buf_free(&cfg_path); @@ -684,6 +684,59 @@ static int repo_init_config(const char *git_dir, int is_bare) return 0; } +#define GIT_HOOKS_DIR "hooks/" +#define GIT_HOOKS_DIR_MODE 0755 + +#define GIT_HOOKS_README_FILE GIT_HOOKS_DIR "README.sample" +#define GIT_HOOKS_README_MODE 0755 +#define GIT_HOOKS_README_CONTENT \ +"#!/bin/sh\n"\ +"#\n"\ +"# Place appropriately named executable hook scripts into this directory\n"\ +"# to intercept various actions that git takes. See `git help hooks` for\n"\ +"# more information.\n" + +#define GIT_INFO_DIR "info/" +#define GIT_INFO_DIR_MODE 0755 + +#define GIT_INFO_EXCLUDE_FILE GIT_INFO_DIR "exclude" +#define GIT_INFO_EXCLUDE_MODE 0644 +#define GIT_INFO_EXCLUDE_CONTENT \ +"# File patterns to ignore; see `git help ignore` for more information.\n"\ +"# Lines that start with '#' are comments.\n" + +#define GIT_DESC_FILE "description" +#define GIT_DESC_MODE 0644 +#define GIT_DESC_CONTENT "Unnamed repository; edit this file 'description' to name the repository.\n" + +static int repo_write_template( + const char *git_dir, const char *file, mode_t mode, const char *content) +{ + git_buf path = GIT_BUF_INIT; + int fd, error = 0; + + if (git_buf_joinpath(&path, git_dir, file) < 0) + return -1; + + fd = p_open(git_buf_cstr(&path), O_WRONLY | O_CREAT | O_EXCL, mode); + + if (fd >= 0) { + error = p_write(fd, content, strlen(content)); + + p_close(fd); + } + else if (errno != EEXIST) + error = fd; + + git_buf_free(&path); + + if (error) + giterr_set(GITERR_OS, + "Failed to initialize repository with template '%s'", file); + + return error; +} + static int repo_init_structure(const char *git_dir, int is_bare) { int i; @@ -692,8 +745,16 @@ static int repo_init_structure(const char *git_dir, int is_bare) { GIT_OBJECTS_PACK_DIR, GIT_OBJECT_DIR_MODE }, /* '/objects/pack/' */ { GIT_REFS_HEADS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/heads/' */ { GIT_REFS_TAGS_DIR, GIT_REFS_DIR_MODE }, /* '/refs/tags/' */ + { GIT_HOOKS_DIR, GIT_HOOKS_DIR_MODE }, /* '/hooks/' */ + { GIT_INFO_DIR, GIT_INFO_DIR_MODE }, /* '/info/' */ { NULL, 0 } }; + struct { const char *file; mode_t mode; const char *content; } tmpl[] = { + { GIT_DESC_FILE, GIT_DESC_MODE, GIT_DESC_CONTENT }, + { GIT_HOOKS_README_FILE, GIT_HOOKS_README_MODE, GIT_HOOKS_README_CONTENT }, + { GIT_INFO_EXCLUDE_FILE, GIT_INFO_EXCLUDE_MODE, GIT_INFO_EXCLUDE_CONTENT }, + { NULL, 0, NULL } + }; /* Make the base directory */ if (git_futils_mkdir_r(git_dir, NULL, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE) < 0) @@ -716,7 +777,13 @@ static int repo_init_structure(const char *git_dir, int is_bare) return -1; } - /* TODO: what's left? templates? */ + /* Make template files as needed */ + for (i = 0; tmpl[i].file != NULL; ++i) { + if (repo_write_template( + git_dir, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0) + return -1; + } + return 0; } diff --git a/src/revwalk.c b/src/revwalk.c index 1b539787f..e64d93f20 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -316,7 +316,7 @@ static int merge_bases_many(commit_list **out, git_revwalk *walk, commit_object if ((p->flags & flags) == flags) continue; - if ((error = commit_parse(walk, p)) < GIT_SUCCESS) + if ((error = commit_parse(walk, p)) < 0) return error; p->flags |= flags; @@ -600,7 +600,7 @@ static int revwalk_next_timesort(commit_object **object_out, git_revwalk *walk) } } - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; } static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk) @@ -618,7 +618,7 @@ static int revwalk_next_unsorted(commit_object **object_out, git_revwalk *walk) } } - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; } static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) @@ -629,7 +629,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) for (;;) { next = commit_list_pop(&walk->iterator_topo); if (next == NULL) - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; if (next->in_degree > 0) { next->topo_delay = 1; @@ -654,7 +654,7 @@ static int revwalk_next_toposort(commit_object **object_out, git_revwalk *walk) static int revwalk_next_reverse(commit_object **object_out, git_revwalk *walk) { *object_out = commit_list_pop(&walk->iterator_reverse); - return *object_out ? 0 : GIT_EREVWALKOVER; + return *object_out ? 0 : GIT_REVWALKOVER; } @@ -670,7 +670,7 @@ static int prepare_walk(git_revwalk *walk) * so we know that the walk is already over. */ if (walk->one == NULL) - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; /* first figure out what the merge bases are */ if (merge_bases_many(&bases, walk, walk->one, &walk->twos) < 0) @@ -698,7 +698,7 @@ static int prepare_walk(git_revwalk *walk) return -1; } - if (error != GIT_EREVWALKOVER) + if (error != GIT_REVWALKOVER) return error; walk->get_next = &revwalk_next_toposort; @@ -710,7 +710,7 @@ static int prepare_walk(git_revwalk *walk) if (commit_list_insert(next, &walk->iterator_reverse) == NULL) return -1; - if (error != GIT_EREVWALKOVER) + if (error != GIT_REVWALKOVER) return error; walk->get_next = &revwalk_next_reverse; @@ -809,9 +809,9 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk) error = walk->get_next(&next, walk); - if (error == GIT_EREVWALKOVER) { + if (error == GIT_REVWALKOVER) { git_revwalk_reset(walk); - return GIT_EREVWALKOVER; + return GIT_REVWALKOVER; } if (!error) @@ -838,5 +838,8 @@ void git_revwalk_reset(git_revwalk *walk) commit_list_free(&walk->iterator_rand); commit_list_free(&walk->iterator_reverse); walk->walking = 0; + + walk->one = NULL; + git_vector_clear(&walk->twos); } diff --git a/src/signature.c b/src/signature.c index 74ef84376..6b28a3e4c 100644 --- a/src/signature.c +++ b/src/signature.c @@ -155,7 +155,7 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) if (*offset_start == '\n') { *offset_out = 0; - return GIT_SUCCESS; + return 0; } if (offset_start[0] != '-' && offset_start[0] != '+') @@ -164,7 +164,7 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) if (offset_start[1] < '0' || offset_start[1] > '9') return timezone_error("expected initial digit"); - if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS) + if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < 0) return timezone_error("not a valid number"); if (offset_end - offset_start != 5) diff --git a/src/status.c b/src/status.c index d07b0c41c..e9ad3cfe4 100644 --- a/src/status.c +++ b/src/status.c @@ -70,7 +70,7 @@ static unsigned int workdir_delta2status(git_delta_t workdir_status) int git_status_foreach_ext( git_repository *repo, - git_status_options *opts, + const git_status_options *opts, int (*cb)(const char *, unsigned int, void *), void *cbdata) { @@ -163,244 +163,71 @@ int git_status_foreach( return git_status_foreach_ext(repo, &opts, callback, payload); } - -/* - * the old stuff - */ - -struct status_entry { - git_index_time mtime; - - git_oid head_oid; - git_oid index_oid; - git_oid wt_oid; - - unsigned int status_flags; - - char path[GIT_FLEX_ARRAY]; /* more */ +struct status_file_info { + unsigned int count; + unsigned int status; + char *expected; }; -static struct status_entry *status_entry_new(git_vector *entries, const char *path) +static int get_one_status(const char *path, unsigned int status, void *data) { - struct status_entry *e = git__calloc(sizeof(*e) + strlen(path) + 1, 1); - if (e == NULL) - return NULL; + struct status_file_info *sfi = data; - if (entries != NULL) - git_vector_insert(entries, e); + sfi->count++; + sfi->status = status; - strcpy(e->path, path); - - return e; -} - -GIT_INLINE(void) status_entry_update_from_tree_entry(struct status_entry *e, const git_tree_entry *tree_entry) -{ - assert(e && tree_entry); - - git_oid_cpy(&e->head_oid, &tree_entry->oid); -} - -GIT_INLINE(void) status_entry_update_from_index_entry(struct status_entry *e, const git_index_entry *index_entry) -{ - assert(e && index_entry); - - git_oid_cpy(&e->index_oid, &index_entry->oid); - e->mtime = index_entry->mtime; -} - -static void status_entry_update_from_index(struct status_entry *e, git_index *index) -{ - int idx; - git_index_entry *index_entry; - - assert(e && index); - - idx = git_index_find(index, e->path); - if (idx < 0) - return; - - index_entry = git_index_get(index, idx); - - status_entry_update_from_index_entry(e, index_entry); -} - -static int status_entry_update_from_workdir(struct status_entry *e, const char* full_path) -{ - struct stat filest; - - if (p_stat(full_path, &filest) < 0) { - giterr_set(GITERR_OS, "Cannot access file '%s'", full_path); - return GIT_ENOTFOUND; - } - - if (e->mtime.seconds == (git_time_t)filest.st_mtime) - git_oid_cpy(&e->wt_oid, &e->index_oid); - else - git_odb_hashfile(&e->wt_oid, full_path, GIT_OBJ_BLOB); - - return 0; -} - -static int status_entry_update_flags(struct status_entry *e) -{ - git_oid zero; - int head_zero, index_zero, wt_zero; - - memset(&zero, 0x0, sizeof(git_oid)); - - head_zero = git_oid_cmp(&zero, &e->head_oid); - index_zero = git_oid_cmp(&zero, &e->index_oid); - wt_zero = git_oid_cmp(&zero, &e->wt_oid); - - if (head_zero == 0 && index_zero == 0 && wt_zero == 0) - return GIT_ENOTFOUND; - - if (head_zero == 0 && index_zero != 0) - e->status_flags |= GIT_STATUS_INDEX_NEW; - else if (index_zero == 0 && head_zero != 0) - e->status_flags |= GIT_STATUS_INDEX_DELETED; - else if (git_oid_cmp(&e->head_oid, &e->index_oid) != 0) - e->status_flags |= GIT_STATUS_INDEX_MODIFIED; - - if (index_zero == 0 && wt_zero != 0) - e->status_flags |= GIT_STATUS_WT_NEW; - else if (wt_zero == 0 && index_zero != 0) - e->status_flags |= GIT_STATUS_WT_DELETED; - else if (git_oid_cmp(&e->index_oid, &e->wt_oid) != 0) - e->status_flags |= GIT_STATUS_WT_MODIFIED; - - return 0; -} - -static int status_entry_is_ignorable(struct status_entry *e) -{ - /* don't ignore files that exist in head or index already */ - return (e->status_flags == GIT_STATUS_WT_NEW); -} - -static int status_entry_update_ignore(struct status_entry *e, git_ignores *ignores, const char *path) -{ - int ignored; - - if (git_ignore__lookup(ignores, path, &ignored) < 0) + if (sfi->count > 1 || strcmp(sfi->expected, path) != 0) { + giterr_set(GITERR_INVALID, + "Ambiguous path '%s' given to git_status_file", sfi->expected); return -1; - - if (ignored) - /* toggle off WT_NEW and on IGNORED */ - e->status_flags = - (e->status_flags & ~GIT_STATUS_WT_NEW) | GIT_STATUS_IGNORED; + } return 0; } -static int recurse_tree_entry(git_tree *tree, struct status_entry *e, const char *path) -{ - char *dir_sep; - const git_tree_entry *tree_entry; - git_tree *subtree; - int error; - - dir_sep = strchr(path, '/'); - if (!dir_sep) { - if ((tree_entry = git_tree_entry_byname(tree, path)) != NULL) - /* The leaf exists in the tree*/ - status_entry_update_from_tree_entry(e, tree_entry); - return 0; - } - - /* Retrieve subtree name */ - *dir_sep = '\0'; - - if ((tree_entry = git_tree_entry_byname(tree, path)) == NULL) - return 0; /* The subtree doesn't exist in the tree*/ - - *dir_sep = '/'; - - /* Retreive subtree */ - error = git_tree_lookup(&subtree, tree->object.repo, &tree_entry->oid); - if (!error) { - error = recurse_tree_entry(subtree, e, dir_sep+1); - git_tree_free(subtree); - } - - return error; -} - int git_status_file( - unsigned int *status_flags, git_repository *repo, const char *path) + unsigned int *status_flags, + git_repository *repo, + const char *path) { - struct status_entry *e; - git_index *index = NULL; - git_buf temp_path = GIT_BUF_INIT; - int error = 0; - git_tree *tree = NULL; - const char *workdir; + int error; + git_status_options opts; + struct status_file_info sfi; assert(status_flags && repo && path); - if ((workdir = git_repository_workdir(repo)) == NULL) { - giterr_set(GITERR_INVALID, "Cannot get file status from bare repo"); - return -1; - } - - if (git_buf_joinpath(&temp_path, workdir, path) < 0) + memset(&sfi, 0, sizeof(sfi)); + if ((sfi.expected = git__strdup(path)) == NULL) return -1; - if (git_path_isdir(temp_path.ptr)) { - giterr_set(GITERR_INVALID, "Cannot get file status for directory '%s'", temp_path.ptr); - git_buf_free(&temp_path); - return -1; + memset(&opts, 0, sizeof(opts)); + opts.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; + opts.flags = GIT_STATUS_OPT_INCLUDE_IGNORED | + GIT_STATUS_OPT_INCLUDE_UNTRACKED | + GIT_STATUS_OPT_RECURSE_UNTRACKED_DIRS | + GIT_STATUS_OPT_INCLUDE_UNMODIFIED; + opts.pathspec.count = 1; + opts.pathspec.strings = &sfi.expected; + + error = git_status_foreach_ext(repo, &opts, get_one_status, &sfi); + + if (!error && !sfi.count) { + giterr_set(GITERR_INVALID, + "Attempt to get status of nonexistent file '%s'", path); + error = GIT_ENOTFOUND; } - e = status_entry_new(NULL, path); - GITERR_CHECK_ALLOC(e); + *status_flags = sfi.status; - /* Find file in Workdir */ - if (git_path_exists(temp_path.ptr) == true && - (error = status_entry_update_from_workdir(e, temp_path.ptr)) < 0) - goto cleanup; - - /* Find file in Index */ - if ((error = git_repository_index__weakptr(&index, repo)) < 0) - goto cleanup; - status_entry_update_from_index(e, index); - - /* Try to find file in HEAD */ - if ((error = git_repository_head_tree(&tree, repo)) < 0) - goto cleanup; - - if (tree != NULL) { - if ((error = git_buf_sets(&temp_path, path)) < 0 || - (error = recurse_tree_entry(tree, e, temp_path.ptr)) < 0) - goto cleanup; - } - - /* Determine status */ - if ((error = status_entry_update_flags(e)) < 0) - giterr_set(GITERR_OS, "Cannot find file '%s' to determine status", path); - - if (!error && status_entry_is_ignorable(e)) { - git_ignores ignores; - - if ((error = git_ignore__for_path(repo, path, &ignores)) == 0) - error = status_entry_update_ignore(e, &ignores, path); - - git_ignore__free(&ignores); - } - - if (!error) - *status_flags = e->status_flags; - -cleanup: - git_buf_free(&temp_path); - git_tree_free(tree); - git__free(e); + git__free(sfi.expected); return error; } -int git_status_should_ignore(git_repository *repo, const char *path, int *ignored) +int git_status_should_ignore( + int *ignored, + git_repository *repo, + const char *path) { int error; git_ignores ignores; diff --git a/src/submodule.c b/src/submodule.c index 1b5b59f45..3c07e657d 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -218,8 +218,11 @@ static int submodule_from_config( sm->update = (git_submodule_update_t)val; } else if (strcmp(property, "fetchRecurseSubmodules") == 0) { - if (git_config_parse_bool(&sm->fetch_recurse, value) < 0) + if (git__parse_bool(&sm->fetch_recurse, value) < 0) { + giterr_set(GITERR_INVALID, + "Invalid value for submodule 'fetchRecurseSubmodules' property: '%s'", value); goto fail; + } } else if (strcmp(property, "ignore") == 0) { int val; diff --git a/src/tag.c b/src/tag.c index 13481c2a6..63424f530 100644 --- a/src/tag.c +++ b/src/tag.c @@ -168,7 +168,7 @@ static int retrieve_tag_reference( return -1; error = git_reference_lookup(&tag_ref, repo, ref_name_out->ptr); - if (error < GIT_SUCCESS) + if (error < 0) return error; /* Be it not foundo or corrupted */ *tag_reference_out = tag_ref; @@ -254,7 +254,7 @@ static int git_tag_create__internal( } error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag_name); - if (error < GIT_SUCCESS && error != GIT_ENOTFOUND) + if (error < 0 && error != GIT_ENOTFOUND) return -1; /** Ensure the tag name doesn't conflict with an already existing @@ -332,7 +332,7 @@ int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *bu } error = retrieve_tag_reference_oid(oid, &ref_name, repo, tag.tag_name); - if (error < GIT_SUCCESS && error != GIT_ENOTFOUND) + if (error < 0 && error != GIT_ENOTFOUND) goto on_error; /* We don't need these objects after this */ @@ -414,7 +414,7 @@ static int tag_list_cb(const char *tag_name, void *payload) return 0; filter = (tag_filter_data *)payload; - if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == GIT_SUCCESS) + if (!*filter->pattern || p_fnmatch(filter->pattern, tag_name + GIT_REFS_TAGS_DIR_LEN, 0) == 0) return git_vector_insert(filter->taglist, git__strdup(tag_name)); return 0; @@ -428,7 +428,7 @@ int git_tag_list_match(git_strarray *tag_names, const char *pattern, git_reposit assert(tag_names && repo && pattern); - if (git_vector_init(&taglist, 8, NULL) < GIT_SUCCESS) + if (git_vector_init(&taglist, 8, NULL) < 0) return -1; filter.taglist = &taglist; diff --git a/src/transport.c b/src/transport.c index bc4248d5b..5b2cd7ea4 100644 --- a/src/transport.c +++ b/src/transport.c @@ -37,7 +37,7 @@ static git_transport_cb transport_find_fn(const char *url) } /* still here? Check to see if the path points to a file on the local file system */ - if ((git_path_exists(url) == GIT_SUCCESS) && git_path_isdir(url)) + if ((git_path_exists(url) == 0) && git_path_isdir(url)) return &git_transport_local; /* It could be a SSH remote path. Check to see if there's a : */ @@ -72,7 +72,7 @@ int git_transport_new(git_transport **out, const char *url) } error = fn(&transport); - if (error < GIT_SUCCESS) + if (error < 0) return error; transport->url = git__strdup(url); @@ -80,7 +80,7 @@ int git_transport_new(git_transport **out, const char *url) *out = transport; - return GIT_SUCCESS; + return 0; } /* from remote.h */ diff --git a/src/transports/git.c b/src/transports/git.c index 9a1741941..844b350be 100644 --- a/src/transports/git.c +++ b/src/transports/git.c @@ -147,7 +147,7 @@ static int store_refs(transport_git *t) return 0; ret = git_protocol_store_refs(&t->proto, buf->data, buf->offset); - if (ret == GIT_ESHORTBUFFER) { + if (ret == GIT_EBUFS) { gitno_consume_n(buf, buf->len); continue; } @@ -279,7 +279,7 @@ static int recv_pkt(gitno_buffer *buf) return -1; error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); - if (error == GIT_ESHORTBUFFER) + if (error == GIT_EBUFS) continue; if (error < 0) return -1; @@ -344,7 +344,7 @@ static int git_negotiate_fetch(git_transport *transport, git_repository *repo, c } } - if (error < 0 && error != GIT_EREVWALKOVER) + if (error < 0 && error != GIT_REVWALKOVER) goto on_error; /* Tell the other end that we're done negotiating */ @@ -384,10 +384,10 @@ static int git_download_pack(git_transport *transport, git_repository *repo, git } error = git_pkt_parse_line(&pkt, ptr, &line_end, buf->offset); - if (error == GIT_ESHORTBUFFER) + if (error == GIT_EBUFS) break; - if (error < GIT_SUCCESS) + if (error < 0) return error; if (pkt->type == GIT_PKT_PACK) { @@ -417,6 +417,8 @@ static int git_close(git_transport *transport) return -1; } + t->parent.connected = 0; + #ifdef GIT_WIN32 WSACleanup(); #endif diff --git a/src/transports/http.c b/src/transports/http.c index bc4a615f1..9ea21a61d 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -354,10 +354,10 @@ static int on_body_parse_response(http_parser *parser, const char *str, size_t l return 0; error = git_pkt_parse_line(&pkt, ptr, &line_end, git_buf_len(buf)); - if (error == GIT_ESHORTBUFFER) { + if (error == GIT_EBUFS) { return 0; /* Ask for more */ } - if (error < GIT_SUCCESS) + if (error < 0) return t->error = -1; git_buf_consume(buf, line_end); @@ -486,7 +486,7 @@ static int http_negotiate_fetch(git_transport *transport, git_repository *repo, git_buf_clear(&request); git_buf_clear(&data); - if (ret < GIT_SUCCESS || i >= 256) + if (ret < 0 || i >= 256) break; if ((ret = parse_response(t)) < 0) @@ -610,6 +610,8 @@ static int http_close(git_transport *transport) return -1; } + t->parent.connected = 0; + return 0; } diff --git a/src/transports/local.c b/src/transports/local.c index 5dc350103..0e1ae3752 100644 --- a/src/transports/local.c +++ b/src/transports/local.c @@ -91,7 +91,7 @@ static int store_refs(transport_local *t) assert(t); - if (git_reference_listall(&ref_names, t->repo, GIT_REF_LISTALL) < 0 || + if (git_reference_list(&ref_names, t->repo, GIT_REF_LISTALL) < 0 || git_vector_init(&t->refs, (unsigned int)ref_names.count, NULL) < 0) goto on_error; @@ -176,10 +176,21 @@ static int local_connect(git_transport *transport, int direction) return 0; } +static int local_negotiate_fetch(git_transport *transport, git_repository *repo, const git_vector *wants) +{ + GIT_UNUSED(transport); + GIT_UNUSED(repo); + GIT_UNUSED(wants); + + giterr_set(GITERR_NET, "Fetch via local transport isn't implemented. Sorry"); + return -1; +} + static int local_close(git_transport *transport) { transport_local *t = (transport_local *)transport; + t->parent.connected = 0; git_repository_free(t->repo); t->repo = NULL; @@ -220,6 +231,7 @@ int git_transport_local(git_transport **out) t->parent.connect = local_connect; t->parent.ls = local_ls; + t->parent.negotiate_fetch = local_negotiate_fetch; t->parent.close = local_close; t->parent.free = local_free; diff --git a/src/tree.c b/src/tree.c index 7e2bfc102..92b1b1e39 100644 --- a/src/tree.c +++ b/src/tree.c @@ -31,8 +31,8 @@ static int entry_sort_cmp(const void *a, const void *b) const git_tree_entry *entry_b = (const git_tree_entry *)(b); return git_path_cmp( - entry_a->filename, entry_a->filename_len, entry_is_tree(entry_a), - entry_b->filename, entry_b->filename_len, entry_is_tree(entry_b)); + entry_a->filename, entry_a->filename_len, git_tree_entry__is_tree(entry_a), + entry_b->filename, entry_b->filename_len, git_tree_entry__is_tree(entry_b)); } @@ -170,7 +170,10 @@ git_otype git_tree_entry_type(const git_tree_entry *entry) return GIT_OBJ_BLOB; } -int git_tree_entry_2object(git_object **object_out, git_repository *repo, const git_tree_entry *entry) +int git_tree_entry_to_object( + git_object **object_out, + git_repository *repo, + const git_tree_entry *entry) { assert(entry && object_out); return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY); @@ -195,6 +198,33 @@ const git_tree_entry *git_tree_entry_byindex(git_tree *tree, unsigned int idx) return git_vector_get(&tree->entries, idx); } +int git_tree__prefix_position(git_tree *tree, const char *path) +{ + git_vector *entries = &tree->entries; + struct tree_key_search ksearch; + unsigned int at_pos; + + ksearch.filename = path; + ksearch.filename_len = strlen(path); + + /* Find tree entry with appropriate prefix */ + git_vector_bsearch3(&at_pos, entries, &homing_search_cmp, &ksearch); + + for (; at_pos < entries->length; ++at_pos) { + const git_tree_entry *entry = entries->contents[at_pos]; + if (homing_search_cmp(&ksearch, entry) < 0) + break; + } + + for (; at_pos > 0; --at_pos) { + const git_tree_entry *entry = entries->contents[at_pos - 1]; + if (homing_search_cmp(&ksearch, entry) > 0) + break; + } + + return at_pos; +} + unsigned int git_tree_entrycount(git_tree *tree) { assert(tree); @@ -617,7 +647,7 @@ static int tree_frompath( { char *slash_pos = NULL; const git_tree_entry* entry; - int error = GIT_SUCCESS; + int error = 0; git_tree *subtree; if (!*(treeentry_path->ptr + offset)) { @@ -694,7 +724,7 @@ static int tree_walk_post( git_buf *path, void *payload) { - int error = GIT_SUCCESS; + int error = 0; unsigned int i; for (i = 0; i < tree->entries.length; ++i) { @@ -703,7 +733,7 @@ static int tree_walk_post( if (callback(path->ptr, entry, payload) < 0) continue; - if (entry_is_tree(entry)) { + if (git_tree_entry__is_tree(entry)) { git_tree *subtree; size_t path_len = git_buf_len(path); @@ -731,7 +761,7 @@ static int tree_walk_post( int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload) { - int error = GIT_SUCCESS; + int error = 0; git_buf root_path = GIT_BUF_INIT; switch (mode) { @@ -753,273 +783,3 @@ int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payl return error; } -static int tree_entry_cmp(const git_tree_entry *a, const git_tree_entry *b) -{ - int ret; - - ret = a->attr - b->attr; - if (ret != 0) - return ret; - - return git_oid_cmp(&a->oid, &b->oid); -} - -static void mark_del(git_tree_diff_data *diff, git_tree_entry *entry) -{ - diff->old_attr = entry->attr; - git_oid_cpy(&diff->old_oid, &entry->oid); - diff->path = entry->filename; - diff->status |= GIT_STATUS_DELETED; -} - -static void mark_add(git_tree_diff_data *diff, git_tree_entry *entry) -{ - diff->new_attr = entry->attr; - git_oid_cpy(&diff->new_oid, &entry->oid); - diff->path = entry->filename; - diff->status |= GIT_STATUS_ADDED; -} - -static int signal_additions(git_tree *tree, int start, int end, git_tree_diff_cb cb, void *data) -{ - git_tree_diff_data diff; - git_tree_entry *entry; - int i; - - if (end < 0) - end = git_tree_entrycount(tree); - - for (i = start; i < end; ++i) { - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - entry = git_vector_get(&tree->entries, i); - mark_add(&diff, entry); - - if (cb(&diff, data) < 0) - return -1; - } - - return 0; -} - -static int signal_addition(git_tree_entry *entry, git_tree_diff_cb cb, void *data) -{ - git_tree_diff_data diff; - - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - - mark_add(&diff, entry); - - return cb(&diff, data); -} - -static int signal_deletions(git_tree *tree, int start, int end, git_tree_diff_cb cb, void *data) -{ - git_tree_diff_data diff; - git_tree_entry *entry; - int i; - - if (end < 0) - end = git_tree_entrycount(tree); - - for (i = start; i < end; ++i) { - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - entry = git_vector_get(&tree->entries, i); - mark_del(&diff, entry); - - if (cb(&diff, data) < 0) - return -1; - } - - return 0; -} - -static int signal_deletion(git_tree_entry *entry, git_tree_diff_cb cb, void *data) -{ - git_tree_diff_data diff; - - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - - mark_del(&diff, entry); - - return cb(&diff, data); -} - -static int signal_modification(git_tree_entry *a, git_tree_entry *b, - git_tree_diff_cb cb, void *data) -{ - git_tree_diff_data diff; - - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - - mark_del(&diff, a); - mark_add(&diff, b); - - return cb(&diff, data); -} - -int git_tree_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data) -{ - unsigned int i_a = 0, i_b = 0; /* Counters for trees a and b */ - git_tree_entry *entry_a = NULL, *entry_b = NULL; - git_tree_diff_data diff; - int cmp; - - while (1) { - entry_a = a == NULL ? NULL : git_vector_get(&a->entries, i_a); - entry_b = b == NULL ? NULL : git_vector_get(&b->entries, i_b); - - if (!entry_a && !entry_b) - return 0; - - memset(&diff, 0x0, sizeof(git_tree_diff_data)); - - /* - * We've run out of tree on one side so the rest of the - * entries on the tree with remaining entries are all - * deletions or additions. - */ - if (entry_a && !entry_b) - return signal_deletions(a, i_a, -1, cb, data); - if (!entry_a && entry_b) - return signal_additions(b, i_b, -1, cb, data); - - /* - * Both trees are sorted with git's almost-alphabetical - * sorting, so a comparison value < 0 means the entry was - * deleted in the right tree. > 0 means the entry was added. - */ - cmp = entry_sort_cmp(entry_a, entry_b); - - if (cmp == 0) { - i_a++; - i_b++; - - /* If everything's the same, jump to next pair */ - if (!tree_entry_cmp(entry_a, entry_b)) - continue; - - /* If they're not both dirs or both files, it's add + del */ - if (S_ISDIR(entry_a->attr) != S_ISDIR(entry_b->attr)) { - if (signal_addition(entry_a, cb, data) < 0) - return -1; - if (signal_deletion(entry_b, cb, data) < 0) - return -1; - } - - /* Otherwise consider it a modification */ - if (signal_modification(entry_a, entry_b, cb, data) < 0) - return -1; - - } else if (cmp < 0) { - i_a++; - if (signal_deletion(entry_a, cb, data) < 0) - return -1; - } else if (cmp > 0) { - i_b++; - if (signal_addition(entry_b, cb, data) < 0) - return -1; - } - } - - return 0; -} - -struct diff_index_cbdata { - git_index *index; - unsigned int i; - git_tree_diff_cb cb; - void *data; -}; - -static int cmp_tentry_ientry(git_tree_entry *tentry, git_index_entry *ientry) -{ - int cmp; - - cmp = tentry->attr - ientry->mode; - if (cmp != 0) - return cmp; - - return git_oid_cmp(&tentry->oid, &ientry->oid); -} - -static void make_tentry(git_tree_entry *tentry, git_index_entry *ientry) -{ - char *last_slash; - - memset(tentry, 0x0, sizeof(git_tree_entry)); - tentry->attr = ientry->mode; - - last_slash = strrchr(ientry->path, '/'); - if (last_slash) - last_slash++; - else - last_slash = ientry->path; - tentry->filename = last_slash; - - git_oid_cpy(&tentry->oid, &ientry->oid); - tentry->filename_len = strlen(tentry->filename); -} - -static int diff_index_cb(const char *root, git_tree_entry *tentry, void *data) -{ - struct diff_index_cbdata *cbdata = (struct diff_index_cbdata *) data; - git_index_entry *ientry = git_index_get(cbdata->index, cbdata->i); - git_tree_entry fake_entry; - git_buf fn_buf = GIT_BUF_INIT; - int cmp; - - if (entry_is_tree(tentry)) - return 0; - - if (!ientry) - return signal_deletion(tentry, cbdata->cb, cbdata->data); - - git_buf_puts(&fn_buf, root); - git_buf_puts(&fn_buf, tentry->filename); - - /* Like with 'git diff-index', the index is the right side*/ - cmp = strcmp(git_buf_cstr(&fn_buf), ientry->path); - git_buf_free(&fn_buf); - if (cmp == 0) { - cbdata->i++; - if (!cmp_tentry_ientry(tentry, ientry)) - return 0; - /* modification */ - make_tentry(&fake_entry, ientry); - if (signal_modification(tentry, &fake_entry, cbdata->cb, cbdata->data) < 0) - return -1; - } else if (cmp < 0) { - /* deletion */ - memcpy(&fake_entry, tentry, sizeof(git_tree_entry)); - if (signal_deletion(tentry, cbdata->cb, cbdata->data) < 0) - return -1; - } else { - /* addition */ - cbdata->i++; - make_tentry(&fake_entry, ientry); - if (signal_addition(&fake_entry, cbdata->cb, cbdata->data) < 0) - return -1; - /* - * The index has an addition. This means that we need to use - * the next entry in the index without advancing the tree - * walker, so call ourselves with the same tree state. - */ - if (diff_index_cb(root, tentry, data) < 0) - return -1;; - } - - return 0; -} - -int git_tree_diff_index_recursive(git_tree *tree, git_index *index, git_tree_diff_cb cb, void *data) -{ - struct diff_index_cbdata cbdata; - git_buf dummy_path = GIT_BUF_INIT; - - cbdata.index = index; - cbdata.i = 0; - cbdata.cb = cb; - cbdata.data = data; - - return tree_walk_post(tree, diff_index_cb, &dummy_path, &cbdata); -} diff --git a/src/tree.h b/src/tree.h index fd00afde5..498a90d66 100644 --- a/src/tree.h +++ b/src/tree.h @@ -30,7 +30,7 @@ struct git_treebuilder { }; -GIT_INLINE(unsigned int) entry_is_tree(const struct git_tree_entry *e) +GIT_INLINE(bool) git_tree_entry__is_tree(const struct git_tree_entry *e) { return (S_ISDIR(e->attr) && !S_ISGITLINK(e->attr)); } @@ -38,4 +38,14 @@ GIT_INLINE(unsigned int) entry_is_tree(const struct git_tree_entry *e) void git_tree__free(git_tree *tree); int git_tree__parse(git_tree *tree, git_odb_object *obj); +/** + * Lookup the first position in the tree with a given prefix. + * + * @param tree a previously loaded tree. + * @param prefix the beginning of a path to find in the tree. + * @return index of the first item at or after the given prefix. + */ +int git_tree__prefix_position(git_tree *tree, const char *prefix); + + #endif diff --git a/src/unix/posix.h b/src/unix/posix.h index 9973acf30..48b492941 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -7,7 +7,14 @@ #ifndef INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__ -#include +#ifndef __sun +# include +# define p_fnmatch(p, s, f) fnmatch(p, s, f) +#else +# include "compat/fnmatch.h" +#endif + +#include #define p_lstat(p,b) lstat(p,b) #define p_readlink(a, b, c) readlink(a, b, c) @@ -16,7 +23,6 @@ #define p_mkdir(p,m) mkdir(p, m) #define p_fsync(fd) fsync(fd) #define p_realpath(p, po) realpath(p, po) -#define p_fnmatch(p, s, f) fnmatch(p, s, f) #define p_vsnprintf(b, c, f, a) vsnprintf(b, c, f, a) #define p_snprintf(b, c, f, ...) snprintf(b, c, f, __VA_ARGS__) #define p_mkstemp(p) mkstemp(p) diff --git a/src/util.c b/src/util.c index 9fd5f286c..ce770203a 100644 --- a/src/util.c +++ b/src/util.c @@ -411,3 +411,27 @@ int git__strcmp_cb(const void *a, const void *b) return strcmp(stra, strb); } + +int git__parse_bool(int *out, const char *value) +{ + /* A missing value means true */ + if (value == NULL) { + *out = 1; + return 0; + } + + if (!strcasecmp(value, "true") || + !strcasecmp(value, "yes") || + !strcasecmp(value, "on")) { + *out = 1; + return 0; + } + if (!strcasecmp(value, "false") || + !strcasecmp(value, "no") || + !strcasecmp(value, "off")) { + *out = 0; + return 0; + } + + return -1; +} diff --git a/src/util.h b/src/util.h index 9003c08ad..c4a55f524 100644 --- a/src/util.h +++ b/src/util.h @@ -216,4 +216,18 @@ GIT_INLINE(int) git__time_cmp(const git_time *a, const git_time *b) return (int)(adjusted_a - b->time); } +GIT_INLINE(bool) git__iswildcard(int c) +{ + return (c == '*' || c == '?' || c == '['); +} + +/* + * Parse a string value as a boolean, just like Core Git + * does. + * + * Valid values for true are: 'true', 'yes', 'on' + * Valid values for false are: 'false', 'no', 'off' + */ +extern int git__parse_bool(int *out, const char *value); + #endif /* INCLUDE_util_h__ */ diff --git a/src/vector.c b/src/vector.c index 304f324f0..6f9aacccf 100644 --- a/src/vector.c +++ b/src/vector.c @@ -116,8 +116,13 @@ void git_vector_sort(git_vector *v) v->sorted = 1; } -int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key) +int git_vector_bsearch3( + unsigned int *at_pos, + git_vector *v, + git_vector_cmp key_lookup, + const void *key) { + int rval; size_t pos; assert(v && key && key_lookup); @@ -127,13 +132,16 @@ int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *ke git_vector_sort(v); - if (git__bsearch(v->contents, v->length, key, key_lookup, &pos) >= 0) - return (int)pos; + rval = git__bsearch(v->contents, v->length, key, key_lookup, &pos); - return GIT_ENOTFOUND; + if (at_pos != NULL) + *at_pos = (unsigned int)pos; + + return (rval >= 0) ? (int)pos : GIT_ENOTFOUND; } -int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key) +int git_vector_search2( + git_vector *v, git_vector_cmp key_lookup, const void *key) { unsigned int i; @@ -157,11 +165,6 @@ int git_vector_search(git_vector *v, const void *entry) return git_vector_search2(v, v->_cmp ? v->_cmp : strict_comparison, entry); } -int git_vector_bsearch(git_vector *v, const void *key) -{ - return git_vector_bsearch2(v, v->_cmp, key); -} - int git_vector_remove(git_vector *v, unsigned int idx) { unsigned int i; diff --git a/src/vector.h b/src/vector.h index 5bc27914a..9139db345 100644 --- a/src/vector.h +++ b/src/vector.h @@ -26,13 +26,24 @@ void git_vector_free(git_vector *v); void git_vector_clear(git_vector *v); void git_vector_swap(git_vector *a, git_vector *b); +void git_vector_sort(git_vector *v); + int git_vector_search(git_vector *v, const void *entry); int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key); -int git_vector_bsearch(git_vector *v, const void *entry); -int git_vector_bsearch2(git_vector *v, git_vector_cmp cmp, const void *key); +int git_vector_bsearch3( + unsigned int *at_pos, git_vector *v, git_vector_cmp cmp, const void *key); -void git_vector_sort(git_vector *v); +GIT_INLINE(int) git_vector_bsearch(git_vector *v, const void *key) +{ + return git_vector_bsearch3(NULL, v, v->_cmp, key); +} + +GIT_INLINE(int) git_vector_bsearch2( + git_vector *v, git_vector_cmp cmp, const void *key) +{ + return git_vector_bsearch3(NULL, v, cmp, key); +} GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position) { diff --git a/src/win32/posix.h b/src/win32/posix.h index 55732f5ac..c38caa8ee 100644 --- a/src/win32/posix.h +++ b/src/win32/posix.h @@ -8,7 +8,7 @@ #define INCLUDE_posix__w32_h__ #include "common.h" -#include "fnmatch.h" +#include "compat/fnmatch.h" #include "utf-conv.h" GIT_INLINE(int) p_link(const char *old, const char *new) diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c index 76f1e4237..0a705c0ad 100644 --- a/src/win32/utf-conv.c +++ b/src/win32/utf-conv.c @@ -32,19 +32,16 @@ void gitwin_set_utf8(void) wchar_t* gitwin_to_utf16(const char* str) { wchar_t* ret; - size_t cb; + int cb; if (!str) return NULL; - cb = strlen(str) * sizeof(wchar_t); + cb = MultiByteToWideChar(_active_codepage, 0, str, -1, NULL, 0); if (cb == 0) return (wchar_t *)git__calloc(1, sizeof(wchar_t)); - /* Add space for null terminator */ - cb += sizeof(wchar_t); - - ret = (wchar_t *)git__malloc(cb); + ret = (wchar_t *)git__malloc(cb * sizeof(wchar_t)); if (!ret) return NULL; @@ -59,7 +56,8 @@ wchar_t* gitwin_to_utf16(const char* str) int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len) { - int result = MultiByteToWideChar(_active_codepage, 0, str, -1, buffer, (int)len); + int result = MultiByteToWideChar( + _active_codepage, 0, str, -1, buffer, (int)len); if (result == 0) giterr_set(GITERR_OS, "Could not convert string to UTF-16"); return result; @@ -68,23 +66,22 @@ int gitwin_append_utf16(wchar_t *buffer, const char *str, size_t len) char* gitwin_from_utf16(const wchar_t* str) { char* ret; - size_t cb; + int cb; if (!str) return NULL; - cb = wcslen(str) * sizeof(char); + cb = WideCharToMultiByte(_active_codepage, 0, str, -1, NULL, 0, NULL, NULL); if (cb == 0) return (char *)git__calloc(1, sizeof(char)); - /* Add space for null terminator */ - cb += sizeof(char); - ret = (char*)git__malloc(cb); if (!ret) return NULL; - if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0) { + if (WideCharToMultiByte( + _active_codepage, 0, str, -1, ret, (int)cb, NULL, NULL) == 0) + { giterr_set(GITERR_OS, "Could not convert string to UTF-8"); git__free(ret); ret = NULL; diff --git a/tests-clar/attr/attr_expect.h b/tests-clar/attr/attr_expect.h index df1e1044b..70f1ab4f5 100644 --- a/tests-clar/attr/attr_expect.h +++ b/tests-clar/attr/attr_expect.h @@ -18,19 +18,20 @@ struct attr_expected { GIT_INLINE(void) attr_check_expected( enum attr_expect_t expected, const char *expected_str, + const char *name, const char *value) { switch (expected) { case EXPECT_TRUE: - cl_assert(GIT_ATTR_TRUE(value)); + cl_assert_(GIT_ATTR_TRUE(value), name); break; case EXPECT_FALSE: - cl_assert(GIT_ATTR_FALSE(value)); + cl_assert_(GIT_ATTR_FALSE(value), name); break; case EXPECT_UNDEFINED: - cl_assert(GIT_ATTR_UNSPECIFIED(value)); + cl_assert_(GIT_ATTR_UNSPECIFIED(value), name); break; case EXPECT_STRING: diff --git a/tests-clar/attr/file.c b/tests-clar/attr/file.c index d19708838..8866fd9bd 100644 --- a/tests-clar/attr/file.c +++ b/tests-clar/attr/file.c @@ -114,7 +114,7 @@ static void check_one_assign( cl_assert_equal_s(name, assign->name); cl_assert(assign->name_hash == git_attr_file__name_hash(assign->name)); - attr_check_expected(expected, expected_str, assign->value); + attr_check_expected(expected, expected_str, assign->name, assign->value); } void test_attr_file__assign_variants(void) diff --git a/tests-clar/attr/flags.c b/tests-clar/attr/flags.c index 5081de8b2..80c6e1171 100644 --- a/tests-clar/attr/flags.c +++ b/tests-clar/attr/flags.c @@ -14,7 +14,7 @@ void test_attr_flags__bare(void) cl_assert(git_repository_is_bare(repo)); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM, "README.md", "diff")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); } @@ -27,34 +27,34 @@ void test_attr_flags__index_vs_workdir(void) /* wd then index */ cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "README.md", "bar", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "README.md", "bar")); cl_assert(GIT_ATTR_FALSE(value)); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "README.md", "blargh", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "README.md", "blargh")); cl_assert_equal_s(value, "goop"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "README.txt", "foo", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "README.txt", "foo")); cl_assert(GIT_ATTR_FALSE(value)); /* index then wd */ cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "README.md", "bar", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "README.md", "bar")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "README.md", "blargh", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "README.md", "blargh")); cl_assert_equal_s(value, "garble"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "README.txt", "foo", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "README.txt", "foo")); cl_assert(GIT_ATTR_TRUE(value)); } @@ -65,44 +65,44 @@ void test_attr_flags__subdir(void) /* wd then index */ cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "sub/sub/README.md", "bar", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "sub/sub/README.md", "bar")); cl_assert_equal_s(value, "1234"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "sub/sub/README.txt", "another", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "sub/sub/README.txt", "another")); cl_assert_equal_s(value, "one"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "sub/sub/README.txt", "again", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "sub/sub/README.txt", "again")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, - "sub/sub/README.txt", "beep", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_FILE_THEN_INDEX, + "sub/sub/README.txt", "beep")); cl_assert_equal_s(value, "10"); /* index then wd */ cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "sub/sub/README.md", "bar", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "sub/sub/README.md", "bar")); cl_assert_equal_s(value, "1337"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "sub/sub/README.txt", "another", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "sub/sub/README.txt", "another")); cl_assert_equal_s(value, "one"); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "sub/sub/README.txt", "again", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "sub/sub/README.txt", "again")); cl_assert(GIT_ATTR_TRUE(value)); cl_git_pass(git_attr_get( - repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, - "sub/sub/README.txt", "beep", &value)); + &value, repo, GIT_ATTR_CHECK_NO_SYSTEM | GIT_ATTR_CHECK_INDEX_THEN_FILE, + "sub/sub/README.txt", "beep")); cl_assert_equal_s(value, "5"); } diff --git a/tests-clar/attr/lookup.c b/tests-clar/attr/lookup.c index b2a6aac64..40aac0b6e 100644 --- a/tests-clar/attr/lookup.c +++ b/tests-clar/attr/lookup.c @@ -44,7 +44,7 @@ static void run_test_cases(git_attr_file *file, struct attr_expected *cases, int error = git_attr_file__lookup_one(file,&path,c->attr,&value); cl_git_pass(error); - attr_check_expected(c->expected, c->expected_str, value); + attr_check_expected(c->expected, c->expected_str, c->attr, value); git_attr_path__free(&path); } diff --git a/tests-clar/attr/repo.c b/tests-clar/attr/repo.c index 006a49081..c37ff544a 100644 --- a/tests-clar/attr/repo.c +++ b/tests-clar/attr/repo.c @@ -64,8 +64,8 @@ void test_attr_repo__get_one(void) for (scan = test_cases; scan->path != NULL; scan++) { const char *value; - cl_git_pass(git_attr_get(g_repo, 0, scan->path, scan->attr, &value)); - attr_check_expected(scan->expected, scan->expected_str, value); + cl_git_pass(git_attr_get(&value, g_repo, 0, scan->path, scan->attr)); + attr_check_expected(scan->expected, scan->expected_str, scan->attr, value); } cl_assert(git_attr_cache__is_cached(g_repo, 0, ".git/info/attributes")); @@ -78,21 +78,21 @@ void test_attr_repo__get_many(void) const char *names[4] = { "repoattr", "rootattr", "missingattr", "subattr" }; const char *values[4]; - cl_git_pass(git_attr_get_many(g_repo, 0, "root_test1", 4, names, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test1", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); - cl_git_pass(git_attr_get_many(g_repo, 0, "root_test2", 4, names, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "root_test2", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_FALSE(values[1])); cl_assert(GIT_ATTR_UNSPECIFIED(values[2])); cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); - cl_git_pass(git_attr_get_many(g_repo, 0, "sub/subdir_test1", 4, names, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "sub/subdir_test1", 4, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); @@ -137,19 +137,19 @@ void test_attr_repo__manpage_example(void) { const char *value; - cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "foo", &value)); + cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "foo")); cl_assert(GIT_ATTR_TRUE(value)); - cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "bar", &value)); + cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "bar")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); - cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "baz", &value)); + cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "baz")); cl_assert(GIT_ATTR_FALSE(value)); - cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "merge", &value)); + cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "merge")); cl_assert_equal_s("filfre", value); - cl_git_pass(git_attr_get(g_repo, 0, "sub/abc", "frotz", &value)); + cl_git_pass(git_attr_get(&value, g_repo, 0, "sub/abc", "frotz")); cl_assert(GIT_ATTR_UNSPECIFIED(value)); } @@ -160,7 +160,7 @@ void test_attr_repo__macros(void) const char *names3[3] = { "macro2", "multi2", "multi3" }; const char *values[5]; - cl_git_pass(git_attr_get_many(g_repo, 0, "binfile", 5, names, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "binfile", 5, names)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); @@ -168,7 +168,7 @@ void test_attr_repo__macros(void) cl_assert(GIT_ATTR_FALSE(values[3])); cl_assert(GIT_ATTR_UNSPECIFIED(values[4])); - cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 5, names2, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 5, names2)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_TRUE(values[1])); @@ -176,7 +176,7 @@ void test_attr_repo__macros(void) cl_assert(GIT_ATTR_UNSPECIFIED(values[3])); cl_assert_equal_s("77", values[4]); - cl_git_pass(git_attr_get_many(g_repo, 0, "macro_test", 3, names3, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_test", 3, names3)); cl_assert(GIT_ATTR_TRUE(values[0])); cl_assert(GIT_ATTR_FALSE(values[1])); @@ -189,7 +189,7 @@ void test_attr_repo__bad_macros(void) "firstmacro", "secondmacro", "thirdmacro" }; const char *values[6]; - cl_git_pass(git_attr_get_many(g_repo, 0, "macro_bad", 6, names, values)); + cl_git_pass(git_attr_get_many(values, g_repo, 0, "macro_bad", 6, names)); /* these three just confirm that the "mymacro" rule ran */ cl_assert(GIT_ATTR_UNSPECIFIED(values[0])); diff --git a/tests-clar/clar b/tests-clar/clar old mode 100644 new mode 100755 diff --git a/tests-clar/commit/signature.c b/tests-clar/commit/signature.c index 605b8330a..290b11fa3 100644 --- a/tests-clar/commit/signature.c +++ b/tests-clar/commit/signature.c @@ -3,9 +3,9 @@ static int try_build_signature(const char *name, const char *email, git_time_t time, int offset) { git_signature *sign; - int error = GIT_SUCCESS; + int error = 0; - if ((error = git_signature_new(&sign, name, email, time, offset)) < GIT_SUCCESS) + if ((error = git_signature_new(&sign, name, email, time, offset)) < 0) return error; git_signature_free((git_signature *)sign); diff --git a/tests-clar/config/add.c b/tests-clar/config/add.c index b58029951..9854fbb39 100644 --- a/tests-clar/config/add.c +++ b/tests-clar/config/add.c @@ -17,7 +17,7 @@ void test_config_add__to_existing_section(void) 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_git_pass(git_config_get_int32(&i, cfg, "empty.tmp")); cl_assert(i == 5); cl_git_pass(git_config_delete(cfg, "empty.tmp")); git_config_free(cfg); @@ -30,7 +30,7 @@ void test_config_add__to_new_section(void) 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_git_pass(git_config_get_int32(&i, cfg, "section.tmp")); cl_assert(i == 5); cl_git_pass(git_config_delete(cfg, "section.tmp")); git_config_free(cfg); diff --git a/tests-clar/config/multivar.c b/tests-clar/config/multivar.c index d3784c0dd..3b40cd09a 100644 --- a/tests-clar/config/multivar.c +++ b/tests-clar/config/multivar.c @@ -21,7 +21,7 @@ static int mv_read_cb(const char *name, const char *value, void *data) if (!strcmp(name, _name)) (*n)++; - return GIT_SUCCESS; + return 0; } void test_config_multivar__foreach(void) @@ -45,7 +45,7 @@ static int cb(const char *val, void *data) (*n)++; - return GIT_SUCCESS; + return 0; } void test_config_multivar__get(void) diff --git a/tests-clar/config/new.c b/tests-clar/config/new.c index 78e8ec828..fae3ce941 100644 --- a/tests-clar/config/new.c +++ b/tests-clar/config/new.c @@ -25,9 +25,9 @@ void test_config_new__write_new_config(void) cl_git_pass(git_config_new(&config)); cl_git_pass(git_config_add_file(config, file, 0)); - cl_git_pass(git_config_get_string(config, "color.ui", &out)); + cl_git_pass(git_config_get_string(&out, config, "color.ui")); cl_assert_equal_s(out, "auto"); - cl_git_pass(git_config_get_string(config, "core.editor", &out)); + cl_git_pass(git_config_get_string(&out, config, "core.editor")); cl_assert_equal_s(out, "ed"); git_config_free(config); diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c index 3e9a8d4bf..f33bdd89e 100644 --- a/tests-clar/config/read.c +++ b/tests-clar/config/read.c @@ -7,13 +7,13 @@ void test_config_read__simple_read(void) cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config0"))); - cl_git_pass(git_config_get_int32(cfg, "core.repositoryformatversion", &i)); + cl_git_pass(git_config_get_int32(&i, cfg, "core.repositoryformatversion")); cl_assert(i == 0); - cl_git_pass(git_config_get_bool(cfg, "core.filemode", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "core.filemode")); cl_assert(i == 1); - cl_git_pass(git_config_get_bool(cfg, "core.bare", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "core.bare")); cl_assert(i == 0); - cl_git_pass(git_config_get_bool(cfg, "core.logallrefupdates", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "core.logallrefupdates")); cl_assert(i == 1); git_config_free(cfg); @@ -27,18 +27,18 @@ void test_config_read__case_sensitive(void) 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_git_pass(git_config_get_string(&str, cfg, "this.that.other")); cl_assert_equal_s(str, "true"); - cl_git_pass(git_config_get_string(cfg, "this.That.other", &str)); + cl_git_pass(git_config_get_string(&str, cfg, "this.That.other")); cl_assert_equal_s(str, "yes"); - cl_git_pass(git_config_get_bool(cfg, "this.that.other", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "this.that.other")); cl_assert(i == 1); - cl_git_pass(git_config_get_bool(cfg, "this.That.other", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "this.That.other")); cl_assert(i == 1); /* This one doesn't exist */ - cl_must_fail(git_config_get_bool(cfg, "this.thaT.other", &i)); + cl_must_fail(git_config_get_bool(&i, cfg, "this.thaT.other")); git_config_free(cfg); } @@ -54,7 +54,7 @@ void test_config_read__multiline_value(void) 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_git_pass(git_config_get_string(&str, cfg, "this.That.and")); cl_assert_equal_s(str, "one one one two two three three"); git_config_free(cfg); @@ -70,11 +70,11 @@ void test_config_read__subsection_header(void) 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_git_pass(git_config_get_string(&str, cfg, "section.subsection.var")); cl_assert_equal_s(str, "hello"); /* The subsection is transformed to lower-case */ - cl_must_fail(git_config_get_string(cfg, "section.subSectIon.var", &str)); + cl_must_fail(git_config_get_string(&str, cfg, "section.subSectIon.var")); git_config_free(cfg); } @@ -87,10 +87,10 @@ void test_config_read__lone_variable(void) 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_git_pass(git_config_get_string(&str, cfg, "some.section.variable")); cl_assert(str == NULL); - cl_git_pass(git_config_get_bool(cfg, "some.section.variable", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variable")); cl_assert(i == 1); git_config_free(cfg); @@ -103,25 +103,25 @@ void test_config_read__number_suffixes(void) cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config5"))); - cl_git_pass(git_config_get_int64(cfg, "number.simple", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.simple")); cl_assert(i == 1); - cl_git_pass(git_config_get_int64(cfg, "number.k", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.k")); cl_assert(i == 1 * 1024); - cl_git_pass(git_config_get_int64(cfg, "number.kk", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.kk")); cl_assert(i == 1 * 1024); - cl_git_pass(git_config_get_int64(cfg, "number.m", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.m")); cl_assert(i == 1 * 1024 * 1024); - cl_git_pass(git_config_get_int64(cfg, "number.mm", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.mm")); cl_assert(i == 1 * 1024 * 1024); - cl_git_pass(git_config_get_int64(cfg, "number.g", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.g")); cl_assert(i == 1 * 1024 * 1024 * 1024); - cl_git_pass(git_config_get_int64(cfg, "number.gg", &i)); + cl_git_pass(git_config_get_int64(&i, cfg, "number.gg")); cl_assert(i == 1 * 1024 * 1024 * 1024); git_config_free(cfg); @@ -134,10 +134,10 @@ void test_config_read__blank_lines(void) 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_git_pass(git_config_get_bool(&i, cfg, "valid.subsection.something")); cl_assert(i == 1); - cl_git_pass(git_config_get_bool(cfg, "something.else.something", &i)); + cl_git_pass(git_config_get_bool(&i, cfg, "something.else.something")); cl_assert(i == 0); git_config_free(cfg); @@ -170,10 +170,10 @@ void test_config_read__prefixes(void) 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_git_pass(git_config_get_string(&str, cfg, "remote.ab.url")); cl_assert_equal_s(str, "http://example.com/git/ab"); - cl_git_pass(git_config_get_string(cfg, "remote.abba.url", &str)); + cl_git_pass(git_config_get_string(&str, cfg, "remote.abba.url")); cl_assert_equal_s(str, "http://example.com/git/abba"); git_config_free(cfg); @@ -185,7 +185,7 @@ void test_config_read__escaping_quotes(void) const char *str; cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config13"))); - cl_git_pass(git_config_get_string(cfg, "core.editor", &str)); + cl_git_pass(git_config_get_string(&str, cfg, "core.editor")); cl_assert(strcmp(str, "\"C:/Program Files/Nonsense/bah.exe\" \"--some option\"") == 0); git_config_free(cfg); diff --git a/tests-clar/config/stress.c b/tests-clar/config/stress.c index 54a61ad67..3de1f7692 100644 --- a/tests-clar/config/stress.c +++ b/tests-clar/config/stress.c @@ -32,8 +32,8 @@ void test_config_stress__dont_break_on_invalid_input(void) cl_git_pass(git_config_new(&config)); cl_git_pass(git_config_add_file(config, file, 0)); - cl_git_pass(git_config_get_string(config, "color.ui", &color)); - cl_git_pass(git_config_get_string(config, "core.editor", &editor)); + cl_git_pass(git_config_get_string(&color, config, "color.ui")); + cl_git_pass(git_config_get_string(&editor, config, "core.editor")); git_config_free(config); } @@ -48,13 +48,13 @@ void test_config_stress__comments(void) cl_git_pass(git_config_new(&config)); cl_git_pass(git_config_add_file(config, file, 0)); - cl_git_pass(git_config_get_string(config, "some.section.other", &str)); + cl_git_pass(git_config_get_string(&str, config, "some.section.other")); cl_assert(!strcmp(str, "hello! \" ; ; ; ")); - cl_git_pass(git_config_get_string(config, "some.section.multi", &str)); + cl_git_pass(git_config_get_string(&str, config, "some.section.multi")); cl_assert(!strcmp(str, "hi, this is a ; multiline comment # with ;\n special chars and other stuff !@#")); - cl_git_pass(git_config_get_string(config, "some.section.back", &str)); + cl_git_pass(git_config_get_string(&str, config, "some.section.back")); cl_assert(!strcmp(str, "this is \ba phrase")); git_config_free(config); diff --git a/tests-clar/config/write.c b/tests-clar/config/write.c index f25bf5a91..f8774473e 100644 --- a/tests-clar/config/write.c +++ b/tests-clar/config/write.c @@ -22,7 +22,7 @@ void test_config_write__replace_value(void) 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_git_pass(git_config_get_int32(&i, cfg, "core.dummy")); cl_assert(i == 5); git_config_free(cfg); @@ -35,12 +35,12 @@ void test_config_write__replace_value(void) 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_git_pass(git_config_get_int64(&l, cfg, "core.verylong")); 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)); + cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong")); git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); @@ -62,7 +62,7 @@ void test_config_write__delete_value(void) 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_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND); cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1)); git_config_free(cfg); } @@ -77,7 +77,7 @@ void test_config_write__write_subsection(void) git_config_free(cfg); cl_git_pass(git_config_open_ondisk(&cfg, "config9")); - cl_git_pass(git_config_get_string(cfg, "my.own.var", &str)); + cl_git_pass(git_config_get_string(&str, cfg, "my.own.var")); cl_git_pass(strcmp(str, "works")); git_config_free(cfg); } diff --git a/tests-clar/core/buffer.c b/tests-clar/core/buffer.c index 9294ccdfd..6a718f459 100644 --- a/tests-clar/core/buffer.c +++ b/tests-clar/core/buffer.c @@ -561,3 +561,53 @@ void test_core_buffer__10(void) git_buf_free(&a); } + +void test_core_buffer__11(void) +{ + git_buf a = GIT_BUF_INIT; + git_strarray t; + char *t1[] = { "nothing", "in", "common" }; + char *t2[] = { "something", "something else", "some other" }; + char *t3[] = { "something", "some fun", "no fun" }; + char *t4[] = { "happy", "happier", "happiest" }; + char *t5[] = { "happiest", "happier", "happy" }; + char *t6[] = { "no", "nope", "" }; + char *t7[] = { "", "doesn't matter" }; + + t.strings = t1; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t2; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "some"); + + t.strings = t3; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t4; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "happ"); + + t.strings = t5; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, "happ"); + + t.strings = t6; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + t.strings = t7; + t.count = 3; + cl_git_pass(git_buf_common_prefix(&a, &t)); + cl_assert_equal_s(a.ptr, ""); + + git_buf_free(&a); +} diff --git a/tests-clar/core/dirent.c b/tests-clar/core/dirent.c index 9c366bf97..5a7859d1b 100644 --- a/tests-clar/core/dirent.c +++ b/tests-clar/core/dirent.c @@ -222,3 +222,14 @@ void test_core_dirent__traverse_weird_filenames(void) check_counts(&odd); } + +/* test filename length limits */ +void test_core_dirent__length_limits(void) +{ + char *big_filename = (char *)git__malloc(FILENAME_MAX + 1); + memset(big_filename, 'a', FILENAME_MAX + 1); + big_filename[FILENAME_MAX] = 0; + + cl_must_fail(p_creat(big_filename, 0666)); + git__free(big_filename); +} diff --git a/tests-clar/core/env.c b/tests-clar/core/env.c new file mode 100644 index 000000000..15d431f01 --- /dev/null +++ b/tests-clar/core/env.c @@ -0,0 +1,168 @@ +#include "clar_libgit2.h" +#include "fileops.h" +#include "path.h" + +#ifdef GIT_WIN32 + +#include "win32/utf-conv.h" + +static char *cl_getenv(const char *name) +{ + wchar_t *name_utf16 = gitwin_to_utf16(name); + DWORD value_len, alloc_len; + wchar_t *value_utf16; + char *value_utf8; + + cl_assert(name_utf16); + alloc_len = GetEnvironmentVariableW(name_utf16, NULL, 0); + if (alloc_len <= 0) + return NULL; + + cl_assert(value_utf16 = git__calloc(alloc_len, sizeof(wchar_t))); + + value_len = GetEnvironmentVariableW(name_utf16, value_utf16, alloc_len); + cl_assert_equal_i(value_len, alloc_len - 1); + + cl_assert(value_utf8 = gitwin_from_utf16(value_utf16)); + + git__free(value_utf16); + + return value_utf8; +} + +static int cl_setenv(const char *name, const char *value) +{ + wchar_t *name_utf16 = gitwin_to_utf16(name); + wchar_t *value_utf16 = value ? gitwin_to_utf16(value) : NULL; + + cl_assert(name_utf16); + cl_assert(SetEnvironmentVariableW(name_utf16, value_utf16)); + + git__free(name_utf16); + git__free(value_utf16); + + return 0; + +} +#else + +#include +#define cl_getenv(n) getenv(n) + +static int cl_setenv(const char *name, const char *value) +{ + return (value == NULL) ? unsetenv(name) : setenv(name, value, 1); +} +#endif + +#ifdef GIT_WIN32 +static char *env_userprofile = NULL; +static char *env_programfiles = NULL; +#else +static char *env_home = NULL; +#endif + +void test_core_env__initialize(void) +{ +#ifdef GIT_WIN32 + env_userprofile = cl_getenv("USERPROFILE"); + env_programfiles = cl_getenv("PROGRAMFILES"); +#else + env_home = cl_getenv("HOME"); +#endif +} + +void test_core_env__cleanup(void) +{ +#ifdef GIT_WIN32 + cl_setenv("USERPROFILE", env_userprofile); + git__free(env_userprofile); + cl_setenv("PROGRAMFILES", env_programfiles); + git__free(env_programfiles); +#else + cl_setenv("HOME", env_home); +#endif +} + +void test_core_env__0(void) +{ + static char *home_values[] = { + "fake_home", + "fáke_hõme", /* all in latin-1 supplement */ + "fĀke_Ĥome", /* latin extended */ + "fακε_hοmέ", /* having fun with greek */ + "faงe_นome", /* now I have no idea, but thai characters */ + "f\xe1\x9cx80ke_\xe1\x9c\x91ome", /* tagalog characters */ + "\xe1\xb8\x9fẢke_hoṁe", /* latin extended additional */ + "\xf0\x9f\x98\x98\xf0\x9f\x98\x82", /* emoticons */ + NULL + }; + git_buf path = GIT_BUF_INIT, found = GIT_BUF_INIT; + char **val; + char *check; + + for (val = home_values; *val != NULL; val++) { + + if (p_mkdir(*val, 0777) == 0) { + /* if we can't make the directory, let's just assume + * we are on a filesystem that doesn't support the + * characters in question and skip this test... + */ + cl_git_pass(git_path_prettify(&path, *val, NULL)); + +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("USERPROFILE", path.ptr)); + + /* do a quick check that it was set correctly */ + check = cl_getenv("USERPROFILE"); + cl_assert_equal_s(path.ptr, check); + git__free(check); +#else + cl_git_pass(cl_setenv("HOME", path.ptr)); + + /* do a quick check that it was set correctly */ + check = cl_getenv("HOME"); + cl_assert_equal_s(path.ptr, check); +#endif + + cl_git_pass(git_buf_puts(&path, "/testfile")); + cl_git_mkfile(path.ptr, "find me"); + + cl_git_pass(git_futils_find_global_file(&found, "testfile")); + } + } + + git_buf_free(&path); + git_buf_free(&found); +} + +void test_core_env__1(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_assert(git_futils_find_global_file(&path, "nonexistentfile") == GIT_ENOTFOUND); + +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("USERPROFILE", "doesnotexist")); +#else + cl_git_pass(cl_setenv("HOME", "doesnotexist")); +#endif + + cl_assert(git_futils_find_global_file(&path, "nonexistentfile") == GIT_ENOTFOUND); + +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("USERPROFILE", NULL)); +#else + cl_git_pass(cl_setenv("HOME", NULL)); +#endif + + cl_assert(git_futils_find_global_file(&path, "nonexistentfile") == -1); + + cl_assert(git_futils_find_system_file(&path, "nonexistentfile") == GIT_ENOTFOUND); + +#ifdef GIT_WIN32 + cl_git_pass(cl_setenv("PROGRAMFILES", NULL)); + + cl_assert(git_futils_find_system_file(&path, "nonexistentfile") == -1); +#endif +} diff --git a/tests-clar/diff/iterator.c b/tests-clar/diff/iterator.c index 0ec2326eb..be29bea66 100644 --- a/tests-clar/diff/iterator.c +++ b/tests-clar/diff/iterator.c @@ -22,6 +22,8 @@ void test_diff_iterator__cleanup(void) static void tree_iterator_test( const char *sandbox, const char *treeish, + const char *start, + const char *end, int expected_count, const char **expected_values) { @@ -32,7 +34,7 @@ static void tree_iterator_test( git_repository *repo = cl_git_sandbox_init(sandbox); cl_assert(t = resolve_commit_oid_to_tree(repo, treeish)); - cl_git_pass(git_iterator_for_tree(repo, t, &i)); + cl_git_pass(git_iterator_for_tree_range(&i, repo, t, start, end)); cl_git_pass(git_iterator_current(i, &entry)); while (entry != NULL) { @@ -74,7 +76,7 @@ const char *expected_tree_0[] = { void test_diff_iterator__tree_0(void) { - tree_iterator_test("attr", "605812a", 16, expected_tree_0); + tree_iterator_test("attr", "605812a", NULL, NULL, 16, expected_tree_0); } /* results of: git ls-tree -r --name-only 6bab5c79 */ @@ -97,7 +99,7 @@ const char *expected_tree_1[] = { void test_diff_iterator__tree_1(void) { - tree_iterator_test("attr", "6bab5c79cd5", 13, expected_tree_1); + tree_iterator_test("attr", "6bab5c79cd5", NULL, NULL, 13, expected_tree_1); } /* results of: git ls-tree -r --name-only 26a125ee1 */ @@ -119,7 +121,7 @@ const char *expected_tree_2[] = { void test_diff_iterator__tree_2(void) { - tree_iterator_test("status", "26a125ee1", 12, expected_tree_2); + tree_iterator_test("status", "26a125ee1", NULL, NULL, 12, expected_tree_2); } /* $ git ls-tree -r --name-only 0017bd4ab1e */ @@ -136,7 +138,7 @@ const char *expected_tree_3[] = { void test_diff_iterator__tree_3(void) { - tree_iterator_test("status", "0017bd4ab1e", 8, expected_tree_3); + tree_iterator_test("status", "0017bd4ab1e", NULL, NULL, 8, expected_tree_3); } /* $ git ls-tree -r --name-only 24fa9a9fc4e202313e24b648087495441dab432b */ @@ -170,14 +172,77 @@ const char *expected_tree_4[] = { void test_diff_iterator__tree_4(void) { tree_iterator_test( - "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", NULL, NULL, 23, expected_tree_4); } +void test_diff_iterator__tree_4_ranged(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "sub", "sub", + 11, &expected_tree_4[12]); +} + +const char *expected_tree_ranged_0[] = { + "gitattributes", + "macro_bad", + "macro_test", + "root_test1", + "root_test2", + "root_test3", + "root_test4.txt", + NULL +}; + +void test_diff_iterator__tree_ranged_0(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "git", "root", + 7, expected_tree_ranged_0); +} + +const char *expected_tree_ranged_1[] = { + "sub/subdir_test2.txt", + NULL +}; + +void test_diff_iterator__tree_ranged_1(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "sub/subdir_test2.txt", "sub/subdir_test2.txt", + 1, expected_tree_ranged_1); +} + +void test_diff_iterator__tree_range_empty_0(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "empty", "empty", 0, NULL); +} + +void test_diff_iterator__tree_range_empty_1(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + "z_empty_after", NULL, 0, NULL); +} + +void test_diff_iterator__tree_range_empty_2(void) +{ + tree_iterator_test( + "attr", "24fa9a9fc4e202313e24b648087495441dab432b", + NULL, ".aaa_empty_before", 0, NULL); +} + /* -- INDEX ITERATOR TESTS -- */ static void index_iterator_test( const char *sandbox, + const char *start, + const char *end, int expected_count, const char **expected_names, const char **expected_oids) @@ -187,7 +252,7 @@ static void index_iterator_test( int count = 0; git_repository *repo = cl_git_sandbox_init(sandbox); - cl_git_pass(git_iterator_for_index(repo, &i)); + cl_git_pass(git_iterator_for_index_range(&i, repo, start, end)); cl_git_pass(git_iterator_current(i, &entry)); while (entry != NULL) { @@ -197,7 +262,7 @@ static void index_iterator_test( if (expected_oids != NULL) { git_oid oid; cl_git_pass(git_oid_fromstr(&oid, expected_oids[count])); - cl_assert(git_oid_cmp(&oid, &entry->oid) == 0); + cl_assert_equal_i(git_oid_cmp(&oid, &entry->oid), 0); } count++; @@ -206,7 +271,7 @@ static void index_iterator_test( git_iterator_free(i); - cl_assert(count == expected_count); + cl_assert_equal_i(expected_count, count); } static const char *expected_index_0[] = { @@ -263,7 +328,46 @@ static const char *expected_index_oids_0[] = { void test_diff_iterator__index_0(void) { - index_iterator_test("attr", 23, expected_index_0, expected_index_oids_0); + index_iterator_test( + "attr", NULL, NULL, 23, expected_index_0, expected_index_oids_0); +} + +static const char *expected_index_range[] = { + "root_test1", + "root_test2", + "root_test3", + "root_test4.txt", +}; + +static const char *expected_index_oids_range[] = { + "45141a79a77842c59a63229403220a4e4be74e3d", + "4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d", + "108bb4e7fd7b16490dc33ff7d972151e73d7166e", + "fe773770c5a6cc7185580c9204b1ff18a33ff3fc", +}; + +void test_diff_iterator__index_range(void) +{ + index_iterator_test( + "attr", "root", "root", 4, expected_index_range, expected_index_oids_range); +} + +void test_diff_iterator__index_range_empty_0(void) +{ + index_iterator_test( + "attr", "empty", "empty", 0, NULL, NULL); +} + +void test_diff_iterator__index_range_empty_1(void) +{ + index_iterator_test( + "attr", "z_empty_after", NULL, 0, NULL, NULL); +} + +void test_diff_iterator__index_range_empty_2(void) +{ + index_iterator_test( + "attr", NULL, ".aaa_empty_before", 0, NULL, NULL); } static const char *expected_index_1[] = { @@ -300,7 +404,8 @@ static const char* expected_index_oids_1[] = { void test_diff_iterator__index_1(void) { - index_iterator_test("status", 13, expected_index_1, expected_index_oids_1); + index_iterator_test( + "status", NULL, NULL, 13, expected_index_1, expected_index_oids_1); } @@ -308,6 +413,8 @@ void test_diff_iterator__index_1(void) static void workdir_iterator_test( const char *sandbox, + const char *start, + const char *end, int expected_count, int expected_ignores, const char **expected_names, @@ -318,7 +425,7 @@ static void workdir_iterator_test( int count = 0, count_all = 0; git_repository *repo = cl_git_sandbox_init(sandbox); - cl_git_pass(git_iterator_for_workdir(repo, &i)); + cl_git_pass(git_iterator_for_workdir_range(&i, repo, start, end)); cl_git_pass(git_iterator_current(i, &entry)); while (entry != NULL) { @@ -350,7 +457,7 @@ static void workdir_iterator_test( void test_diff_iterator__workdir_0(void) { - workdir_iterator_test("attr", 25, 2, NULL, "ign"); + workdir_iterator_test("attr", NULL, NULL, 25, 2, NULL, "ign"); } static const char *status_paths[] = { @@ -372,5 +479,92 @@ static const char *status_paths[] = { void test_diff_iterator__workdir_1(void) { - workdir_iterator_test("status", 12, 1, status_paths, "ignored_file"); + workdir_iterator_test( + "status", NULL, NULL, 12, 1, status_paths, "ignored_file"); +} + +static const char *status_paths_range_0[] = { + "staged_changes", + "staged_changes_modified_file", + "staged_delete_modified_file", + "staged_new_file", + "staged_new_file_modified_file", + NULL +}; + +void test_diff_iterator__workdir_1_ranged_0(void) +{ + workdir_iterator_test( + "status", "staged", "staged", 5, 0, status_paths_range_0, NULL); +} + +static const char *status_paths_range_1[] = { + "modified_file", NULL +}; + +void test_diff_iterator__workdir_1_ranged_1(void) +{ + workdir_iterator_test( + "status", "modified_file", "modified_file", + 1, 0, status_paths_range_1, NULL); +} + +static const char *status_paths_range_3[] = { + "subdir.txt", + "subdir/current_file", + "subdir/modified_file", + NULL +}; + +void test_diff_iterator__workdir_1_ranged_3(void) +{ + workdir_iterator_test( + "status", "subdir", "subdir/modified_file", + 3, 0, status_paths_range_3, NULL); +} + +static const char *status_paths_range_4[] = { + "subdir/current_file", + "subdir/modified_file", + "subdir/new_file", + NULL +}; + +void test_diff_iterator__workdir_1_ranged_4(void) +{ + workdir_iterator_test( + "status", "subdir/", NULL, 3, 0, status_paths_range_4, NULL); +} + +static const char *status_paths_range_5[] = { + "subdir/modified_file", + NULL +}; + +void test_diff_iterator__workdir_1_ranged_5(void) +{ + workdir_iterator_test( + "status", "subdir/modified_file", "subdir/modified_file", + 1, 0, status_paths_range_5, NULL); +} + +void test_diff_iterator__workdir_1_ranged_empty_0(void) +{ + workdir_iterator_test( + "status", "z_does_not_exist", NULL, + 0, 0, NULL, NULL); +} + +void test_diff_iterator__workdir_1_ranged_empty_1(void) +{ + workdir_iterator_test( + "status", "empty", "empty", + 0, 0, NULL, NULL); +} + +void test_diff_iterator__workdir_1_ranged_empty_2(void) +{ + workdir_iterator_test( + "status", NULL, "aaaa_empty_before", + 0, 0, NULL, NULL); } diff --git a/tests-clar/index/tests.c b/tests-clar/index/tests.c index 3d01b7cfb..3436f8d1e 100644 --- a/tests-clar/index/tests.c +++ b/tests-clar/index/tests.c @@ -50,10 +50,10 @@ static void files_are_equal(const char *a, const char *b) git_buf buf_b = GIT_BUF_INIT; int pass; - if (git_futils_readbuffer(&buf_a, a) < GIT_SUCCESS) + if (git_futils_readbuffer(&buf_a, a) < 0) cl_assert(0); - if (git_futils_readbuffer(&buf_b, b) < GIT_SUCCESS) { + if (git_futils_readbuffer(&buf_b, b) < 0) { git_buf_free(&buf_a); cl_assert(0); } diff --git a/tests-clar/network/remotelocal.c b/tests-clar/network/remotelocal.c index 4bf9fb6d8..e66ea118f 100644 --- a/tests-clar/network/remotelocal.c +++ b/tests-clar/network/remotelocal.c @@ -68,7 +68,7 @@ static int count_ref__cb(git_remote_head *head, void *payload) (void)head; (*count)++; - return GIT_SUCCESS; + return 0; } static int ensure_peeled__cb(git_remote_head *head, void *payload) @@ -90,6 +90,15 @@ static void connect_to_local_repository(const char *local_repository) } +void test_network_remotelocal__connected(void) +{ + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_assert(git_remote_connected(remote)); + + git_remote_disconnect(remote); + cl_assert(!git_remote_connected(remote)); +} + void test_network_remotelocal__retrieve_advertised_references(void) { int how_many_refs = 0; diff --git a/tests-clar/network/remotes.c b/tests-clar/network/remotes.c index 0649c86dd..3f631835c 100644 --- a/tests-clar/network/remotes.c +++ b/tests-clar/network/remotes.c @@ -92,6 +92,7 @@ void test_network_remotes__save(void) cl_assert(_refspec != NULL); cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/upstream/*"); + cl_assert(git_refspec_force(_refspec) == 0); _refspec = git_remote_pushspec(_remote); cl_assert(_refspec != NULL); @@ -159,6 +160,15 @@ void test_network_remotes__loading_a_missing_remote_returns_ENOTFOUND(void) cl_assert_equal_i(GIT_ENOTFOUND, git_remote_load(&_remote, _repo, "just-left-few-minutes-ago")); } +/* + * $ git remote add addtest http://github.com/libgit2/libgit2 + * + * $ cat .git/config + * [...] + * [remote "addtest"] + * url = http://github.com/libgit2/libgit2 + * fetch = +refs/heads/*:refs/remotes/addtest/* + */ void test_network_remotes__add(void) { git_remote_free(_remote); @@ -168,5 +178,6 @@ void test_network_remotes__add(void) cl_git_pass(git_remote_load(&_remote, _repo, "addtest")); _refspec = git_remote_fetchspec(_remote); cl_assert(!strcmp(git_refspec_src(_refspec), "refs/heads/*")); + cl_assert(git_refspec_force(_refspec) == 1); cl_assert(!strcmp(git_refspec_dst(_refspec), "refs/remotes/addtest/*")); } diff --git a/tests-clar/notes/notes.c b/tests-clar/notes/notes.c index ca82ab29c..5185f25ea 100644 --- a/tests-clar/notes/notes.c +++ b/tests-clar/notes/notes.c @@ -1,43 +1,46 @@ #include "clar_libgit2.h" static git_repository *_repo; -static git_note *_note; -static git_blob *_blob; static git_signature *_sig; void test_notes_notes__initialize(void) { - cl_fixture_sandbox("testrepo.git"); - cl_git_pass(git_repository_open(&_repo, "testrepo.git")); + _repo = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_signature_now(&_sig, "alice", "alice@example.com")); } void test_notes_notes__cleanup(void) { - git_note_free(_note); - git_blob_free(_blob); git_signature_free(_sig); + cl_git_sandbox_cleanup(); +} - git_repository_free(_repo); - cl_fixture_cleanup("testrepo.git"); +static void create_note(git_oid *note_oid, const char *canonical_namespace, const char *target_sha, const char *message) +{ + git_oid oid; + + cl_git_pass(git_oid_fromstr(&oid, target_sha)); + cl_git_pass(git_note_create(note_oid, _repo, _sig, _sig, canonical_namespace, &oid, message)); } void test_notes_notes__1(void) { git_oid oid, note_oid; + static git_note *note; + static git_blob *blob; - cl_git_pass(git_signature_now(&_sig, "alice", "alice@example.com")); cl_git_pass(git_oid_fromstr(&oid, "8496071c1b46c854b31185ea97743be6a8774479")); cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, "refs/notes/some/namespace", &oid, "hello world\n")); cl_git_pass(git_note_create(¬e_oid, _repo, _sig, _sig, NULL, &oid, "hello world\n")); - cl_git_pass(git_note_read(&_note, _repo, NULL, &oid)); + cl_git_pass(git_note_read(¬e, _repo, NULL, &oid)); - cl_assert_equal_s(git_note_message(_note), "hello world\n"); - cl_assert(!git_oid_cmp(git_note_oid(_note), ¬e_oid)); + cl_assert_equal_s(git_note_message(note), "hello world\n"); + cl_assert(!git_oid_cmp(git_note_oid(note), ¬e_oid)); - cl_git_pass(git_blob_lookup(&_blob, _repo, ¬e_oid)); - cl_assert_equal_s(git_note_message(_note), git_blob_rawcontent(_blob)); + cl_git_pass(git_blob_lookup(&blob, _repo, ¬e_oid)); + cl_assert_equal_s(git_note_message(note), git_blob_rawcontent(blob)); cl_git_fail(git_note_create(¬e_oid, _repo, _sig, _sig, NULL, &oid, "hello world\n")); cl_git_fail(git_note_create(¬e_oid, _repo, _sig, _sig, "refs/notes/some/namespace", &oid, "hello world\n")); @@ -47,4 +50,84 @@ void test_notes_notes__1(void) cl_git_fail(git_note_remove(_repo, NULL, _sig, _sig, ¬e_oid)); cl_git_fail(git_note_remove(_repo, "refs/notes/some/namespace", _sig, _sig, &oid)); + + git_note_free(note); + git_blob_free(blob); +} + +static struct { + const char *note_sha; + const char *annotated_object_sha; +} list_expectations[] = { + { "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045" }, + { "1c73b1f51762155d357bcd1fd4f2c409ef80065b", "9fd738e8f7967c078dceed8190330fc8648ee56a" }, + { "257b43746b6b46caa4aa788376c647cce0a33e2b", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750" }, + { "1ec1c8e03f461f4f5d3f3702172483662e7223f3", "c47800c7266a2be04c571c04d5a6614691ea99bd" }, + { NULL, NULL } +}; + +#define EXPECTATIONS_COUNT (sizeof(list_expectations)/sizeof(list_expectations[0])) - 1 + +static int note_list_cb(git_note_data *note_data, void *payload) +{ + git_oid expected_note_oid, expected_target_oid; + + unsigned int *count = (unsigned int *)payload; + + cl_assert(*count < EXPECTATIONS_COUNT); + + cl_git_pass(git_oid_fromstr(&expected_note_oid, list_expectations[*count].note_sha)); + cl_assert(git_oid_cmp(&expected_note_oid, ¬e_data->blob_oid) == 0); + + cl_git_pass(git_oid_fromstr(&expected_target_oid, list_expectations[*count].annotated_object_sha)); + cl_assert(git_oid_cmp(&expected_target_oid, ¬e_data->annotated_object_oid) == 0); + + (*count)++; + + return 0; +} + +/* + * $ git notes --ref i-can-see-dead-notes add -m "I decorate a65f" a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + * $ git notes --ref i-can-see-dead-notes add -m "I decorate c478" c47800c7266a2be04c571c04d5a6614691ea99bd + * $ git notes --ref i-can-see-dead-notes add -m "I decorate 9fd7 and 4a20" 9fd738e8f7967c078dceed8190330fc8648ee56a + * $ git notes --ref i-can-see-dead-notes add -m "I decorate 9fd7 and 4a20" 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 + * + * $ git notes --ref i-can-see-dead-notes list + * 1c73b1f51762155d357bcd1fd4f2c409ef80065b 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 + * 1c73b1f51762155d357bcd1fd4f2c409ef80065b 9fd738e8f7967c078dceed8190330fc8648ee56a + * 257b43746b6b46caa4aa788376c647cce0a33e2b a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + * 1ec1c8e03f461f4f5d3f3702172483662e7223f3 c47800c7266a2be04c571c04d5a6614691ea99bd + * + * $ git ls-tree refs/notes/i-can-see-dead-notes + * 100644 blob 1c73b1f51762155d357bcd1fd4f2c409ef80065b 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 + * 100644 blob 1c73b1f51762155d357bcd1fd4f2c409ef80065b 9fd738e8f7967c078dceed8190330fc8648ee56a + * 100644 blob 257b43746b6b46caa4aa788376c647cce0a33e2b a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + * 100644 blob 1ec1c8e03f461f4f5d3f3702172483662e7223f3 c47800c7266a2be04c571c04d5a6614691ea99bd +*/ +void test_notes_notes__can_retrieve_a_list_of_notes_for_a_given_namespace(void) +{ + git_oid note_oid1, note_oid2, note_oid3, note_oid4; + unsigned int retrieved_notes = 0; + + create_note(¬e_oid1, "refs/notes/i-can-see-dead-notes", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "I decorate a65f\n"); + create_note(¬e_oid2, "refs/notes/i-can-see-dead-notes", "c47800c7266a2be04c571c04d5a6614691ea99bd", "I decorate c478\n"); + create_note(¬e_oid3, "refs/notes/i-can-see-dead-notes", "9fd738e8f7967c078dceed8190330fc8648ee56a", "I decorate 9fd7 and 4a20\n"); + create_note(¬e_oid4, "refs/notes/i-can-see-dead-notes", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045", "I decorate 9fd7 and 4a20\n"); + + cl_git_pass(git_note_foreach(_repo, "refs/notes/i-can-see-dead-notes", note_list_cb, &retrieved_notes)); + + cl_assert_equal_i(4, retrieved_notes); +} + +void test_notes_notes__retrieving_a_list_of_notes_for_an_unknown_namespace_returns_ENOTFOUND(void) +{ + int error; + unsigned int retrieved_notes = 0; + + error = git_note_foreach(_repo, "refs/notes/i-am-not", note_list_cb, &retrieved_notes); + cl_git_fail(error); + cl_assert_equal_i(GIT_ENOTFOUND, error); + + cl_assert_equal_i(0, retrieved_notes); } diff --git a/tests-clar/object/blob/write.c b/tests-clar/object/blob/write.c new file mode 100644 index 000000000..722c7b956 --- /dev/null +++ b/tests-clar/object/blob/write.c @@ -0,0 +1,69 @@ +#include "clar_libgit2.h" +#include "buffer.h" +#include "posix.h" +#include "path.h" +#include "fileops.h" + +static git_repository *repo; + +#define WORKDIR "empty_standard_repo" +#define BARE_REPO "testrepo.git" +#define ELSEWHERE "elsewhere" + +typedef int (*blob_creator_fn)( + git_oid *, + git_repository *, + const char *); + +void test_object_blob_write__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +static void assert_blob_creation(const char *path_to_file, const char *blob_from_path, blob_creator_fn creator) +{ + git_oid oid; + cl_git_mkfile(path_to_file, "1..2...3... Can you hear me?\n"); + + cl_must_pass(creator(&oid, repo, blob_from_path)); + cl_assert(git_oid_streq(&oid, "da5e4f20c91c81b44a7e298f3d3fb3fe2f178e32") == 0); +} + +void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_file_located_in_the_working_directory(void) +{ + repo = cl_git_sandbox_init(WORKDIR); + + assert_blob_creation(WORKDIR "/test.txt", "test.txt", &git_blob_create_fromfile); +} + +void test_object_blob_write__can_create_a_blob_in_a_standard_repo_from_a_absolute_filepath_pointing_outside_of_the_working_directory(void) +{ + git_buf full_path = GIT_BUF_INIT; + + repo = cl_git_sandbox_init(WORKDIR); + + cl_must_pass(p_mkdir(ELSEWHERE, 0777)); + cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL)); + cl_must_pass(git_buf_puts(&full_path, "test.txt")); + + assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); + + git_buf_free(&full_path); + cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS)); +} + +void test_object_blob_write__can_create_a_blob_in_a_bare_repo_from_a_absolute_filepath(void) +{ + git_buf full_path = GIT_BUF_INIT; + + repo = cl_git_sandbox_init(BARE_REPO); + + cl_must_pass(p_mkdir(ELSEWHERE, 0777)); + cl_must_pass(git_path_prettify_dir(&full_path, ELSEWHERE, NULL)); + cl_must_pass(git_buf_puts(&full_path, "test.txt")); + + assert_blob_creation(ELSEWHERE "/test.txt", git_buf_cstr(&full_path), &git_blob_create_fromdisk); + + git_buf_free(&full_path); + cl_must_pass(git_futils_rmdir_r(ELSEWHERE, GIT_DIRREMOVAL_FILES_AND_DIRS)); +} diff --git a/tests-clar/object/lookup.c b/tests-clar/object/lookup.c index 4732865cb..7cbcc6140 100644 --- a/tests-clar/object/lookup.c +++ b/tests-clar/object/lookup.c @@ -35,3 +35,29 @@ void test_object_lookup__lookup_nonexisting_returns_enotfound(void) cl_assert_equal_i( GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_ANY)); } + +void test_object_lookup__lookup_wrong_type_by_abbreviated_id_returns_enotfound(void) +{ + const char *commit = "e90810b"; + git_oid oid; + git_object *object; + + cl_git_pass(git_oid_fromstrn(&oid, commit, strlen(commit))); + cl_assert_equal_i( + GIT_ENOTFOUND, git_object_lookup_prefix(&object, g_repo, &oid, strlen(commit), GIT_OBJ_TAG)); +} + +void test_object_lookup__lookup_wrong_type_eventually_returns_enotfound(void) +{ + const char *commit = "e90810b8df3e80c413d903f631643c716887138d"; + git_oid oid; + git_object *object; + + cl_git_pass(git_oid_fromstr(&oid, commit)); + + cl_git_pass(git_object_lookup(&object, g_repo, &oid, GIT_OBJ_COMMIT)); + git_object_free(object); + + cl_assert_equal_i( + GIT_ENOTFOUND, git_object_lookup(&object, g_repo, &oid, GIT_OBJ_TAG)); +} diff --git a/tests-clar/object/tag/read.c b/tests-clar/object/tag/read.c index cfeb3aeee..6a0ad8a23 100644 --- a/tests-clar/object/tag/read.c +++ b/tests-clar/object/tag/read.c @@ -17,9 +17,9 @@ static void ensure_tag_pattern_match(git_repository *repo, const size_t expected_matches) { git_strarray tag_list; - int error = GIT_SUCCESS; + int error = 0; - if ((error = git_tag_list_match(&tag_list, pattern, repo)) < GIT_SUCCESS) + if ((error = git_tag_list_match(&tag_list, pattern, repo)) < 0) goto exit; if (tag_list.count != expected_matches) diff --git a/tests-clar/object/tree/diff.c b/tests-clar/object/tree/diff.c deleted file mode 100644 index 631fc3be4..000000000 --- a/tests-clar/object/tree/diff.c +++ /dev/null @@ -1,168 +0,0 @@ -#include "clar_libgit2.h" -#include "tree.h" -#include "repository.h" - -static git_repository *repo; -static git_index *theindex; -static git_tree *atree, *btree; -static git_oid aoid, boid; - -static void diff_cmp(const git_tree_diff_data *a, const git_tree_diff_data *b) -{ - cl_assert(a->old_attr - b->old_attr == 0); - - cl_assert(a->new_attr - b->new_attr == 0); - - cl_assert(git_oid_cmp(&a->old_oid, &b->old_oid) == 0); - cl_assert(git_oid_cmp(&a->new_oid, &b->new_oid) == 0); - - cl_assert(a->status - b->status == 0); - - cl_assert_equal_s(a->path, b->path); -} - -static int diff_cb(const git_tree_diff_data *diff, void *data) -{ - diff_cmp(diff, data); - return 0; -} - -static void test_diff(git_tree *a, git_tree *b, git_tree_diff_cb cb, void *data) -{ - cl_must_pass(git_tree_diff(a, b, cb, data)); - - cl_git_pass(git_index_read_tree(theindex, b)); - cl_git_pass(git_tree_diff_index_recursive(a, theindex, cb, data)); -} - -void test_object_tree_diff__initialize(void) -{ - cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); - cl_git_pass(git_repository_index(&theindex, repo)); -} - -void test_object_tree_diff__cleanup(void) -{ - git_tree_free(atree); - git_tree_free(btree); - git_index_free(theindex); - git_repository_free(repo); -} - -void test_object_tree_diff__addition(void) -{ - char *astr = "181037049a54a1eb5fab404658a3a250b44335d7"; - char *bstr = "f60079018b664e4e79329a7ef9559c8d9e0378d1"; - git_tree_diff_data expect; - - memset(&expect, 0x0, sizeof(git_tree_diff_data)); - expect.old_attr = 0; - expect.new_attr = 0100644; - git_oid_fromstr(&expect.new_oid, "fa49b077972391ad58037050f2a75f74e3671e92"); - expect.status = GIT_STATUS_ADDED; - expect.path = "new.txt"; - - cl_must_pass(git_oid_fromstr(&aoid, astr)); - cl_must_pass(git_oid_fromstr(&boid, bstr)); - - cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); - cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - - test_diff(atree, btree, diff_cb, &expect); -} - -void test_object_tree_diff__deletion(void) -{ - char *astr = "f60079018b664e4e79329a7ef9559c8d9e0378d1"; - char *bstr = "181037049a54a1eb5fab404658a3a250b44335d7"; - git_tree_diff_data expect; - - memset(&expect, 0x0, sizeof(git_tree_diff_data)); - expect.old_attr = 0100644; - expect.new_attr = 0; - git_oid_fromstr(&expect.old_oid, "fa49b077972391ad58037050f2a75f74e3671e92"); - expect.status = GIT_STATUS_DELETED; - expect.path = "new.txt"; - cl_must_pass(git_oid_fromstr(&aoid, astr)); - cl_must_pass(git_oid_fromstr(&boid, bstr)); - - cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); - cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - - test_diff(atree, btree, diff_cb, &expect); -} - -void test_object_tree_diff__modification(void) -{ - char *astr = "1810dff58d8a660512d4832e740f692884338ccd"; - char *bstr = "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"; - git_tree_diff_data expect; - - expect.old_attr = 0100644; - expect.new_attr = 0100644; - git_oid_fromstr(&expect.old_oid, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); - git_oid_fromstr(&expect.new_oid, "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); - expect.status = GIT_STATUS_MODIFIED; - expect.path = "branch_file.txt"; - - cl_must_pass(git_oid_fromstr(&aoid, astr)); - cl_must_pass(git_oid_fromstr(&boid, bstr)); - - cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); - cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - - test_diff(atree, btree, diff_cb, &expect); -} - -struct diff_more_data { - git_tree_diff_data expect[3]; - int expect_idx; -}; - -static int diff_more_cb(const git_tree_diff_data *diff, void *data) -{ - struct diff_more_data *more_data = data; - diff_cmp(diff, &more_data->expect[more_data->expect_idx]); - - more_data->expect_idx = (more_data->expect_idx + 1) % ARRAY_SIZE(more_data->expect); - - return 0; -} - -void test_object_tree_diff__more(void) -{ - char *astr = "814889a078c031f61ed08ab5fa863aea9314344d"; - char *bstr = "75057dd4114e74cca1d750d0aee1647c903cb60a"; - struct diff_more_data more_data; - git_tree_diff_data *expect = more_data.expect; - - memset(&more_data, 0x0, sizeof(struct diff_more_data)); - /* M README */ - expect[0].old_attr = 0100644; - expect[0].new_attr = 0100644; - git_oid_fromstr(&expect[0].old_oid, "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); - git_oid_fromstr(&expect[0].new_oid, "1385f264afb75a56a5bec74243be9b367ba4ca08"); - expect[0].status = GIT_STATUS_MODIFIED; - expect[0].path = "README"; - /* A branch_file.txt */ - expect[1].old_attr = 0; - expect[1].new_attr = 0100644; - git_oid_fromstr(&expect[1].new_oid, "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); - expect[1].status = GIT_STATUS_ADDED; - expect[1].path = "branch_file.txt"; - /* M new.txt */ - expect[2].old_attr = 0100644; - expect[2].new_attr = 0100644; - git_oid_fromstr(&expect[2].old_oid, "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"); - git_oid_fromstr(&expect[2].new_oid, "fa49b077972391ad58037050f2a75f74e3671e92"); - expect[2].status = GIT_STATUS_MODIFIED; - expect[2].path = "new.txt"; - - cl_must_pass(git_oid_fromstr(&aoid, astr)); - cl_must_pass(git_oid_fromstr(&boid, bstr)); - - cl_must_pass(git_tree_lookup(&atree, repo, &aoid)); - cl_must_pass(git_tree_lookup(&btree, repo, &boid)); - - test_diff(atree, btree, diff_more_cb, &more_data); -} diff --git a/tests-clar/object/tree/frompath.c b/tests-clar/object/tree/frompath.c index ea0add37b..06c69ac08 100644 --- a/tests-clar/object/tree/frompath.c +++ b/tests-clar/object/tree/frompath.c @@ -30,10 +30,10 @@ static void assert_tree_from_path(git_tree *root, const char *path, int expected cl_assert(git_tree_get_subtree(&containing_tree, root, path) == expected_result); - if (containing_tree == NULL && expected_result != GIT_SUCCESS) + if (containing_tree == NULL && expected_result != 0) return; - cl_assert(containing_tree != NULL && expected_result == GIT_SUCCESS); + cl_assert(containing_tree != NULL && expected_result == 0); cl_git_pass(git_oid_streq(git_object_id((const git_object *)containing_tree), expected_raw_oid)); @@ -49,19 +49,19 @@ static void assert_tree_from_path_klass(git_tree *root, const char *path, int ex void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void) { /* Will return self if given a one path segment... */ - assert_tree_from_path(tree, "README", GIT_SUCCESS, tree_with_subtrees_oid); + assert_tree_from_path(tree, "README", 0, tree_with_subtrees_oid); /* ...even one that lead to a non existent tree entry. */ - assert_tree_from_path(tree, "i-do-not-exist.txt", GIT_SUCCESS, tree_with_subtrees_oid); + assert_tree_from_path(tree, "i-do-not-exist.txt", 0, tree_with_subtrees_oid); /* Will return fgh tree oid given this following path... */ - assert_tree_from_path(tree, "ab/de/fgh/1.txt", GIT_SUCCESS, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54"); + assert_tree_from_path(tree, "ab/de/fgh/1.txt", 0, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54"); /* ... and ab tree oid given this one. */ - assert_tree_from_path(tree, "ab/de", GIT_SUCCESS, "f1425cef211cc08caa31e7b545ffb232acb098c3"); + assert_tree_from_path(tree, "ab/de", 0, "f1425cef211cc08caa31e7b545ffb232acb098c3"); /* Will succeed if given a valid path which leads to a tree entry which doesn't exist */ - assert_tree_from_path(tree, "ab/de/fgh/i-do-not-exist.txt", GIT_SUCCESS, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54"); + assert_tree_from_path(tree, "ab/de/fgh/i-do-not-exist.txt", 0, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54"); } void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void) diff --git a/tests-clar/object/tree/read.c b/tests-clar/object/tree/read.c index 362508f91..59a809bf1 100644 --- a/tests-clar/object/tree/read.c +++ b/tests-clar/object/tree/read.c @@ -67,7 +67,7 @@ void test_object_tree_read__two(void) cl_assert_equal_s(git_tree_entry_name(entry), "README"); - cl_git_pass(git_tree_entry_2object(&obj, g_repo, entry)); + cl_git_pass(git_tree_entry_to_object(&obj, g_repo, entry)); cl_assert(obj != NULL); git_object_free(obj); diff --git a/tests-clar/odb/mixed.c b/tests-clar/odb/mixed.c new file mode 100644 index 000000000..0bd23e157 --- /dev/null +++ b/tests-clar/odb/mixed.c @@ -0,0 +1,24 @@ +#include "clar_libgit2.h" +#include "odb.h" + +static git_odb *_odb; + +void test_odb_mixed__initialize(void) +{ + cl_git_pass(git_odb_open(&_odb, cl_fixture("duplicate.git/objects"))); +} + +void test_odb_mixed__cleanup(void) +{ + git_odb_free(_odb); +} + +void test_odb_mixed__dup_oid(void) { + const char hex[] = "ce013625030ba8dba906f756967f9e9ca394464a"; + git_oid oid; + git_odb_object *obj; + cl_git_pass(git_oid_fromstr(&oid, hex)); + cl_git_pass(git_odb_read_prefix(&obj, _odb, &oid, GIT_OID_HEXSZ)); + git_odb_object_free(obj); +} + diff --git a/tests-clar/refs/branches/delete.c b/tests-clar/refs/branches/delete.c index 095893020..03d3c56d7 100644 --- a/tests-clar/refs/branches/delete.c +++ b/tests-clar/refs/branches/delete.c @@ -74,3 +74,18 @@ void test_refs_branches_delete__can_delete_a_remote_branch(void) { cl_git_pass(git_branch_delete(repo, "nulltoken/master", GIT_BRANCH_REMOTE)); } + +static void assert_non_exisitng_branch_removal(const char *branch_name, git_branch_t branch_type) +{ + int error; + error = git_branch_delete(repo, branch_name, branch_type); + + cl_git_fail(error); + cl_assert_equal_i(GIT_ENOTFOUND, error); +} + +void test_refs_branches_delete__deleting_a_non_existing_branch_returns_ENOTFOUND(void) +{ + assert_non_exisitng_branch_removal("i-do-not-locally-exist", GIT_BRANCH_LOCAL); + assert_non_exisitng_branch_removal("neither/remotely", GIT_BRANCH_REMOTE); +} diff --git a/tests-clar/refs/branches/listall.c b/tests-clar/refs/branches/listall.c index 8eb228d31..0bb559173 100644 --- a/tests-clar/refs/branches/listall.c +++ b/tests-clar/refs/branches/listall.c @@ -47,3 +47,32 @@ void test_refs_branches_listall__retrieve_local_branches(void) { assert_retrieval(GIT_BRANCH_LOCAL, 7); } + +static void assert_branch_list_contains(git_strarray *branches, const char* expected_branch_name) +{ + unsigned int i; + + for (i = 0; i < branches->count; i++) { + if (strcmp(expected_branch_name, branches->strings[i]) == 0) + return; + } + + cl_fail("expected branch not found in list."); +} + +/* + * $ git branch -r + * nulltoken/HEAD -> nulltoken/master + * nulltoken/master + */ +void test_refs_branches_listall__retrieve_remote_symbolic_HEAD_when_present(void) +{ + git_reference_free(fake_remote); + cl_git_pass(git_reference_create_symbolic(&fake_remote, repo, "refs/remotes/nulltoken/HEAD", "refs/remotes/nulltoken/master", 0)); + + cl_git_pass(git_branch_list(&branch_list, repo, GIT_BRANCH_REMOTE)); + + cl_assert_equal_i(2, branch_list.count); + assert_branch_list_contains(&branch_list, "refs/remotes/nulltoken/HEAD"); + assert_branch_list_contains(&branch_list, "refs/remotes/nulltoken/master"); +} diff --git a/tests-clar/refs/branches/move.c b/tests-clar/refs/branches/move.c index 208bb460e..242e5cd01 100644 --- a/tests-clar/refs/branches/move.c +++ b/tests-clar/refs/branches/move.c @@ -60,3 +60,13 @@ void test_refs_branches_move__can_not_move_a_branch_through_its_canonical_name(v { cl_git_fail(git_branch_move(repo, "refs/heads/br2", NEW_BRANCH_NAME, 1)); } + +void test_refs_branches_move__moving_a_non_exisiting_branch_returns_ENOTFOUND(void) +{ + int error; + + error = git_branch_move(repo, "where/am/I", NEW_BRANCH_NAME, 0); + cl_git_fail(error); + + cl_assert_equal_i(GIT_ENOTFOUND, error); +} diff --git a/tests-clar/refs/list.c b/tests-clar/refs/list.c index f673bd9be..2a7b157ca 100644 --- a/tests-clar/refs/list.c +++ b/tests-clar/refs/list.c @@ -25,7 +25,7 @@ void test_refs_list__all(void) // try to list all the references in our test repo git_strarray ref_list; - cl_git_pass(git_reference_listall(&ref_list, g_repo, GIT_REF_LISTALL)); + cl_git_pass(git_reference_list(&ref_list, g_repo, GIT_REF_LISTALL)); /*{ unsigned short i; @@ -46,7 +46,7 @@ void test_refs_list__symbolic_only(void) // try to list only the symbolic references git_strarray ref_list; - cl_git_pass(git_reference_listall(&ref_list, g_repo, GIT_REF_SYMBOLIC)); + cl_git_pass(git_reference_list(&ref_list, g_repo, GIT_REF_SYMBOLIC)); cl_assert(ref_list.count == 0); /* no symrefs in the test repo */ git_strarray_free(&ref_list); diff --git a/tests-clar/refs/listall.c b/tests-clar/refs/listall.c index ced40a26e..7f1de74cc 100644 --- a/tests-clar/refs/listall.c +++ b/tests-clar/refs/listall.c @@ -9,7 +9,7 @@ static void ensure_no_refname_starts_with_a_forward_slash(const char *path) size_t i; cl_git_pass(git_repository_open(&repo, path)); - cl_git_pass(git_reference_listall(&ref_list, repo, GIT_REF_LISTALL)); + cl_git_pass(git_reference_list(&ref_list, repo, GIT_REF_LISTALL)); cl_assert(ref_list.count > 0); diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c index a12a2c2fb..7f16b5b7c 100644 --- a/tests-clar/repo/init.c +++ b/tests-clar/repo/init.c @@ -141,3 +141,27 @@ void test_repo_init__reinit_too_recent_bare_repo(void) cl_fixture_cleanup("reinit.git"); } + +void test_repo_init__additional_templates(void) +{ + git_buf path = GIT_BUF_INIT; + + cl_set_cleanup(&cleanup_repository, "tester"); + + ensure_repository_init("tester", 0, "tester/.git/", "tester/"); + + cl_git_pass( + git_buf_joinpath(&path, git_repository_path(_repo), "description")); + cl_assert(git_path_isfile(git_buf_cstr(&path))); + + cl_git_pass( + git_buf_joinpath(&path, git_repository_path(_repo), "info/exclude")); + cl_assert(git_path_isfile(git_buf_cstr(&path))); + + cl_git_pass( + git_buf_joinpath(&path, git_repository_path(_repo), "hooks")); + cl_assert(git_path_isdir(git_buf_cstr(&path))); + /* won't confirm specific contents of hooks dir since it may vary */ + + git_buf_free(&path); +} diff --git a/tests-clar/repo/open.c b/tests-clar/repo/open.c index 292466390..c70ec83a9 100644 --- a/tests-clar/repo/open.c +++ b/tests-clar/repo/open.c @@ -279,4 +279,4 @@ void test_repo_open__opening_a_non_existing_repository_returns_ENOTFOUND(void) { git_repository *repo; cl_assert_equal_i(GIT_ENOTFOUND, git_repository_open(&repo, "i-do-not/exist")); -} \ No newline at end of file +} diff --git a/tests-clar/resources/duplicate.git/COMMIT_EDITMSG b/tests-clar/resources/duplicate.git/COMMIT_EDITMSG new file mode 100644 index 000000000..01f9a2aac --- /dev/null +++ b/tests-clar/resources/duplicate.git/COMMIT_EDITMSG @@ -0,0 +1 @@ +commit diff --git a/tests-clar/resources/duplicate.git/HEAD b/tests-clar/resources/duplicate.git/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests-clar/resources/duplicate.git/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/duplicate.git/config b/tests-clar/resources/duplicate.git/config new file mode 100644 index 000000000..515f48362 --- /dev/null +++ b/tests-clar/resources/duplicate.git/config @@ -0,0 +1,5 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true diff --git a/tests-clar/resources/duplicate.git/description b/tests-clar/resources/duplicate.git/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/tests-clar/resources/duplicate.git/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests-clar/resources/duplicate.git/hooks/applypatch-msg.sample b/tests-clar/resources/duplicate.git/hooks/applypatch-msg.sample new file mode 100755 index 000000000..8b2a2fe84 --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/applypatch-msg.sample @@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +: diff --git a/tests-clar/resources/duplicate.git/hooks/commit-msg.sample b/tests-clar/resources/duplicate.git/hooks/commit-msg.sample new file mode 100755 index 000000000..b58d1184a --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/commit-msg.sample @@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} diff --git a/tests-clar/resources/duplicate.git/hooks/post-update.sample b/tests-clar/resources/duplicate.git/hooks/post-update.sample new file mode 100755 index 000000000..ec17ec193 --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/tests-clar/resources/duplicate.git/hooks/pre-applypatch.sample b/tests-clar/resources/duplicate.git/hooks/pre-applypatch.sample new file mode 100755 index 000000000..b1f187c2e --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/pre-applypatch.sample @@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +: diff --git a/tests-clar/resources/duplicate.git/hooks/pre-commit.sample b/tests-clar/resources/duplicate.git/hooks/pre-commit.sample new file mode 100755 index 000000000..18c482976 --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/pre-commit.sample @@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- diff --git a/tests-clar/resources/duplicate.git/hooks/pre-rebase.sample b/tests-clar/resources/duplicate.git/hooks/pre-rebase.sample new file mode 100755 index 000000000..9773ed4cb --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/pre-rebase.sample @@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". diff --git a/tests-clar/resources/duplicate.git/hooks/prepare-commit-msg.sample b/tests-clar/resources/duplicate.git/hooks/prepare-commit-msg.sample new file mode 100755 index 000000000..f093a02ec --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/prepare-commit-msg.sample @@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" diff --git a/tests-clar/resources/duplicate.git/hooks/update.sample b/tests-clar/resources/duplicate.git/hooks/update.sample new file mode 100755 index 000000000..71ab04edc --- /dev/null +++ b/tests-clar/resources/duplicate.git/hooks/update.sample @@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 )" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 " >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 diff --git a/tests-clar/resources/duplicate.git/index b/tests-clar/resources/duplicate.git/index new file mode 100644 index 000000000..a61e1c5ca Binary files /dev/null and b/tests-clar/resources/duplicate.git/index differ diff --git a/tests-clar/resources/duplicate.git/info/exclude b/tests-clar/resources/duplicate.git/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/tests-clar/resources/duplicate.git/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests-clar/resources/duplicate.git/info/refs b/tests-clar/resources/duplicate.git/info/refs new file mode 100644 index 000000000..3b5bb03be --- /dev/null +++ b/tests-clar/resources/duplicate.git/info/refs @@ -0,0 +1 @@ +8d2f05c97ef29a4697b37c30fe81c248ef411a23 refs/heads/master diff --git a/tests-clar/resources/duplicate.git/logs/HEAD b/tests-clar/resources/duplicate.git/logs/HEAD new file mode 100644 index 000000000..be9b4c6cb --- /dev/null +++ b/tests-clar/resources/duplicate.git/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 8d2f05c97ef29a4697b37c30fe81c248ef411a23 Han-Wen Nienhuys 1336844322 -0300 commit (initial): commit diff --git a/tests-clar/resources/duplicate.git/logs/refs/heads/master b/tests-clar/resources/duplicate.git/logs/refs/heads/master new file mode 100644 index 000000000..be9b4c6cb --- /dev/null +++ b/tests-clar/resources/duplicate.git/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 8d2f05c97ef29a4697b37c30fe81c248ef411a23 Han-Wen Nienhuys 1336844322 -0300 commit (initial): commit diff --git a/tests-clar/resources/duplicate.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a b/tests-clar/resources/duplicate.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a new file mode 100644 index 000000000..6802d4949 Binary files /dev/null and b/tests-clar/resources/duplicate.git/objects/ce/013625030ba8dba906f756967f9e9ca394464a differ diff --git a/tests-clar/resources/duplicate.git/objects/info/packs b/tests-clar/resources/duplicate.git/objects/info/packs new file mode 100644 index 000000000..3696a7d36 --- /dev/null +++ b/tests-clar/resources/duplicate.git/objects/info/packs @@ -0,0 +1,2 @@ +P pack-e87994ad581c9af946de0eb890175c08cd005f38.pack + diff --git a/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.idx b/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.idx new file mode 100644 index 000000000..fd8abee98 Binary files /dev/null and b/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.idx differ diff --git a/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.pack b/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.pack new file mode 100644 index 000000000..9879e0869 Binary files /dev/null and b/tests-clar/resources/duplicate.git/objects/pack/pack-e87994ad581c9af946de0eb890175c08cd005f38.pack differ diff --git a/tests-clar/resources/duplicate.git/packed-refs b/tests-clar/resources/duplicate.git/packed-refs new file mode 100644 index 000000000..9f0d4e434 --- /dev/null +++ b/tests-clar/resources/duplicate.git/packed-refs @@ -0,0 +1,2 @@ +# pack-refs with: peeled +8d2f05c97ef29a4697b37c30fe81c248ef411a23 refs/heads/master diff --git a/tests-clar/resources/issue_592b/.gitted/HEAD b/tests-clar/resources/issue_592b/.gitted/HEAD new file mode 100644 index 000000000..cb089cd89 --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/HEAD @@ -0,0 +1 @@ +ref: refs/heads/master diff --git a/tests-clar/resources/issue_592b/.gitted/config b/tests-clar/resources/issue_592b/.gitted/config new file mode 100644 index 000000000..af107929f --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/config @@ -0,0 +1,6 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true + ignorecase = true diff --git a/tests-clar/resources/issue_592b/.gitted/description b/tests-clar/resources/issue_592b/.gitted/description new file mode 100644 index 000000000..498b267a8 --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/description @@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. diff --git a/tests-clar/resources/issue_592b/.gitted/hooks/post-update.sample b/tests-clar/resources/issue_592b/.gitted/hooks/post-update.sample new file mode 100755 index 000000000..ec17ec193 --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/hooks/post-update.sample @@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info diff --git a/tests-clar/resources/issue_592b/.gitted/index b/tests-clar/resources/issue_592b/.gitted/index new file mode 100644 index 000000000..596438216 Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/index differ diff --git a/tests-clar/resources/issue_592b/.gitted/info/exclude b/tests-clar/resources/issue_592b/.gitted/info/exclude new file mode 100644 index 000000000..a5196d1be --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/info/exclude @@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ diff --git a/tests-clar/resources/issue_592b/.gitted/logs/HEAD b/tests-clar/resources/issue_592b/.gitted/logs/HEAD new file mode 100644 index 000000000..6f3ba90cc --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/logs/HEAD @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 3fbf1852f72fd268e36457b13a18cdd9a4c9ea35 Russell Belfer 1337205933 -0700 commit (initial): Initial commit diff --git a/tests-clar/resources/issue_592b/.gitted/logs/refs/heads/master b/tests-clar/resources/issue_592b/.gitted/logs/refs/heads/master new file mode 100644 index 000000000..6f3ba90cc --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/logs/refs/heads/master @@ -0,0 +1 @@ +0000000000000000000000000000000000000000 3fbf1852f72fd268e36457b13a18cdd9a4c9ea35 Russell Belfer 1337205933 -0700 commit (initial): Initial commit diff --git a/tests-clar/resources/issue_592b/.gitted/objects/3f/bf1852f72fd268e36457b13a18cdd9a4c9ea35 b/tests-clar/resources/issue_592b/.gitted/objects/3f/bf1852f72fd268e36457b13a18cdd9a4c9ea35 new file mode 100644 index 000000000..6eaf64b46 --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/objects/3f/bf1852f72fd268e36457b13a18cdd9a4c9ea35 @@ -0,0 +1,2 @@ +xK +1]}%BwnAq xzVƃv ɂc&%9@9xdu.]".=EבO+ۘBEk\N_<>E U%9 \ No newline at end of file diff --git a/tests-clar/resources/issue_592b/.gitted/objects/6f/a891d3e578c83e1c03bdb9e0fdd8e6e934157f b/tests-clar/resources/issue_592b/.gitted/objects/6f/a891d3e578c83e1c03bdb9e0fdd8e6e934157f new file mode 100644 index 000000000..c4becfe2f Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/6f/a891d3e578c83e1c03bdb9e0fdd8e6e934157f differ diff --git a/tests-clar/resources/issue_592b/.gitted/objects/80/07d41d5794e6ce4d4d2c97e370d5a9aa6d5213 b/tests-clar/resources/issue_592b/.gitted/objects/80/07d41d5794e6ce4d4d2c97e370d5a9aa6d5213 new file mode 100644 index 000000000..aea14f2af Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/80/07d41d5794e6ce4d4d2c97e370d5a9aa6d5213 differ diff --git a/tests-clar/resources/issue_592b/.gitted/objects/a6/5fb6583a7c425284142f285bc359a2d6565513 b/tests-clar/resources/issue_592b/.gitted/objects/a6/5fb6583a7c425284142f285bc359a2d6565513 new file mode 100644 index 000000000..9b7407221 Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/a6/5fb6583a7c425284142f285bc359a2d6565513 differ diff --git a/tests-clar/resources/issue_592b/.gitted/objects/ae/be7a55922c7097ef91ca3a7bc327a901d87c2c b/tests-clar/resources/issue_592b/.gitted/objects/ae/be7a55922c7097ef91ca3a7bc327a901d87c2c new file mode 100644 index 000000000..1494ed822 Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/ae/be7a55922c7097ef91ca3a7bc327a901d87c2c differ diff --git a/tests-clar/resources/issue_592b/.gitted/objects/b3/44b055867fcdc1f01eaa75056a43e868eb4fbc b/tests-clar/resources/issue_592b/.gitted/objects/b3/44b055867fcdc1f01eaa75056a43e868eb4fbc new file mode 100644 index 000000000..7a6626636 Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/b3/44b055867fcdc1f01eaa75056a43e868eb4fbc differ diff --git a/tests-clar/resources/issue_592b/.gitted/objects/f7/d75fbfad8b1d2e307ced287ea78aad403cdce3 b/tests-clar/resources/issue_592b/.gitted/objects/f7/d75fbfad8b1d2e307ced287ea78aad403cdce3 new file mode 100644 index 000000000..65a1fd0d0 Binary files /dev/null and b/tests-clar/resources/issue_592b/.gitted/objects/f7/d75fbfad8b1d2e307ced287ea78aad403cdce3 differ diff --git a/tests-clar/resources/issue_592b/.gitted/refs/heads/master b/tests-clar/resources/issue_592b/.gitted/refs/heads/master new file mode 100644 index 000000000..c0a9ab495 --- /dev/null +++ b/tests-clar/resources/issue_592b/.gitted/refs/heads/master @@ -0,0 +1 @@ +3fbf1852f72fd268e36457b13a18cdd9a4c9ea35 diff --git a/tests-clar/resources/issue_592b/gitignore b/tests-clar/resources/issue_592b/gitignore new file mode 100644 index 000000000..8007d41d5 --- /dev/null +++ b/tests-clar/resources/issue_592b/gitignore @@ -0,0 +1 @@ +ignored/ diff --git a/tests-clar/resources/issue_592b/ignored/contained/ignored3.txt b/tests-clar/resources/issue_592b/ignored/contained/ignored3.txt new file mode 100644 index 000000000..b5dc7b073 --- /dev/null +++ b/tests-clar/resources/issue_592b/ignored/contained/ignored3.txt @@ -0,0 +1 @@ +I'm ignored diff --git a/tests-clar/resources/issue_592b/ignored/contained/tracked3.txt b/tests-clar/resources/issue_592b/ignored/contained/tracked3.txt new file mode 100644 index 000000000..b344b0558 --- /dev/null +++ b/tests-clar/resources/issue_592b/ignored/contained/tracked3.txt @@ -0,0 +1 @@ +You added me anyhow diff --git a/tests-clar/resources/issue_592b/ignored/ignored2.txt b/tests-clar/resources/issue_592b/ignored/ignored2.txt new file mode 100644 index 000000000..b5dc7b073 --- /dev/null +++ b/tests-clar/resources/issue_592b/ignored/ignored2.txt @@ -0,0 +1 @@ +I'm ignored diff --git a/tests-clar/resources/issue_592b/ignored/tracked2.txt b/tests-clar/resources/issue_592b/ignored/tracked2.txt new file mode 100644 index 000000000..6fa891d3e --- /dev/null +++ b/tests-clar/resources/issue_592b/ignored/tracked2.txt @@ -0,0 +1 @@ +You like me diff --git a/tests-clar/resources/issue_592b/ignored1.txt b/tests-clar/resources/issue_592b/ignored1.txt new file mode 100644 index 000000000..b5dc7b073 --- /dev/null +++ b/tests-clar/resources/issue_592b/ignored1.txt @@ -0,0 +1 @@ +I'm ignored diff --git a/tests-clar/resources/issue_592b/tracked1.txt b/tests-clar/resources/issue_592b/tracked1.txt new file mode 100644 index 000000000..6fa891d3e --- /dev/null +++ b/tests-clar/resources/issue_592b/tracked1.txt @@ -0,0 +1 @@ +You like me diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index 7d54ce990..a5a9b2eda 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -73,7 +73,7 @@ static int test_walk(git_revwalk *walk, const git_oid *root, i = 0; - while (git_revwalk_next(&oid, walk) == GIT_SUCCESS) { + while (git_revwalk_next(&oid, walk) == 0) { result_array[i++] = get_commit_index(&oid); /*{ char str[41]; @@ -86,7 +86,7 @@ static int test_walk(git_revwalk *walk, const git_oid *root, for (i = 0; i < results_count; ++i) if (memcmp(possible_results[i], result_array, result_bytes) == 0) - return GIT_SUCCESS; + return 0; return GIT_ERROR; } @@ -125,7 +125,7 @@ void test_revwalk_basic__glob_heads(void) cl_git_pass(git_revwalk_push_glob(_walk, "heads")); - while (git_revwalk_next(&oid, _walk) == GIT_SUCCESS) { + while (git_revwalk_next(&oid, _walk) == 0) { i++; } @@ -140,7 +140,7 @@ void test_revwalk_basic__push_head(void) cl_git_pass(git_revwalk_push_head(_walk)); - while (git_revwalk_next(&oid, _walk) == GIT_SUCCESS) { + while (git_revwalk_next(&oid, _walk) == 0) { i++; } @@ -156,7 +156,7 @@ void test_revwalk_basic__push_head_hide_ref(void) cl_git_pass(git_revwalk_push_head(_walk)); cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed-test")); - while (git_revwalk_next(&oid, _walk) == GIT_SUCCESS) { + while (git_revwalk_next(&oid, _walk) == 0) { i++; } @@ -172,7 +172,7 @@ void test_revwalk_basic__push_head_hide_ref_nobase(void) cl_git_pass(git_revwalk_push_head(_walk)); cl_git_pass(git_revwalk_hide_ref(_walk, "refs/heads/packed")); - while (git_revwalk_next(&oid, _walk) == GIT_SUCCESS) { + while (git_revwalk_next(&oid, _walk) == 0) { i++; } diff --git a/tests-clar/revwalk/mergebase.c b/tests-clar/revwalk/mergebase.c index 91bc6ae8c..e807e3ad2 100644 --- a/tests-clar/revwalk/mergebase.c +++ b/tests-clar/revwalk/mergebase.c @@ -35,3 +35,114 @@ void test_revwalk_mergebase__single2(void) cl_git_pass(git_merge_base(&result, _repo, &one, &two)); cl_assert(git_oid_cmp(&result, &expected) == 0); } + +void test_revwalk_mergebase__merged_branch(void) +{ + git_oid result, one, two, expected; + + git_oid_fromstr(&one, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + git_oid_fromstr(&two, "9fd738e8f7967c078dceed8190330fc8648ee56a"); + git_oid_fromstr(&expected, "9fd738e8f7967c078dceed8190330fc8648ee56a"); + + cl_git_pass(git_merge_base(&result, _repo, &one, &two)); + cl_assert(git_oid_cmp(&result, &expected) == 0); + + cl_git_pass(git_merge_base(&result, _repo, &two, &one)); + cl_assert(git_oid_cmp(&result, &expected) == 0); +} + +void test_revwalk_mergebase__no_common_ancestor_returns_ENOTFOUND(void) +{ + git_oid result, one, two, expected; + int error; + + git_oid_fromstr(&one, "763d71aadf09a7951596c9746c024e7eece7c7af"); + git_oid_fromstr(&two, "e90810b8df3e80c413d903f631643c716887138d"); + git_oid_fromstr(&expected, "c47800c7266a2be04c571c04d5a6614691ea99bd"); + + error = git_merge_base(&result, _repo, &one, &two); + cl_git_fail(error); + + cl_assert_equal_i(GIT_ENOTFOUND, error); +} + +/* + * $ git log --graph --all + * * commit 763d71aadf09a7951596c9746c024e7eece7c7af + * | Author: nulltoken + * | Date: Sun Oct 9 12:54:47 2011 +0200 + * | + * | Add some files into subdirectories + * | + * | * commit a65fedf39aefe402d3bb6e24df4d4f5fe4547750 + * | | Author: Scott Chacon + * | | Date: Tue Aug 9 19:33:46 2011 -0700 + * | | + * | * commit be3563ae3f795b2b4353bcce3a527ad0a4f7f644 + * | |\ Merge: 9fd738e c47800c + * | |/ Author: Scott Chacon + * |/| Date: Tue May 25 11:58:27 2010 -0700 + * | | + * | | Merge branch 'br2' + * | | + * | | * commit e90810b8df3e80c413d903f631643c716887138d + * | | | Author: Vicent Marti + * | | | Date: Thu Aug 5 18:42:20 2010 +0200 + * | | | + * | | | Test commit 2 + * | | | + * | | * commit 6dcf9bf7541ee10456529833502442f385010c3d + * | | Author: Vicent Marti + * | | Date: Thu Aug 5 18:41:33 2010 +0200 + * | | + * | | Test commit 1 + * | | + * | | * commit a4a7dce85cf63874e984719f4fdd239f5145052f + * | | |\ Merge: c47800c 9fd738e + * | |/ / Author: Scott Chacon + * |/| / Date: Tue May 25 12:00:23 2010 -0700 + * | |/ + * | | Merge branch 'master' into br2 + * | | + * | * commit 9fd738e8f7967c078dceed8190330fc8648ee56a + * | | Author: Scott Chacon + * | | Date: Mon May 24 10:19:19 2010 -0700 + * | | + * | | a fourth commit + * | | + * | * commit 4a202b346bb0fb0db7eff3cffeb3c70babbd2045 + * | | Author: Scott Chacon + * | | Date: Mon May 24 10:19:04 2010 -0700 + * | | + * | | a third commit + * | | + * * | commit c47800c7266a2be04c571c04d5a6614691ea99bd + * |/ Author: Scott Chacon + * | Date: Tue May 25 11:58:14 2010 -0700 + * | + * | branch commit one + * | + * * commit 5b5b025afb0b4c913b4c338a42934a3863bf3644 + * | Author: Scott Chacon + * | Date: Tue May 11 13:38:42 2010 -0700 + * | + * | another commit + * | + * * commit 8496071c1b46c854b31185ea97743be6a8774479 + * Author: Scott Chacon + * Date: Sat May 8 16:13:06 2010 -0700 + * + * testing + * + * * commit 41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9 + * | Author: Scott Chacon + * | Date: Tue May 11 13:40:41 2010 -0700 + * | + * | packed commit two + * | + * * commit 5001298e0c09ad9c34e4249bc5801c75e9754fa5 + * Author: Scott Chacon + * Date: Tue May 11 13:40:23 2010 -0700 + * + * packed commit one + */ diff --git a/tests-clar/status/ignore.c b/tests-clar/status/ignore.c index e92d6a577..369b25bda 100644 --- a/tests-clar/status/ignore.c +++ b/tests-clar/status/ignore.c @@ -2,12 +2,12 @@ #include "fileops.h" #include "git2/attr.h" #include "attr.h" +#include "status_helpers.h" static git_repository *g_repo = NULL; void test_status_ignore__initialize(void) { - g_repo = cl_git_sandbox_init("attr"); } void test_status_ignore__cleanup(void) @@ -40,9 +40,11 @@ void test_status_ignore__0(void) { NULL, 0 } }, *one_test; + g_repo = cl_git_sandbox_init("attr"); + for (one_test = test_cases; one_test->path != NULL; one_test++) { int ignored; - cl_git_pass(git_status_should_ignore(g_repo, one_test->path, &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, one_test->path)); cl_assert_(ignored == one_test->expected, one_test->path); } @@ -56,25 +58,76 @@ void test_status_ignore__1(void) { int ignored; + g_repo = cl_git_sandbox_init("attr"); + cl_git_rewritefile("attr/.gitignore", "/*.txt\n/dir/\n"); git_attr_cache_flush(g_repo); - cl_git_pass(git_status_should_ignore(g_repo, "root_test4.txt", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "root_test4.txt")); cl_assert(ignored); - cl_git_pass(git_status_should_ignore(g_repo, "sub/subdir_test2.txt", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/subdir_test2.txt")); cl_assert(!ignored); - cl_git_pass(git_status_should_ignore(g_repo, "dir", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "dir")); cl_assert(ignored); - cl_git_pass(git_status_should_ignore(g_repo, "dir/", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "dir/")); cl_assert(ignored); - cl_git_pass(git_status_should_ignore(g_repo, "sub/dir", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/dir")); cl_assert(!ignored); - cl_git_pass(git_status_should_ignore(g_repo, "sub/dir/", &ignored)); + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "sub/dir/")); cl_assert(!ignored); } + +void test_status_ignore__empty_repo_with_gitignore_rewrite(void) +{ + status_entry_single st; + int ignored; + + g_repo = cl_git_sandbox_init("empty_standard_repo"); + + cl_git_mkfile( + "empty_standard_repo/look-ma.txt", "I'm going to be ignored!"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); + cl_assert(st.count == 1); + cl_assert(st.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); + cl_assert(st.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); + cl_assert(!ignored); + + cl_git_rewritefile("empty_standard_repo/.gitignore", "*.nomatch\n"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); + cl_assert(st.count == 2); + cl_assert(st.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); + cl_assert(st.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); + cl_assert(!ignored); + + cl_git_rewritefile("empty_standard_repo/.gitignore", "*.txt\n"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(g_repo, cb_status__single, &st)); + cl_assert(st.count == 2); + cl_assert(st.status == GIT_STATUS_IGNORED); + + cl_git_pass(git_status_file(&st.status, g_repo, "look-ma.txt")); + cl_assert(st.status == GIT_STATUS_IGNORED); + + cl_git_pass(git_status_should_ignore(&ignored, g_repo, "look-ma.txt")); + cl_assert(ignored); +} + diff --git a/tests-clar/status/status_data.h b/tests-clar/status/status_data.h index 7f078bf60..f109717e8 100644 --- a/tests-clar/status/status_data.h +++ b/tests-clar/status/status_data.h @@ -1,12 +1,4 @@ - -struct status_entry_counts { - size_t wrong_status_flags_count; - size_t wrong_sorted_path; - size_t entry_count; - const unsigned int* expected_statuses; - const char** expected_paths; - size_t expected_entry_count; -}; +#include "status_helpers.h" /* entries for a plain copy of tests/resources/status */ diff --git a/tests-clar/status/status_helpers.c b/tests-clar/status/status_helpers.c new file mode 100644 index 000000000..3dbf43a5b --- /dev/null +++ b/tests-clar/status/status_helpers.c @@ -0,0 +1,49 @@ +#include "clar_libgit2.h" +#include "status_helpers.h" + +int cb_status__normal( + const char *path, unsigned int status_flags, void *payload) +{ + status_entry_counts *counts = payload; + + if (counts->entry_count >= counts->expected_entry_count) { + counts->wrong_status_flags_count++; + goto exit; + } + + if (strcmp(path, counts->expected_paths[counts->entry_count])) { + counts->wrong_sorted_path++; + goto exit; + } + + if (status_flags != counts->expected_statuses[counts->entry_count]) + counts->wrong_status_flags_count++; + +exit: + counts->entry_count++; + return 0; +} + +int cb_status__count(const char *p, unsigned int s, void *payload) +{ + volatile int *count = (int *)payload; + + GIT_UNUSED(p); + GIT_UNUSED(s); + + (*count)++; + + return 0; +} + +int cb_status__single(const char *p, unsigned int s, void *payload) +{ + status_entry_single *data = (status_entry_single *)payload; + + GIT_UNUSED(p); + + data->count++; + data->status = s; + + return 0; +} diff --git a/tests-clar/status/status_helpers.h b/tests-clar/status/status_helpers.h new file mode 100644 index 000000000..cffca66a5 --- /dev/null +++ b/tests-clar/status/status_helpers.h @@ -0,0 +1,33 @@ +#ifndef INCLUDE_cl_status_helpers_h__ +#define INCLUDE_cl_status_helpers_h__ + +typedef struct { + size_t wrong_status_flags_count; + size_t wrong_sorted_path; + size_t entry_count; + const unsigned int* expected_statuses; + const char** expected_paths; + size_t expected_entry_count; +} status_entry_counts; + +/* cb_status__normal takes payload of "status_entry_counts *" */ + +extern int cb_status__normal( + const char *path, unsigned int status_flags, void *payload); + + +/* cb_status__count takes payload of "int *" */ + +extern int cb_status__count(const char *p, unsigned int s, void *payload); + + +typedef struct { + int count; + unsigned int status; +} status_entry_single; + +/* cb_status__single takes payload of "status_entry_single *" */ + +extern int cb_status__single(const char *p, unsigned int s, void *payload); + +#endif diff --git a/tests-clar/status/submodules.c b/tests-clar/status/submodules.c index 969158825..9423e8490 100644 --- a/tests-clar/status/submodules.c +++ b/tests-clar/status/submodules.c @@ -2,6 +2,7 @@ #include "buffer.h" #include "path.h" #include "posix.h" +#include "status_helpers.h" static git_repository *g_repo = NULL; @@ -43,19 +44,6 @@ void test_status_submodules__api(void) cl_assert_equal_s("testrepo", sm->path); } -static int -cb_status__submodule_count(const char *p, unsigned int s, void *payload) -{ - volatile int *count = (int *)payload; - - GIT_UNUSED(p); - GIT_UNUSED(s); - - (*count)++; - - return 0; -} - void test_status_submodules__0(void) { int counts = 0; @@ -65,7 +53,7 @@ void test_status_submodules__0(void) cl_assert(git_path_isfile("submodules/.gitmodules")); cl_git_pass( - git_status_foreach(g_repo, cb_status__submodule_count, &counts) + git_status_foreach(g_repo, cb_status__count, &counts) ); cl_assert(counts == 6); @@ -115,3 +103,10 @@ void test_status_submodules__1(void) cl_assert(index == 6); } + +void test_status_submodules__single_file(void) +{ + unsigned int status; + cl_git_pass( git_status_file(&status, g_repo, "testrepo") ); + cl_assert(status == 0); +} diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index 4ac556aa6..b3ebdb781 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -6,45 +6,6 @@ #include "util.h" #include "path.h" -/** - * Auxiliary methods - */ -static int -cb_status__normal( const char *path, unsigned int status_flags, void *payload) -{ - struct status_entry_counts *counts = payload; - - if (counts->entry_count >= counts->expected_entry_count) { - counts->wrong_status_flags_count++; - goto exit; - } - - if (strcmp(path, counts->expected_paths[counts->entry_count])) { - counts->wrong_sorted_path++; - goto exit; - } - - if (status_flags != counts->expected_statuses[counts->entry_count]) - counts->wrong_status_flags_count++; - -exit: - counts->entry_count++; - return 0; -} - -static int -cb_status__count(const char *p, unsigned int s, void *payload) -{ - volatile int *count = (int *)payload; - - GIT_UNUSED(p); - GIT_UNUSED(s); - - (*count)++; - - return 0; -} - /** * Initializer * @@ -72,10 +33,10 @@ void test_status_worktree__cleanup(void) /* this test is equivalent to t18-status.c:statuscb0 */ void test_status_worktree__whole_repository(void) { - struct status_entry_counts counts; + status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); - memset(&counts, 0x0, sizeof(struct status_entry_counts)); + memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count0; counts.expected_paths = entry_paths0; counts.expected_statuses = entry_statuses0; @@ -84,9 +45,9 @@ void test_status_worktree__whole_repository(void) git_status_foreach(repo, cb_status__normal, &counts) ); - cl_assert(counts.entry_count == counts.expected_entry_count); - cl_assert(counts.wrong_status_flags_count == 0); - cl_assert(counts.wrong_sorted_path == 0); + cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); + cl_assert_equal_i(0, counts.wrong_status_flags_count); + cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is equivalent to t18-status.c:statuscb1 */ @@ -97,7 +58,7 @@ void test_status_worktree__empty_repository(void) cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); - cl_assert(count == 0); + cl_assert_equal_i(0, count); } static int remove_file_cb(void *data, git_buf *file) @@ -120,7 +81,7 @@ static int remove_file_cb(void *data, git_buf *file) /* this test is equivalent to t18-status.c:statuscb2 */ void test_status_worktree__purged_worktree(void) { - struct status_entry_counts counts; + status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_buf workdir = GIT_BUF_INIT; @@ -130,7 +91,7 @@ void test_status_worktree__purged_worktree(void) git_buf_free(&workdir); /* now get status */ - memset(&counts, 0x0, sizeof(struct status_entry_counts)); + memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count2; counts.expected_paths = entry_paths2; counts.expected_statuses = entry_statuses2; @@ -139,15 +100,15 @@ void test_status_worktree__purged_worktree(void) git_status_foreach(repo, cb_status__normal, &counts) ); - cl_assert(counts.entry_count == counts.expected_entry_count); - cl_assert(counts.wrong_status_flags_count == 0); - cl_assert(counts.wrong_sorted_path == 0); + cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); + cl_assert_equal_i(0, counts.wrong_status_flags_count); + cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is similar to t18-status.c:statuscb3 */ void test_status_worktree__swap_subdir_and_file(void) { - struct status_entry_counts counts; + status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_status_options opts; @@ -161,7 +122,7 @@ void test_status_worktree__swap_subdir_and_file(void) cl_git_mkfile("status/README.md", "dummy"); /* now get status */ - memset(&counts, 0x0, sizeof(struct status_entry_counts)); + memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count3; counts.expected_paths = entry_paths3; counts.expected_statuses = entry_statuses3; @@ -174,15 +135,14 @@ void test_status_worktree__swap_subdir_and_file(void) git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) ); - cl_assert(counts.entry_count == counts.expected_entry_count); - cl_assert(counts.wrong_status_flags_count == 0); - cl_assert(counts.wrong_sorted_path == 0); - + cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); + cl_assert_equal_i(0, counts.wrong_status_flags_count); + cl_assert_equal_i(0, counts.wrong_sorted_path); } void test_status_worktree__swap_subdir_with_recurse_and_pathspec(void) { - struct status_entry_counts counts; + status_entry_counts counts; git_repository *repo = cl_git_sandbox_init("status"); git_status_options opts; @@ -196,7 +156,7 @@ void test_status_worktree__swap_subdir_with_recurse_and_pathspec(void) cl_git_mkfile("status/zzz_new_file", "dummy"); /* now get status */ - memset(&counts, 0x0, sizeof(struct status_entry_counts)); + memset(&counts, 0x0, sizeof(status_entry_counts)); counts.expected_entry_count = entry_count4; counts.expected_paths = entry_paths4; counts.expected_statuses = entry_statuses4; @@ -210,9 +170,9 @@ void test_status_worktree__swap_subdir_with_recurse_and_pathspec(void) git_status_foreach_ext(repo, &opts, cb_status__normal, &counts) ); - cl_assert(counts.entry_count == counts.expected_entry_count); - cl_assert(counts.wrong_status_flags_count == 0); - cl_assert(counts.wrong_sorted_path == 0); + cl_assert_equal_i(counts.expected_entry_count, counts.entry_count); + cl_assert_equal_i(0, counts.wrong_status_flags_count); + cl_assert_equal_i(0, counts.wrong_sorted_path); } /* this test is equivalent to t18-status.c:singlestatus0 */ @@ -286,18 +246,18 @@ void test_status_worktree__ignores(void) for (i = 0; i < (int)entry_count0; i++) { cl_git_pass( - git_status_should_ignore(repo, entry_paths0[i], &ignored) + git_status_should_ignore(&ignored, repo, entry_paths0[i]) ); cl_assert(ignored == (entry_statuses0[i] == GIT_STATUS_IGNORED)); } cl_git_pass( - git_status_should_ignore(repo, "nonexistent_file", &ignored) + git_status_should_ignore(&ignored, repo, "nonexistent_file") ); cl_assert(!ignored); cl_git_pass( - git_status_should_ignore(repo, "ignored_nonexistent_file", &ignored) + git_status_should_ignore(&ignored, repo, "ignored_nonexistent_file") ); cl_assert(ignored); } @@ -386,6 +346,65 @@ void test_status_worktree__issue_592_5(void) git_buf_free(&path); } +void test_status_worktree__issue_592_ignores_0(void) +{ + int count = 0; + status_entry_single st; + git_repository *repo = cl_git_sandbox_init("issue_592"); + + cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); + cl_assert_equal_i(0, count); + + cl_git_rewritefile("issue_592/.gitignore", + ".gitignore\n*.txt\nc/\n[tT]*/\n"); + + cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); + cl_assert_equal_i(1, count); + + /* This is a situation where the behavior of libgit2 is + * different from core git. Core git will show ignored.txt + * in the list of ignored files, even though the directory + * "t" is ignored and the file is untracked because we have + * the explicit "*.txt" ignore rule. Libgit2 just excludes + * all untracked files that are contained within ignored + * directories without explicitly listing them. + */ + cl_git_rewritefile("issue_592/t/ignored.txt", "ping"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); + cl_assert_equal_i(1, st.count); + cl_assert(st.status == GIT_STATUS_IGNORED); + + cl_git_rewritefile("issue_592/c/ignored_by_dir", "ping"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); + cl_assert_equal_i(1, st.count); + cl_assert(st.status == GIT_STATUS_IGNORED); + + cl_git_rewritefile("issue_592/t/ignored_by_dir_pattern", "ping"); + + memset(&st, 0, sizeof(st)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &st)); + cl_assert_equal_i(1, st.count); + cl_assert(st.status == GIT_STATUS_IGNORED); +} + +void test_status_worktree__issue_592_ignored_dirs_with_tracked_content(void) +{ + int count = 0; + git_repository *repo = cl_git_sandbox_init("issue_592b"); + + cl_git_pass(git_status_foreach(repo, cb_status__count, &count)); + cl_assert_equal_i(1, count); + + /* if we are really mimicking core git, then only ignored1.txt + * at the top level will show up in the ignores list here. + * everything else will be unmodified or skipped completely. + */ +} + void test_status_worktree__cannot_retrieve_the_status_of_a_bare_repository(void) { git_repository *repo; @@ -402,24 +421,6 @@ void test_status_worktree__cannot_retrieve_the_status_of_a_bare_repository(void) git_repository_free(repo); } -typedef struct { - int count; - unsigned int status; -} status_entry_single; - -static int -cb_status__single(const char *p, unsigned int s, void *payload) -{ - status_entry_single *data = (status_entry_single *)payload; - - GIT_UNUSED(p); - - data->count++; - data->status = s; - - return 0; -} - void test_status_worktree__first_commit_in_progress(void) { git_repository *repo; @@ -431,7 +432,7 @@ void test_status_worktree__first_commit_in_progress(void) memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); - cl_assert(result.count == 1); + cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_WT_NEW); cl_git_pass(git_repository_index(&index, repo)); @@ -440,9 +441,143 @@ void test_status_worktree__first_commit_in_progress(void) memset(&result, 0, sizeof(result)); cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); - cl_assert(result.count == 1); + cl_assert_equal_i(1, result.count); cl_assert(result.status == GIT_STATUS_INDEX_NEW); git_index_free(index); git_repository_free(repo); } + + + +void test_status_worktree__status_file_without_index_or_workdir(void) +{ + git_repository *repo; + unsigned int status = 0; + git_index *index; + + cl_git_pass(p_mkdir("wd", 0777)); + + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_set_workdir(repo, "wd")); + + cl_git_pass(git_index_open(&index, "empty-index")); + cl_assert_equal_i(0, git_index_entrycount(index)); + git_repository_set_index(repo, index); + + cl_git_pass(git_status_file(&status, repo, "branch_file.txt")); + + cl_assert_equal_i(GIT_STATUS_INDEX_DELETED, status); + + git_repository_free(repo); + git_index_free(index); + cl_git_pass(p_rmdir("wd")); +} + +static void fill_index_wth_head_entries(git_repository *repo, git_index *index) +{ + git_oid oid; + git_commit *commit; + git_tree *tree; + + cl_git_pass(git_reference_name_to_oid(&oid, repo, "HEAD")); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + cl_git_pass(git_commit_tree(&tree, commit)); + + cl_git_pass(git_index_read_tree(index, tree)); + cl_git_pass(git_index_write(index)); + + git_tree_free(tree); + git_commit_free(commit); +} + +void test_status_worktree__status_file_with_clean_index_and_empty_workdir(void) +{ + git_repository *repo; + unsigned int status = 0; + git_index *index; + + cl_git_pass(p_mkdir("wd", 0777)); + + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_repository_set_workdir(repo, "wd")); + + cl_git_pass(git_index_open(&index, "my-index")); + fill_index_wth_head_entries(repo, index); + + git_repository_set_index(repo, index); + + cl_git_pass(git_status_file(&status, repo, "branch_file.txt")); + + cl_assert_equal_i(GIT_STATUS_WT_DELETED, status); + + git_repository_free(repo); + git_index_free(index); + cl_git_pass(p_rmdir("wd")); + cl_git_pass(p_unlink("my-index")); +} + + +void test_status_worktree__space_in_filename(void) +{ + git_repository *repo; + git_index *index; + status_entry_single result; + unsigned int status_flags; + +#define FILE_WITH_SPACE "LICENSE - copy.md" + + cl_git_pass(git_repository_init(&repo, "with_space", 0)); + cl_git_mkfile("with_space/" FILE_WITH_SPACE, "I have a space in my name\n"); + + /* file is new to working directory */ + + memset(&result, 0, sizeof(result)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); + cl_assert_equal_i(1, result.count); + cl_assert(result.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); + cl_assert(status_flags == GIT_STATUS_WT_NEW); + + /* ignore the file */ + + cl_git_rewritefile("with_space/.gitignore", "*.md\n.gitignore\n"); + + memset(&result, 0, sizeof(result)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); + cl_assert_equal_i(2, result.count); + cl_assert(result.status == GIT_STATUS_IGNORED); + + cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); + cl_assert(status_flags == GIT_STATUS_IGNORED); + + /* don't ignore the file */ + + cl_git_rewritefile("with_space/.gitignore", ".gitignore\n"); + + memset(&result, 0, sizeof(result)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); + cl_assert_equal_i(2, result.count); + cl_assert(result.status == GIT_STATUS_WT_NEW); + + cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); + cl_assert(status_flags == GIT_STATUS_WT_NEW); + + /* add the file to the index */ + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_add(index, FILE_WITH_SPACE, 0)); + cl_git_pass(git_index_write(index)); + + memset(&result, 0, sizeof(result)); + cl_git_pass(git_status_foreach(repo, cb_status__single, &result)); + cl_assert_equal_i(2, result.count); + cl_assert(result.status == GIT_STATUS_INDEX_NEW); + + cl_git_pass(git_status_file(&status_flags, repo, FILE_WITH_SPACE)); + cl_assert(status_flags == GIT_STATUS_INDEX_NEW); + + git_index_free(index); + git_repository_free(repo); +}