From bad1505609068de0d57cba1584590e9084afe9d6 Mon Sep 17 00:00:00 2001 From: "U-Poseidon\\Chris" Date: Tue, 5 Jun 2012 11:41:43 +0100 Subject: [PATCH 001/123] Force not to use openssl, as confusing cross-compiler t to use openssl, as confusing cross-compiler t to use openssl, as confusing cross-compiler ss Changes to be committed: (use "git reset HEAD ..." to unstage) modified: CMakeLists.txt --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acac2a6de..567ac10e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,8 @@ # Install: # > cmake --build . --target install +SET(CMAKE_SYSTEM_NAME "Generic") + PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) @@ -25,7 +27,7 @@ SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${ INCLUDE_DIRECTORIES(deps/zlib src include) # Try finding openssl -FIND_PACKAGE(OpenSSL) +#FIND_PACKAGE(OpenSSL) IF (OPENSSL_CRYPTO_LIBRARIES) SET(SHA1_TYPE "openssl" CACHE STRING "Which SHA1 implementation to use: builtin, ppc, openssl") ELSEIF () From d0517805d84f0fdd6c1311eb00a0d4ff257b4e47 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Tue, 5 Jun 2012 11:47:17 +0100 Subject: [PATCH 002/123] Required include for OS4 to typedef int64_t --- include/git2/types.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/git2/types.h b/include/git2/types.h index b569e83c1..8fdfd7fc8 100644 --- a/include/git2/types.h +++ b/include/git2/types.h @@ -48,6 +48,9 @@ GIT_BEGIN_DECL * stat() functions, for all platforms. */ #include +#ifdef __amigaos4__ +#include +#endif #if defined(_MSC_VER) From 82c23c58708acd1370a129f712207ce60e7e6199 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Tue, 5 Jun 2012 12:06:40 +0100 Subject: [PATCH 003/123] Assume this is irrelevant for now --- src/unix/map.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/unix/map.c b/src/unix/map.c index 9bc6178ed..1613152a0 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -1,11 +1,14 @@ #include "map.h" +#ifndef __amigaos4__ #include +#endif #include int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { +#ifndef __amigaos4__ int mprot = 0; int mflag = 0; @@ -42,19 +45,20 @@ int git__mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t o if (!out->data || out->data == MAP_FAILED) return git__throw(GIT_EOSERR, "Failed to mmap. Could not write data"); out->len = len; - +#endif return GIT_SUCCESS; } int git__munmap(git_map *map) { +#ifndef __amigaos4__ assert(map != NULL); if (!map) return git__throw(GIT_ERROR, "Failed to munmap. Map does not exist"); munmap(map->data, map->len); - +#endif return GIT_SUCCESS; } From cada414a8044307b28f7a4c75986e5473bb4bc1c Mon Sep 17 00:00:00 2001 From: Chris Young Date: Tue, 5 Jun 2012 12:07:08 +0100 Subject: [PATCH 004/123] OS4 is PPC --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 567ac10e9..93747bb64 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,7 +31,7 @@ INCLUDE_DIRECTORIES(deps/zlib src include) IF (OPENSSL_CRYPTO_LIBRARIES) SET(SHA1_TYPE "openssl" CACHE STRING "Which SHA1 implementation to use: builtin, ppc, openssl") ELSEIF () - SET(SHA1_TYPE "builtin" CACHE STRING "Which SHA1 implementation to use: builtin, ppc") + SET(SHA1_TYPE "ppc" CACHE STRING "Which SHA1 implementation to use: builtin, ppc") ENDIF () INCLUDE(FindPkgConfig) From fb0b1523c40e843fd3bdae539e7382acd4a5c06b Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 20:40:03 +0100 Subject: [PATCH 005/123] force disable of openssl, confusing cross-compiler --- CMakeLists.txt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9bff1ba0a..d3ab19ce3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -91,12 +91,12 @@ IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF () -FIND_PACKAGE(OpenSSL) -IF (OPENSSL_FOUND) - ADD_DEFINITIONS(-DGIT_SSL) - INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) -ENDIF() +#FIND_PACKAGE(OpenSSL) +#IF (OPENSSL_FOUND) +# ADD_DEFINITIONS(-DGIT_SSL) +# INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) +# SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) +#ENDIF() IF (THREADSAFE) IF (NOT WIN32) From 2774ccb8515354c2c6b9e9e4da09115ca44ecbd5 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 20:40:34 +0100 Subject: [PATCH 006/123] no fnmatch.h --- src/unix/posix.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/unix/posix.h b/src/unix/posix.h index 48b492941..83fd8a189 100644 --- a/src/unix/posix.h +++ b/src/unix/posix.h @@ -7,7 +7,7 @@ #ifndef INCLUDE_posix__w32_h__ #define INCLUDE_posix__w32_h__ -#ifndef __sun +#if !defined(__sun) && !defined(__amigaos4__) # include # define p_fnmatch(p, s, f) fnmatch(p, s, f) #else From c41fc47512ed78697122de7a2b628676e3e08726 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 21:26:39 +0100 Subject: [PATCH 007/123] horrid gethostbyname compatibility --- src/netops.c | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/src/netops.c b/src/netops.c index e6f3e5627..fdbd965b1 100644 --- a/src/netops.c +++ b/src/netops.c @@ -376,11 +376,17 @@ static int ssl_setup(git_transport *t, const char *host) int gitno_connect(git_transport *t, const char *host, const char *port) { +#ifndef __amigaos4__ struct addrinfo *info = NULL, *p; struct addrinfo hints; +#else + int p; + struct hostent *hent; + struct sockaddr_in saddr; +#endif int ret; GIT_SOCKET s = INVALID_SOCKET; - +#ifndef __amigaos4__ memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -389,15 +395,29 @@ int gitno_connect(git_transport *t, const char *host, const char *port) giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret)); return -1; } +#else + hent = gethostbyname(host); +#endif +#ifndef __amigaos4__ for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); +#else + for (p = 0; hent->h_addr_list[p] != NULL; p++) { + s = socket(hent->h_addrtype, SOCK_STREAM, 0); +#endif if (s == INVALID_SOCKET) { net_set_error("error creating socket"); break; } - +#ifndef __amigaos4__ if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) +#else + saddr.sin_addr.s_addr = *hent->h_addr_list[p]; + saddr.sin_family = hent->h_addrtype; + saddr.sin_port = port; + if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == 0) +#endif break; /* If we can't connect, try the next one */ @@ -406,14 +426,20 @@ int gitno_connect(git_transport *t, const char *host, const char *port) } /* Oops, we couldn't connect to any address */ - if (s == INVALID_SOCKET && p == NULL) { + if (s == INVALID_SOCKET && +#ifndef __amigaos4__ + p == NULL) { +#else + hent->h_addr_list[p] == NULL) { +#endif giterr_set(GITERR_OS, "Failed to connect to %s", host); return -1; } t->socket = s; +#ifndef __amigaos4__ freeaddrinfo(info); - +#endif if (t->encrypt && ssl_setup(t, host) < 0) return -1; From 6b5db63c159ea1d2112fe8dc535b877da03a6848 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 21:40:07 +0100 Subject: [PATCH 008/123] random page size for os4 --- src/pool.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/pool.c b/src/pool.c index 641292d06..c5414b3b6 100644 --- a/src/pool.c +++ b/src/pool.c @@ -275,6 +275,8 @@ uint32_t git_pool__system_page_size(void) SYSTEM_INFO info; GetSystemInfo(&info); size = (uint32_t)info.dwPageSize; +#elif defined(__amigaos4__) + size = (uint32_t)1000000; // random value #else size = (uint32_t)sysconf(_SC_PAGE_SIZE); #endif From 0f5e1f3b68eb68c257eb45b72650e8a653451a1d Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 21:56:19 +0100 Subject: [PATCH 009/123] Network byte order is big-endian - the way it should be :) --- include/git2/common.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/git2/common.h b/include/git2/common.h index 0e9379804..4e6c2a57e 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -55,6 +55,14 @@ #define GIT_WIN32 1 #endif +#ifdef __amigaos4__ +/* Network byte order is big-endian... so is PPC, so these functions are NOP */ +#define htonl(x) x +#define ntohl(x) x +#define htons(x) x +#define ntohs(x) x +#endif + /** * @file git2/common.h * @brief Git common platform definitions From 519757279eb25fe4075f65b86da5ce52d352b454 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 7 Jun 2012 23:13:39 +0100 Subject: [PATCH 010/123] Fix double-defines when using GIT_OLD_ERRORS --- include/git2/errors.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index ccbc9fcf4..b4809fe15 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -20,6 +20,7 @@ GIT_BEGIN_DECL #ifdef GIT_OLD_ERRORS enum { GIT_SUCCESS = 0, + GIT_ERROR = -1, GIT_ENOTOID = -2, GIT_ENOTFOUND = -3, GIT_ENOMEM = -4, @@ -52,7 +53,7 @@ enum { GIT_ENOMATCH = -31, GIT_ESHORTBUFFER = -32, }; -#endif +#else /** Generic return codes */ enum { @@ -66,6 +67,7 @@ enum { GIT_PASSTHROUGH = -30, GIT_REVWALKOVER = -31, }; +#endif typedef struct { char *message; From aa5a92d121d4fcc56d9661ce1c76534b410784c7 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 8 Jun 2012 18:57:35 +0100 Subject: [PATCH 011/123] OS4 compatibility --- include/git2/common.h | 2 ++ src/path.c | 4 ++-- src/posix.h | 6 +++++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 4e6c2a57e..b692c67e2 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -107,6 +107,8 @@ GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src); */ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev); +GIT_EXTERN(int) p_fnmatch(const char *pattern, const char *string, int flags); + /** @} */ GIT_END_DECL #endif diff --git a/src/path.c b/src/path.c index 84edf6d89..056b6b910 100644 --- a/src/path.c +++ b/src/path.c @@ -512,7 +512,7 @@ int git_path_direach( de_buf = git__malloc(sizeof(struct dirent)); #endif - while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { + while (p_readdir_r(dir, de_buf, de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) @@ -570,7 +570,7 @@ int git_path_dirload( 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; diff --git a/src/posix.h b/src/posix.h index d020d94ac..8e8b394c8 100644 --- a/src/posix.h +++ b/src/posix.h @@ -74,6 +74,10 @@ typedef SOCKET GIT_SOCKET; # include "unix/posix.h" #endif -#define p_readdir_r(d,e,r) readdir_r(d,e,r) +#ifndef __amigaos4__ +#define p_readdir_r(d,e,r) readdir_r(d,e,&r) +#else +#define p_readdir_r(d,e,r) r = readdir(d) +#endif #endif From fa56478fb8d5e19d64bf43b51372ab3315cb1884 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 8 Jun 2012 19:15:11 +0100 Subject: [PATCH 012/123] Generic needs compat files --- CMakeLists.txt | 2 +- include/git2/common.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d3ab19ce3..7d3df285e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ FILE(GLOB SRC_H include/git2/*.h) 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 src/compat/*.c) -ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") +ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS|Generic)") 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) diff --git a/include/git2/common.h b/include/git2/common.h index b692c67e2..045ba85c4 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -107,7 +107,7 @@ GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src); */ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev); -GIT_EXTERN(int) p_fnmatch(const char *pattern, const char *string, int flags); +/* GIT_EXTERN(int) p_fnmatch(const char *pattern, const char *string, int flags); */ /** @} */ GIT_END_DECL From c3f7a9386d1f244a5442a1be484e1093b1698a02 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 8 Jun 2012 19:37:24 +0100 Subject: [PATCH 013/123] Re-add the ability to select the PowerPC SHA1 function --- CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d3df285e..c6254efda 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,11 +23,22 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") +# Comment out the line below to use OpenSSL SHA1 +SET(SHA1_TYPE "ppc") + # Find required dependencies INCLUDE_DIRECTORIES(src include deps/http-parser) FILE(GLOB SRC_HTTP deps/http-parser/*.c) +# Specify sha1 implementation +IF (SHA1_TYPE STREQUAL "ppc") + ADD_DEFINITIONS(-DPPC_SHA1) + FILE(GLOB SRC_SHA1 src/ppc/*.c) +ELSE () + SET (SRC_SHA1) +ENDIF() + IF (NOT WIN32) FIND_PACKAGE(ZLIB) ELSE() @@ -122,7 +133,7 @@ ELSE() ENDIF () # Compile and link libgit2 -ADD_LIBRARY(git2 ${SRC} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${WIN_RC}) +ADD_LIBRARY(git2 ${SRC} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) IF (WIN32) TARGET_LINK_LIBRARIES(git2 ws2_32) From 4c650c2b80d1b38759f0e7b6a782ed88d78648d5 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Fri, 8 Jun 2012 19:55:04 +0100 Subject: [PATCH 014/123] Don't use the PPC native SHA1 :( CMake is refusing to acknowledge the sha1ppc.S ppc asm code. --- CMakeLists.txt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6254efda..041553fd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,8 +23,8 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") -# Comment out the line below to use OpenSSL SHA1 -SET(SHA1_TYPE "ppc") +# Uncomment out the line below to use PowerPC SHA1 +#SET(SHA1_TYPE "ppc") # Find required dependencies INCLUDE_DIRECTORIES(src include deps/http-parser) @@ -34,7 +34,7 @@ FILE(GLOB SRC_HTTP deps/http-parser/*.c) # Specify sha1 implementation IF (SHA1_TYPE STREQUAL "ppc") ADD_DEFINITIONS(-DPPC_SHA1) - FILE(GLOB SRC_SHA1 src/ppc/*.c) + FILE(GLOB SRC_SHA1 src/ppc/*.c src/ppc/*.S) ELSE () SET (SRC_SHA1) ENDIF() From bb502fa803605bcfce08da5467e52813eff4d38d Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 12:52:49 +0100 Subject: [PATCH 015/123] Fix makefile --- examples/network/Makefile | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/examples/network/Makefile b/examples/network/Makefile index c21869ac9..0cffe855b 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -1,8 +1,9 @@ default: all -CC = gcc +CC = ppc-amigaos-gcc CFLAGS += -g -CFLAGS += -I../../include -L../../ -lgit2 -lpthread +CFLAGS += -I../../include -L../../build +LIBS += -lgit2 -lpthread -lregex OBJECTS = \ git2.o \ @@ -11,4 +12,4 @@ OBJECTS = \ index-pack.o all: $(OBJECTS) - $(CC) $(CFLAGS) -o git2 $(OBJECTS) + $(CC) $(CFLAGS) -o git2 $(OBJECTS) $(LIBS) From 5c0fd7b976b8fb1271dbe61b9ea456672ab5b370 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 13:20:07 +0100 Subject: [PATCH 016/123] allow disabling pthreads for testing --- examples/network/fetch.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index 8dcb81b1f..fc4e94cfd 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -36,7 +36,9 @@ static void *download(void *ptr) exit: data->finished = 1; +#ifndef NO_PTHREADS pthread_exit(&data->ret); +#endif } int update_cb(const char *refname, const git_oid *a, const git_oid *b) @@ -81,6 +83,9 @@ int fetch(git_repository *repo, int argc, char **argv) data.finished = 0; memset(&stats, 0, sizeof(stats)); +#ifdef NO_PTHREADS + download(&data); +#else pthread_create(&worker, NULL, download, &data); // Loop while the worker thread is still running. Here we show processed @@ -91,6 +96,7 @@ int fetch(git_repository *repo, int argc, char **argv) usleep(10000); printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes); } while (!data.finished); +#endif printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes); // Disconnect the underlying connection to prevent from idling. From b9bfc7684b94bf052203034cbddfdf01e26205e5 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 17:33:08 +0100 Subject: [PATCH 017/123] pre-compiled sha1ppc.S.obj file with nasty CMake hack instructions as the cross-compile process refuses to build and link this file itself. --- CMakeLists.txt | 2 +- README.amiga | 4 ++++ src/ppc/sha1ppc.S.obj | Bin 0 -> 4471 bytes 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100755 README.amiga create mode 100644 src/ppc/sha1ppc.S.obj diff --git a/CMakeLists.txt b/CMakeLists.txt index 041553fd0..d245109bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") # Uncomment out the line below to use PowerPC SHA1 -#SET(SHA1_TYPE "ppc") +SET(SHA1_TYPE "ppc") # Find required dependencies INCLUDE_DIRECTORIES(src include deps/http-parser) diff --git a/README.amiga b/README.amiga new file mode 100755 index 000000000..97414dda2 --- /dev/null +++ b/README.amiga @@ -0,0 +1,4 @@ +Nasty build hack: +When setting SHA1 to ppc in CMakeLists.txt, after running initial CMake, +copy src/ppc/sha1ppc.S.obj to build/CMakeFiles/git2.dir/src/ppc/ +Add CMakeFiles/git2.dir/src/ppc/sha1ppc.S.obj to the list in build/CMakeFiles/git2.dir/link.txt diff --git a/src/ppc/sha1ppc.S.obj b/src/ppc/sha1ppc.S.obj new file mode 100644 index 0000000000000000000000000000000000000000..a7dad600fee80b062086f352aa62b87b1755e7ac GIT binary patch literal 4471 zcma)=L1-M;8ONU$(Qct&8Rnpp9Aq%mD}s?i3S(o;Vv-_;QdAMGL6_KT2aHUUAn7o1 zXLc*qml#7q=u*>zBjVBu48h<-)P|}eY(WPfL{TX%LD0}W|Nrm%wuyRZ z1*>@)y*E3*|NDOP-fr*JAN}yy$gwp1IhHcCzjk8G{`ImBr_;C7=*Gz}KltdqH2V9i zDOJCF?l-H~QaXQcVXgPCFUr+hX|(s}&&%F#KPy+?PmRm>-}zPV-G7#=AE)p37XMyW z{e`SLoGI($GkMh?$>v+9FU&WeUa0yvvnowytDmMZp05U-tWL9KJvEzGgOTjD9rP>E zZ?L9*YoiH$MzXrGnAHyl$Z1;pq#n^`Bm-8@H|BsWi^>b#p1JTX|XS=Xu@4 z`zG`opkH&{`n{4~;Q6}1eeAT#>ho4!7w9*E_idnGao74?OA|a_^>H8M$c}PsTEAQA zlyTfPjvpN5*s^}_r_;u33<$~bTzDJ?nQWX`ZUVL*qDilw;rey^_uw$95);8@r|Mw*{UXch%{iGw4nuL(iZ+jWNn#Nf~tK$ciz@pgU)IFoW(KGDHUF@4fjq=FpzQ zIP|-G|Fiex+hI|5myNkf7tyv{m_>Ja%W^>$?PYSUA&0rLyJ5Ul!q^SVggJCKkR#Zc zLwkcvsQZbR%I+g$tvL3P<)I87ZCg#C4%&~%gZgisE4v5AStX1;uq?!Xfc(JB8fYJo z13vEHo}U?Gl`!_1@?KgXFFXNnO;0ed9=anbLu6X4L=9Ij0gp8PLIpVx@r0Va9mwp5<{Rm$Ap*CwBepG{f@yZS7l^f10 zH=LJl)D3t6-Wpy6FTDs}dZ9KwhZl7dPH=wdg!9S?=amyNzjUHlwE3kE&MP0BS3Wo| zeW?0yf%Oa*f|o7?FI@;;dQc5+T0OJ=omchmysCfaW&PI;)IWGx|G~@p4_?-P@T&fs zsDJXZ{)3nGAH1yp;AQ<6>&DCam$ScoUNubzf|(8kGaR^l{}2DD`taazCZ`AFQwH$B zGQjfy9z+Ihd4PK1dOO$z|7xd1U8Vm=72Sx9bMHn3&4x1$kBT@WL{| z_25NhVqT#BxgIy+M=Q_e2e_Gy{7^Qy9{uoa%nx(DF0iicw6KO4JDry&s)-!uk*Vin zp5Q+5tgHI)1-a0d$c4T{F7zdGF<&B=J>?>AJQsQ6xyT#O#k`4J;16=4KamUliCpMU zo{RkQT;!MMVtz#~@C>!^`A{X;4a#>R@^38LRZ=Q>M z^IXig$mO=>Lhm9MdKbCSyU0b};XYL_@Q=B`zhN$LZ zXQ~B^<$C3{AkUmv`?x;*0x$gvUanWcOTU7bepQ1-@yaXbl~>Lyubfx=w+4Iyul8=v ztG%1^YVYQ}+P5{~5qRa1^U5RVl}FAikBT*WCUCuSUiss^^2d4UPt}Jv>rz!+GV0 z^U9B6OT6;JdF6%k$_wYE7gZlVfR{c5FMSAJx)8i{A-|Pc)nHr9^f#D;m&dw+ng^qO z{-h&wLq4+AP1HD;>~kmok9v0=xm@gvfzP9uvtfPW-g{rZl=VJ2m-RlnnDu^LWWArw zWf#-aTYtpo@DK5MJU^LcfBf?_kCCk&D_7E)&hql` zWB>orcpiQDy}-A;FTN2te$U%H#CHZKz5Sg1@AzNrIQ$*`zK=5vy#80e6aVSMYv_6} zvgJQ Date: Sat, 9 Jun 2012 18:13:07 +0100 Subject: [PATCH 018/123] Fix gethostbyname compatibility --- include/git2/common.h | 6 +----- src/netops.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/include/git2/common.h b/include/git2/common.h index 045ba85c4..99018d4f5 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -56,11 +56,7 @@ #endif #ifdef __amigaos4__ -/* Network byte order is big-endian... so is PPC, so these functions are NOP */ -#define htonl(x) x -#define ntohl(x) x -#define htons(x) x -#define ntohs(x) x +#include #endif /** diff --git a/src/netops.c b/src/netops.c index fdbd965b1..6808c8ee7 100644 --- a/src/netops.c +++ b/src/netops.c @@ -382,7 +382,9 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #else int p; struct hostent *hent; + struct servent *sent; struct sockaddr_in saddr; + long port_num = 0; #endif int ret; GIT_SOCKET s = INVALID_SOCKET; @@ -397,6 +399,12 @@ int gitno_connect(git_transport *t, const char *host, const char *port) } #else hent = gethostbyname(host); + sent = getservbyname(port, 0); + + if(sent) + port_num = sent->s_port; + else + port_num = atol(port); #endif #ifndef __amigaos4__ @@ -413,9 +421,9 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #ifndef __amigaos4__ if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) #else - saddr.sin_addr.s_addr = *hent->h_addr_list[p]; + memcpy(&saddr.sin_addr, hent->h_addr_list[p], hent->h_length); saddr.sin_family = hent->h_addrtype; - saddr.sin_port = port; + saddr.sin_port = port_num; if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == 0) #endif break; From 7d1983ebc2312c526057ecedd4cef628a4c33974 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 18:58:11 +0100 Subject: [PATCH 019/123] stop readdir parsing crashing --- src/path.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/path.c b/src/path.c index 056b6b910..eb9bc06f3 100644 --- a/src/path.c +++ b/src/path.c @@ -482,9 +482,14 @@ int git_path_cmp( /* Taken from git.git */ GIT_INLINE(int) is_dot_or_dotdot(const char *name) { +#ifdef __amigaos4__ + /* This is irrelevant on AmigaOS */ + return 0; +#else return (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))); +#endif } int git_path_direach( @@ -512,7 +517,11 @@ int git_path_direach( de_buf = git__malloc(sizeof(struct dirent)); #endif +#ifdef __amigaos4__ + while (de = readdir(dir)) { +#else while (p_readdir_r(dir, de_buf, de) == 0 && de != NULL) { +#endif int result; if (is_dot_or_dotdot(de->d_name)) From 41cbbea8fe0aa56dc33027ba24249f69d831fe03 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 23:03:27 +0100 Subject: [PATCH 020/123] Let platform 'Generic' get the regex deps so we don't need to use our external ones --- CMakeLists.txt | 23 +++++++++++++++-------- examples/network/Makefile | 4 ++-- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 041553fd0..2591fccbf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -41,6 +41,10 @@ ENDIF() IF (NOT WIN32) FIND_PACKAGE(ZLIB) + IF (CMAKE_SYSTEM_NAME MATCHES "Generic") + INCLUDE_DIRECTORIES(deps/regex) + SET(SRC_REGEX deps/regex/regex.c) + ENDIF() ELSE() # Windows doesn't understand POSIX regex on its own INCLUDE_DIRECTORIES(deps/regex) @@ -54,7 +58,7 @@ ELSE (ZLIB_FOUND) INCLUDE_DIRECTORIES(deps/zlib) ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP) FILE(GLOB SRC_ZLIB deps/zlib/*.c) -ENDIF() +#ENDIF() # Installation paths SET(INSTALL_BIN bin CACHE PATH "Where to install binaries to.") @@ -62,7 +66,7 @@ SET(INSTALL_LIB lib CACHE PATH "Where to install libraries to.") SET(INSTALL_INC include CACHE PATH "Where to install headers to.") # Build options -OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" ON) +OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" OFF) 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) @@ -102,12 +106,15 @@ IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF () -#FIND_PACKAGE(OpenSSL) -#IF (OPENSSL_FOUND) -# ADD_DEFINITIONS(-DGIT_SSL) -# INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) -# SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) -#ENDIF() +IF (CMAKE_SYSTEM_NAME MATCHES "Generic") +ELSE () + FIND_PACKAGE(OpenSSL) + IF (OPENSSL_FOUND) + ADD_DEFINITIONS(-DGIT_SSL) + INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) + SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) + ENDIF() +ENDIF() IF (THREADSAFE) IF (NOT WIN32) diff --git a/examples/network/Makefile b/examples/network/Makefile index 0cffe855b..708a6b1b3 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -1,9 +1,9 @@ default: all -CC = ppc-amigaos-gcc +CC = gcc CFLAGS += -g CFLAGS += -I../../include -L../../build -LIBS += -lgit2 -lpthread -lregex +LIBS += -lgit2 -lpthread #-lregex OBJECTS = \ git2.o \ From c9f79972baefb00e3c86a96e7a448c124bde7693 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sat, 9 Jun 2012 23:13:21 +0100 Subject: [PATCH 021/123] remove errorneous comment --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e52c74b9..969a5e682 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,7 +58,7 @@ ELSE (ZLIB_FOUND) INCLUDE_DIRECTORIES(deps/zlib) ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP) FILE(GLOB SRC_ZLIB deps/zlib/*.c) -#ENDIF() +ENDIF() # Installation paths SET(INSTALL_BIN bin CACHE PATH "Where to install binaries to.") From 90490113af9cef092b36c5ee0231c11675ed9f51 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Sun, 10 Jun 2012 18:08:15 +0100 Subject: [PATCH 022/123] Basic mmap/munmap compatiblity --- src/map.h | 4 ++++ src/pack.c | 4 ++-- src/unix/map.c | 19 ++++++++++++++++--- 3 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/map.h b/src/map.h index 96d879547..6ce6d3685 100644 --- a/src/map.h +++ b/src/map.h @@ -23,6 +23,10 @@ #define GIT_MAP_TYPE 0xf #define GIT_MAP_FIXED 0x10 +#ifdef __amigaos4__ +#define MAP_FAILED 0 +#endif + typedef struct { /* memory mapped buffer */ void *data; /* data bytes */ size_t len; /* data length */ diff --git a/src/pack.c b/src/pack.c index 0db1069de..85bc6707e 100644 --- a/src/pack.c +++ b/src/pack.c @@ -215,7 +215,7 @@ static int packfile_unpack_header1( unsigned shift; unsigned long size, c; unsigned long used = 0; - +printf("[pack 218] buf = %lx, used = %ld, len = %ld\n", buf, used, len); c = buf[used++]; *type = (c >> 4) & 7; size = c & 15; @@ -261,7 +261,7 @@ int git_packfile_unpack_header( base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) return GIT_EBUFS; - +printf("[pack 264] base = %lx, mwf = %lx\n", base, mwf); ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); if (ret == GIT_EBUFS) diff --git a/src/unix/map.c b/src/unix/map.c index 65f4ac91c..8e853b9be 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -16,7 +16,6 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { -#ifndef __amigaos4__ int mprot = 0; int mflag = 0; @@ -25,6 +24,7 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs out->data = NULL; out->len = 0; +#ifndef __amigaos4__ if (prot & GIT_PROT_WRITE) mprot = PROT_WRITE; else if (prot & GIT_PROT_READ) @@ -36,21 +36,34 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs mflag = MAP_PRIVATE; out->data = mmap(NULL, len, mprot, mflag, fd, offset); +#else + if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { + printf("Trying to map shared-writeable file!!!\n"); + + if(out->data = malloc(len)) { + lseek(fd, offset, SEEK_SET); + p_read(fd, out->data, len); + } + } +#endif + if (!out->data || out->data == MAP_FAILED) { giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); return -1; } out->len = len; -#endif + return 0; } int p_munmap(git_map *map) { -#ifndef __amigaos4__ assert(map != NULL); +#ifndef __amigaos4__ munmap(map->data, map->len); +#else + free(map->data); #endif return 0; } From 2aeadb9c78df4b463ffb3293e242e19a7e0d17a9 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Tue, 12 Jun 2012 19:25:09 +0100 Subject: [PATCH 023/123] Actually do the mmap... unsurprisingly, this makes the indexer work on SFS On RAM: the .idx and .pack files become links to a .lock and the original download respectively. Assume some feature (such as record locking) supported by SFS but not JXFS or RAM: is required. --- src/indexer.c | 2 +- src/mwindow.c | 1 + src/pack.c | 6 +++--- src/unix/map.c | 8 ++++---- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index f0e0a6381..5542bfeba 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -363,11 +363,11 @@ 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_EBUFS) return 0; if (error < 0) return error; - continue; } diff --git a/src/mwindow.c b/src/mwindow.c index 57adabd48..74fbf7834 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -158,6 +158,7 @@ static git_mwindow *new_window( git_mwindow *w; w = git__malloc(sizeof(*w)); + if (w == NULL) return NULL; diff --git a/src/pack.c b/src/pack.c index 85bc6707e..9b5e0e18f 100644 --- a/src/pack.c +++ b/src/pack.c @@ -215,7 +215,7 @@ static int packfile_unpack_header1( unsigned shift; unsigned long size, c; unsigned long used = 0; -printf("[pack 218] buf = %lx, used = %ld, len = %ld\n", buf, used, len); + c = buf[used++]; *type = (c >> 4) & 7; size = c & 15; @@ -261,8 +261,8 @@ int git_packfile_unpack_header( base = git_mwindow_open(mwf, w_curs, *curpos, 20, &left); if (base == NULL) return GIT_EBUFS; -printf("[pack 264] base = %lx, mwf = %lx\n", base, mwf); - ret = packfile_unpack_header1(&used, size_p, type_p, base, left); + + ret = packfile_unpack_header1(&used, size_p, type_p, base, left); git_mwindow_close(w_curs); if (ret == GIT_EBUFS) return ret; diff --git a/src/unix/map.c b/src/unix/map.c index 8e853b9be..b04e95a76 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -39,11 +39,11 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs #else if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { printf("Trying to map shared-writeable file!!!\n"); + } - if(out->data = malloc(len)) { - lseek(fd, offset, SEEK_SET); - p_read(fd, out->data, len); - } + if(out->data = malloc(len)) { + lseek(fd, offset, SEEK_SET); + p_read(fd, out->data, len); } #endif From 96ef3d84629ef72fb662d95abbab3de634921678 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Wed, 13 Jun 2012 23:16:14 +0100 Subject: [PATCH 024/123] Make this more generic and mergeable. Needs AmigaOS.cmake now from CMake package at OS4Depot, or contents below: --8<-- SET(AMIGA 1) SET(CMAKE_SHARED_LIBRARY_C_FLAGS "-fPIC") SET(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-shared") --8<-- --- CMakeLists.txt | 34 ++++++++++++++++--------------- src/amiga/map.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++++ src/netops.c | 12 +++++------ src/path.c | 2 +- src/posix.h | 2 +- src/unix/map.c | 18 +---------------- 6 files changed, 80 insertions(+), 41 deletions(-) create mode 100755 src/amiga/map.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 969a5e682..fdc103e8a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ # Install: # > cmake --build . --target install -SET(CMAKE_SYSTEM_NAME "Generic") +SET(CMAKE_SYSTEM_NAME "AmigaOS") PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) @@ -23,8 +23,10 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") -# Uncomment out the line below to use PowerPC SHA1 -SET(SHA1_TYPE "ppc") +IF (AMIGA) + # Default AmigaOS to use the PowerPC SHA1 + SET(SHA1_TYPE "ppc") +ENDIF() # Find required dependencies INCLUDE_DIRECTORIES(src include deps/http-parser) @@ -33,15 +35,15 @@ FILE(GLOB SRC_HTTP deps/http-parser/*.c) # Specify sha1 implementation IF (SHA1_TYPE STREQUAL "ppc") - ADD_DEFINITIONS(-DPPC_SHA1) - FILE(GLOB SRC_SHA1 src/ppc/*.c src/ppc/*.S) + ADD_DEFINITIONS(-DPPC_SHA1) + FILE(GLOB SRC_SHA1 src/ppc/*.c src/ppc/*.S) ELSE () SET (SRC_SHA1) ENDIF() IF (NOT WIN32) FIND_PACKAGE(ZLIB) - IF (CMAKE_SYSTEM_NAME MATCHES "Generic") + IF (CMAKE_SYSTEM_NAME STREQUAL "AmigaOS") INCLUDE_DIRECTORIES(deps/regex) SET(SRC_REGEX deps/regex/regex.c) ENDIF() @@ -68,7 +70,7 @@ SET(INSTALL_INC include CACHE PATH "Where to install headers to.") # Build options OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" OFF) OPTION (THREADSAFE "Build libgit2 as threadsafe" OFF) -OPTION (BUILD_CLAR "Build Tests using the Clar suite" ON) +OPTION (BUILD_CLAR "Build Tests using the Clar suite" OFF) OPTION (BUILD_EXAMPLES "Build library usage example apps" OFF) OPTION (TAGS "Generate tags" OFF) OPTION (PROFILE "Generate profiling information" OFF) @@ -106,14 +108,11 @@ IF (NOT CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Debug" CACHE STRING "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE) ENDIF () -IF (CMAKE_SYSTEM_NAME MATCHES "Generic") -ELSE () - FIND_PACKAGE(OpenSSL) - IF (OPENSSL_FOUND) - ADD_DEFINITIONS(-DGIT_SSL) - INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) - SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) - ENDIF() +FIND_PACKAGE(OpenSSL) +IF (OPENSSL_FOUND) + ADD_DEFINITIONS(-DGIT_SSL) + INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR}) + SET(SSL_LIBRARIES ${OPENSSL_LIBRARIES}) ENDIF() IF (THREADSAFE) @@ -133,8 +132,11 @@ FILE(GLOB SRC_H include/git2/*.h) 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 src/compat/*.c) -ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS|Generic)") +ELSEIF (CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/unix/*.c src/compat/*.c) +ELSEIF (AMIGA) + ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R) + FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/amiga/*.c src/compat/*.c) ELSE() FILE(GLOB SRC src/*.c src/transports/*.c src/xdiff/*.c src/unix/*.c) ENDIF () diff --git a/src/amiga/map.c b/src/amiga/map.c new file mode 100755 index 000000000..d36bcbc9c --- /dev/null +++ b/src/amiga/map.c @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009-2012 the libgit2 contributors + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ +#include + +#ifndef GIT_WIN32 + +#include "posix.h" +#include "map.h" +#include + +int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) +{ + int mprot = 0; + int mflag = 0; + + GIT_MMAP_VALIDATE(out, len, prot, flags); + + out->data = NULL; + out->len = 0; + + if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { + printf("Trying to map shared-writeable file!!!\n"); + } + + if(out->data = malloc(len)) { + p_lseek(fd, offset, SEEK_SET); + p_read(fd, out->data, len); + } + + if (!out->data || out->data == MAP_FAILED) { + giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); + return -1; + } + + out->len = len; + + return 0; +} + +int p_munmap(git_map *map) +{ + assert(map != NULL); + free(map->data); + + return 0; +} + +#endif + diff --git a/src/netops.c b/src/netops.c index 6808c8ee7..11295c5cd 100644 --- a/src/netops.c +++ b/src/netops.c @@ -376,7 +376,7 @@ static int ssl_setup(git_transport *t, const char *host) int gitno_connect(git_transport *t, const char *host, const char *port) { -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO struct addrinfo *info = NULL, *p; struct addrinfo hints; #else @@ -388,7 +388,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #endif int ret; GIT_SOCKET s = INVALID_SOCKET; -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -407,7 +407,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) port_num = atol(port); #endif -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); #else @@ -418,7 +418,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) net_set_error("error creating socket"); break; } -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) #else memcpy(&saddr.sin_addr, hent->h_addr_list[p], hent->h_length); @@ -435,7 +435,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) /* Oops, we couldn't connect to any address */ if (s == INVALID_SOCKET && -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO p == NULL) { #else hent->h_addr_list[p] == NULL) { @@ -445,7 +445,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) } t->socket = s; -#ifndef __amigaos4__ +#ifndef NO_ADDRINFO freeaddrinfo(info); #endif if (t->encrypt && ssl_setup(t, host) < 0) diff --git a/src/path.c b/src/path.c index eb9bc06f3..596dad164 100644 --- a/src/path.c +++ b/src/path.c @@ -517,7 +517,7 @@ int git_path_direach( de_buf = git__malloc(sizeof(struct dirent)); #endif -#ifdef __amigaos4__ +#ifdef NO_READDIR_R while (de = readdir(dir)) { #else while (p_readdir_r(dir, de_buf, de) == 0 && de != NULL) { diff --git a/src/posix.h b/src/posix.h index 8e8b394c8..35118f968 100644 --- a/src/posix.h +++ b/src/posix.h @@ -74,7 +74,7 @@ typedef SOCKET GIT_SOCKET; # include "unix/posix.h" #endif -#ifndef __amigaos4__ +#ifndef NO_READDIR_R #define p_readdir_r(d,e,r) readdir_r(d,e,&r) #else #define p_readdir_r(d,e,r) r = readdir(d) diff --git a/src/unix/map.c b/src/unix/map.c index b04e95a76..9dcae5845 100644 --- a/src/unix/map.c +++ b/src/unix/map.c @@ -9,9 +9,7 @@ #ifndef GIT_WIN32 #include "map.h" -#ifndef __amigaos4__ #include -#endif #include int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) @@ -24,7 +22,6 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs out->data = NULL; out->len = 0; -#ifndef __amigaos4__ if (prot & GIT_PROT_WRITE) mprot = PROT_WRITE; else if (prot & GIT_PROT_READ) @@ -36,16 +33,6 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs mflag = MAP_PRIVATE; out->data = mmap(NULL, len, mprot, mflag, fd, offset); -#else - if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { - printf("Trying to map shared-writeable file!!!\n"); - } - - if(out->data = malloc(len)) { - lseek(fd, offset, SEEK_SET); - p_read(fd, out->data, len); - } -#endif if (!out->data || out->data == MAP_FAILED) { giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); @@ -60,11 +47,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs int p_munmap(git_map *map) { assert(map != NULL); -#ifndef __amigaos4__ munmap(map->data, map->len); -#else - free(map->data); -#endif + return 0; } From 17b45d801d6dd40566ec1b876b108eb033e6779a Mon Sep 17 00:00:00 2001 From: Chris Young Date: Wed, 13 Jun 2012 23:43:25 +0100 Subject: [PATCH 025/123] Removed hardcoded CMAKE_SYSTEM_NAME --- CMakeLists.txt | 2 -- 1 file changed, 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8f260f025..657544938 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,6 @@ # Install: # > cmake --build . --target install -SET(CMAKE_SYSTEM_NAME "AmigaOS") - PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) From a8df98c6fb07b8ddff18a01d7f2f607d9493dd7c Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 14 Jun 2012 18:57:24 +0100 Subject: [PATCH 026/123] Updates from comments on OS4 compatibility pull request http://github.com/libgit2/libgit2/pull/766 --- examples/network/Makefile | 3 +-- examples/network/fetch.c | 7 +----- include/git2/common.h | 2 -- src/amiga/map.c | 3 ++- src/netops.c | 45 ++++++++++++++++++++++----------------- src/path.c | 9 -------- src/pool.c | 2 +- src/posix.h | 7 +++++- 8 files changed, 37 insertions(+), 41 deletions(-) diff --git a/examples/network/Makefile b/examples/network/Makefile index 708a6b1b3..17efcfdb3 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -3,7 +3,6 @@ default: all CC = gcc CFLAGS += -g CFLAGS += -I../../include -L../../build -LIBS += -lgit2 -lpthread #-lregex OBJECTS = \ git2.o \ @@ -12,4 +11,4 @@ OBJECTS = \ index-pack.o all: $(OBJECTS) - $(CC) $(CFLAGS) -o git2 $(OBJECTS) $(LIBS) + $(CC) $(CFLAGS) -o git2 $(OBJECTS) diff --git a/examples/network/fetch.c b/examples/network/fetch.c index fc4e94cfd..d2752124d 100644 --- a/examples/network/fetch.c +++ b/examples/network/fetch.c @@ -36,9 +36,7 @@ static void *download(void *ptr) exit: data->finished = 1; -#ifndef NO_PTHREADS pthread_exit(&data->ret); -#endif } int update_cb(const char *refname, const git_oid *a, const git_oid *b) @@ -83,9 +81,6 @@ int fetch(git_repository *repo, int argc, char **argv) data.finished = 0; memset(&stats, 0, sizeof(stats)); -#ifdef NO_PTHREADS - download(&data); -#else pthread_create(&worker, NULL, download, &data); // Loop while the worker thread is still running. Here we show processed @@ -96,7 +91,7 @@ int fetch(git_repository *repo, int argc, char **argv) usleep(10000); printf("\rReceived %d/%d objects in %d bytes", stats.processed, stats.total, bytes); } while (!data.finished); -#endif + printf("\rReceived %d/%d objects in %d bytes\n", stats.processed, stats.total, bytes); // Disconnect the underlying connection to prevent from idling. diff --git a/include/git2/common.h b/include/git2/common.h index 99018d4f5..1af045cff 100644 --- a/include/git2/common.h +++ b/include/git2/common.h @@ -103,8 +103,6 @@ GIT_EXTERN(int) git_strarray_copy(git_strarray *tgt, const git_strarray *src); */ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev); -/* GIT_EXTERN(int) p_fnmatch(const char *pattern, const char *string, int flags); */ - /** @} */ GIT_END_DECL #endif diff --git a/src/amiga/map.c b/src/amiga/map.c index d36bcbc9c..643e6c65d 100755 --- a/src/amiga/map.c +++ b/src/amiga/map.c @@ -23,7 +23,8 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs out->len = 0; if ((prot & GIT_PROT_WRITE) && ((flags & GIT_MAP_TYPE) == GIT_MAP_SHARED)) { - printf("Trying to map shared-writeable file!!!\n"); + giterr_set(GITERR_OS, "Trying to map shared-writeable"); + return -1; } if(out->data = malloc(len)) { diff --git a/src/netops.c b/src/netops.c index 11295c5cd..166c97162 100644 --- a/src/netops.c +++ b/src/netops.c @@ -33,6 +33,16 @@ #include "buffer.h" #include "transport.h" +#ifdef NO_ADDRINFO +struct addrinfo { + struct hostent *ai_hostent; + struct servent *ai_servent; + struct sockaddr_in ai_addr; + int ai_socktype; + long ai_port; +}; +#endif + #ifdef GIT_WIN32 static void net_set_error(const char *str) { @@ -378,41 +388,38 @@ int gitno_connect(git_transport *t, const char *host, const char *port) { #ifndef NO_ADDRINFO struct addrinfo *info = NULL, *p; - struct addrinfo hints; #else int p; - struct hostent *hent; - struct servent *sent; - struct sockaddr_in saddr; - long port_num = 0; #endif + struct addrinfo hints; int ret; GIT_SOCKET s = INVALID_SOCKET; -#ifndef NO_ADDRINFO + memset(&hints, 0x0, sizeof(struct addrinfo)); - hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; +#ifndef NO_ADDRINFO + hints.ai_family = AF_UNSPEC; if ((ret = getaddrinfo(host, port, &hints, &info)) < 0) { giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret)); return -1; } #else - hent = gethostbyname(host); - sent = getservbyname(port, 0); + hints.ai_hostent = gethostbyname(host); + hints.ai_servent = getservbyname(port, 0); - if(sent) - port_num = sent->s_port; + if(hints.ai_servent) + hints.ai_port = hints.ai_servent->s_port; else - port_num = atol(port); + hints.ai_port = atol(port); #endif #ifndef NO_ADDRINFO for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); #else - for (p = 0; hent->h_addr_list[p] != NULL; p++) { - s = socket(hent->h_addrtype, SOCK_STREAM, 0); + for (p = 0; hints.ai_hostent->h_addr_list[p] != NULL; p++) { + s = socket(hints.ai_hostent->h_addrtype, hints.ai_socktype, 0); #endif if (s == INVALID_SOCKET) { net_set_error("error creating socket"); @@ -421,10 +428,10 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #ifndef NO_ADDRINFO if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) #else - memcpy(&saddr.sin_addr, hent->h_addr_list[p], hent->h_length); - saddr.sin_family = hent->h_addrtype; - saddr.sin_port = port_num; - if (connect(s, (struct sockaddr *)&saddr, sizeof(struct sockaddr_in)) == 0) + memcpy(&hints.ai_addr.sin_addr, hints.ai_hostent->h_addr_list[p], hints.ai_hostent->h_length); + hints.ai_addr.sin_family = hints.ai_hostent->h_addrtype; + hints.ai_addr.sin_port = honts.ai_port; + if (connect(s, (struct sockaddr *)&hints.ai_addr, sizeof(struct sockaddr_in)) == 0) #endif break; @@ -438,7 +445,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #ifndef NO_ADDRINFO p == NULL) { #else - hent->h_addr_list[p] == NULL) { + hints.ai_hostent->h_addr_list[p] == NULL) { #endif giterr_set(GITERR_OS, "Failed to connect to %s", host); return -1; diff --git a/src/path.c b/src/path.c index d48435bd8..bd659f815 100644 --- a/src/path.c +++ b/src/path.c @@ -486,14 +486,9 @@ int git_path_cmp( /* Taken from git.git */ GIT_INLINE(int) is_dot_or_dotdot(const char *name) { -#ifdef __amigaos4__ - /* This is irrelevant on AmigaOS */ - return 0; -#else return (name[0] == '.' && (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'))); -#endif } int git_path_direach( @@ -521,11 +516,7 @@ int git_path_direach( de_buf = git__malloc(sizeof(struct dirent)); #endif -#ifdef NO_READDIR_R - while (de = readdir(dir)) { -#else while (p_readdir_r(dir, de_buf, de) == 0 && de != NULL) { -#endif int result; if (is_dot_or_dotdot(de->d_name)) diff --git a/src/pool.c b/src/pool.c index c5414b3b6..63bf09cee 100644 --- a/src/pool.c +++ b/src/pool.c @@ -276,7 +276,7 @@ uint32_t git_pool__system_page_size(void) GetSystemInfo(&info); size = (uint32_t)info.dwPageSize; #elif defined(__amigaos4__) - size = (uint32_t)1000000; // random value + size = (uint32_t)4096; /* 4K as there is no global value we can query */ #else size = (uint32_t)sysconf(_SC_PAGE_SIZE); #endif diff --git a/src/posix.h b/src/posix.h index 6b6c53db1..cc35c52e3 100644 --- a/src/posix.h +++ b/src/posix.h @@ -86,7 +86,12 @@ extern int p_gettimeofday(struct timeval *tv, struct timezone *tz); #ifndef NO_READDIR_R #define p_readdir_r(d,e,r) readdir_r(d,e,&r) #else -#define p_readdir_r(d,e,r) r = readdir(d) +GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct direct **result) +{ + GIT_UNUSED(entry); + *result = readdir(dirp); + return 0; +} #endif #endif From d043013fea859f5eb6f677cad28319d093f1dbda Mon Sep 17 00:00:00 2001 From: Chris Young Date: Thu, 14 Jun 2012 19:09:42 +0100 Subject: [PATCH 027/123] More changes resulting from pull request --- README.amiga | 4 ---- src/amiga/map.c | 7 ++----- src/netops.c | 2 +- src/path.c | 4 ++-- src/posix.h | 5 +++-- src/ppc/sha1ppc.S.obj | Bin 4471 -> 0 bytes 6 files changed, 8 insertions(+), 14 deletions(-) delete mode 100755 README.amiga delete mode 100644 src/ppc/sha1ppc.S.obj diff --git a/README.amiga b/README.amiga deleted file mode 100755 index 97414dda2..000000000 --- a/README.amiga +++ /dev/null @@ -1,4 +0,0 @@ -Nasty build hack: -When setting SHA1 to ppc in CMakeLists.txt, after running initial CMake, -copy src/ppc/sha1ppc.S.obj to build/CMakeFiles/git2.dir/src/ppc/ -Add CMakeFiles/git2.dir/src/ppc/sha1ppc.S.obj to the list in build/CMakeFiles/git2.dir/link.txt diff --git a/src/amiga/map.c b/src/amiga/map.c index 643e6c65d..2fb065c8b 100755 --- a/src/amiga/map.c +++ b/src/amiga/map.c @@ -14,9 +14,6 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offset) { - int mprot = 0; - int mflag = 0; - GIT_MMAP_VALIDATE(out, len, prot, flags); out->data = NULL; @@ -27,12 +24,12 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs return -1; } - if(out->data = malloc(len)) { + if((out->data = malloc(len))) { p_lseek(fd, offset, SEEK_SET); p_read(fd, out->data, len); } - if (!out->data || out->data == MAP_FAILED) { + if (!out->data || (out->data == MAP_FAILED)) { giterr_set(GITERR_OS, "Failed to mmap. Could not write data"); return -1; } diff --git a/src/netops.c b/src/netops.c index 166c97162..98b5035ff 100644 --- a/src/netops.c +++ b/src/netops.c @@ -430,7 +430,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) #else memcpy(&hints.ai_addr.sin_addr, hints.ai_hostent->h_addr_list[p], hints.ai_hostent->h_length); hints.ai_addr.sin_family = hints.ai_hostent->h_addrtype; - hints.ai_addr.sin_port = honts.ai_port; + hints.ai_addr.sin_port = hints.ai_port; if (connect(s, (struct sockaddr *)&hints.ai_addr, sizeof(struct sockaddr_in)) == 0) #endif break; diff --git a/src/path.c b/src/path.c index bd659f815..1d85559a9 100644 --- a/src/path.c +++ b/src/path.c @@ -516,7 +516,7 @@ int git_path_direach( de_buf = git__malloc(sizeof(struct dirent)); #endif - while (p_readdir_r(dir, de_buf, de) == 0 && de != NULL) { + while (p_readdir_r(dir, de_buf, &de) == 0 && de != NULL) { int result; if (is_dot_or_dotdot(de->d_name)) @@ -574,7 +574,7 @@ int git_path_dirload( 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; diff --git a/src/posix.h b/src/posix.h index cc35c52e3..d423b7e07 100644 --- a/src/posix.h +++ b/src/posix.h @@ -84,9 +84,10 @@ extern int p_gettimeofday(struct timeval *tv, struct timezone *tz); #endif #ifndef NO_READDIR_R -#define p_readdir_r(d,e,r) readdir_r(d,e,&r) +#define p_readdir_r(d,e,r) readdir_r(d,e,r) #else -GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct direct **result) +#include +GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { GIT_UNUSED(entry); *result = readdir(dirp); diff --git a/src/ppc/sha1ppc.S.obj b/src/ppc/sha1ppc.S.obj deleted file mode 100644 index a7dad600fee80b062086f352aa62b87b1755e7ac..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4471 zcma)=L1-M;8ONU$(Qct&8Rnpp9Aq%mD}s?i3S(o;Vv-_;QdAMGL6_KT2aHUUAn7o1 zXLc*qml#7q=u*>zBjVBu48h<-)P|}eY(WPfL{TX%LD0}W|Nrm%wuyRZ z1*>@)y*E3*|NDOP-fr*JAN}yy$gwp1IhHcCzjk8G{`ImBr_;C7=*Gz}KltdqH2V9i zDOJCF?l-H~QaXQcVXgPCFUr+hX|(s}&&%F#KPy+?PmRm>-}zPV-G7#=AE)p37XMyW z{e`SLoGI($GkMh?$>v+9FU&WeUa0yvvnowytDmMZp05U-tWL9KJvEzGgOTjD9rP>E zZ?L9*YoiH$MzXrGnAHyl$Z1;pq#n^`Bm-8@H|BsWi^>b#p1JTX|XS=Xu@4 z`zG`opkH&{`n{4~;Q6}1eeAT#>ho4!7w9*E_idnGao74?OA|a_^>H8M$c}PsTEAQA zlyTfPjvpN5*s^}_r_;u33<$~bTzDJ?nQWX`ZUVL*qDilw;rey^_uw$95);8@r|Mw*{UXch%{iGw4nuL(iZ+jWNn#Nf~tK$ciz@pgU)IFoW(KGDHUF@4fjq=FpzQ zIP|-G|Fiex+hI|5myNkf7tyv{m_>Ja%W^>$?PYSUA&0rLyJ5Ul!q^SVggJCKkR#Zc zLwkcvsQZbR%I+g$tvL3P<)I87ZCg#C4%&~%gZgisE4v5AStX1;uq?!Xfc(JB8fYJo z13vEHo}U?Gl`!_1@?KgXFFXNnO;0ed9=anbLu6X4L=9Ij0gp8PLIpVx@r0Va9mwp5<{Rm$Ap*CwBepG{f@yZS7l^f10 zH=LJl)D3t6-Wpy6FTDs}dZ9KwhZl7dPH=wdg!9S?=amyNzjUHlwE3kE&MP0BS3Wo| zeW?0yf%Oa*f|o7?FI@;;dQc5+T0OJ=omchmysCfaW&PI;)IWGx|G~@p4_?-P@T&fs zsDJXZ{)3nGAH1yp;AQ<6>&DCam$ScoUNubzf|(8kGaR^l{}2DD`taazCZ`AFQwH$B zGQjfy9z+Ihd4PK1dOO$z|7xd1U8Vm=72Sx9bMHn3&4x1$kBT@WL{| z_25NhVqT#BxgIy+M=Q_e2e_Gy{7^Qy9{uoa%nx(DF0iicw6KO4JDry&s)-!uk*Vin zp5Q+5tgHI)1-a0d$c4T{F7zdGF<&B=J>?>AJQsQ6xyT#O#k`4J;16=4KamUliCpMU zo{RkQT;!MMVtz#~@C>!^`A{X;4a#>R@^38LRZ=Q>M z^IXig$mO=>Lhm9MdKbCSyU0b};XYL_@Q=B`zhN$LZ zXQ~B^<$C3{AkUmv`?x;*0x$gvUanWcOTU7bepQ1-@yaXbl~>Lyubfx=w+4Iyul8=v ztG%1^YVYQ}+P5{~5qRa1^U5RVl}FAikBT*WCUCuSUiss^^2d4UPt}Jv>rz!+GV0 z^U9B6OT6;JdF6%k$_wYE7gZlVfR{c5FMSAJx)8i{A-|Pc)nHr9^f#D;m&dw+ng^qO z{-h&wLq4+AP1HD;>~kmok9v0=xm@gvfzP9uvtfPW-g{rZl=VJ2m-RlnnDu^LWWArw zWf#-aTYtpo@DK5MJU^LcfBf?_kCCk&D_7E)&hql` zWB>orcpiQDy}-A;FTN2te$U%H#CHZKz5Sg1@AzNrIQ$*`zK=5vy#80e6aVSMYv_6} zvgJQ Date: Thu, 14 Jun 2012 19:15:46 +0100 Subject: [PATCH 028/123] Fix incorrect revert --- examples/network/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/network/Makefile b/examples/network/Makefile index 17efcfdb3..298b1dc86 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -2,7 +2,7 @@ default: all CC = gcc CFLAGS += -g -CFLAGS += -I../../include -L../../build +CFLAGS += -I../../include -L../../build -lgit2 -lpthread OBJECTS = \ git2.o \ From abd6d52c724a97bf183ed41d3efa5408087d5856 Mon Sep 17 00:00:00 2001 From: Chris Young Date: Wed, 20 Jun 2012 19:27:17 +0100 Subject: [PATCH 029/123] revert defaults --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 657544938..a8e646d06 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -66,9 +66,9 @@ SET(INSTALL_LIB lib CACHE PATH "Where to install libraries to.") SET(INSTALL_INC include CACHE PATH "Where to install headers to.") # Build options -OPTION (BUILD_SHARED_LIBS "Build Shared Library (OFF for Static)" OFF) +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" 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) From 8d18f1f72375bab73029f3f755b9a8e5e57e1edc Mon Sep 17 00:00:00 2001 From: Chris Young Date: Wed, 20 Jun 2012 20:12:30 +0100 Subject: [PATCH 030/123] getaddrinfo() replacement functions --- src/netops.c | 121 ++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 86 insertions(+), 35 deletions(-) diff --git a/src/netops.c b/src/netops.c index 98b5035ff..67c631cd0 100644 --- a/src/netops.c +++ b/src/netops.c @@ -37,10 +37,91 @@ struct addrinfo { struct hostent *ai_hostent; struct servent *ai_servent; - struct sockaddr_in ai_addr; + struct sockaddr_in ai_addr_in; + struct sockaddr *ai_addr; + size_t ai_addrlen; + int ai_family; int ai_socktype; + int ai_protocol; long ai_port; + struct addrinfo *ai_next; }; + +static int getaddrinfo(const char *host, const char *port, struct addrinfo *hints, struct addrinfo **info) { + GIT_UNUSED(hints); + + struct addrinfo *ainfo, *ai; + int p = 0; + + if((ainfo = malloc(sizeof(struct addrinfo))) == NULL) + return -1; + + if((ainfo->ai_hostent = gethostbyname(host)) == NULL) + return -2; + + ainfo->ai_servent = getservbyname(port, 0); + + if(ainfo->ai_servent) + ainfo->ai_port = ainfo->ai_servent->s_port; + else + ainfo->ai_port = atol(port); + + ainfo->ai_addrlen = ainfo->ai_hostent->h_length; + + memcpy(&ainfo->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_length); + ainfo->ai_addr_in.sin_family = ainfo->ai_hostent->h_addrtype; + ainfo->ai_addr_in.sin_port = ainfo->ai_port; + ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; + + *info = ainfo; + + if(ainfo->ai_hostent->h_addr_list[1] == NULL) { + ainfo->ai_next = NULL; + return 0; + } + + ai = ainfo; + + for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { + ai->ai_next = malloc(sizeof(struct addrinfo)); + memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); + memcpy(&ai->ai_next->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[p], ainfo->ai_hostent->h_length); + ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; + ainfo->ai_addrlen = ainfo->ai_hostent->h_length; + ai = ai->ai_next; + } + + ai->ai_next = NULL; + return 0; +} + +static void freeaddrinfo(struct addrinfo *info) { + struct addrinfo *p, *next; + + p = info; + + while(p != NULL) { + next = p->ai_next; + free(p); + p = next; + } +} + +static const char *gai_strerror(int ret) { + switch(ret) { + case -1: + return "Out of memory"; + break; + + case -2: + return "Address lookup failed"; + break; + + default: + return "Unknown error"; + break; + } +} #endif #ifdef GIT_WIN32 @@ -386,53 +467,29 @@ static int ssl_setup(git_transport *t, const char *host) int gitno_connect(git_transport *t, const char *host, const char *port) { -#ifndef NO_ADDRINFO struct addrinfo *info = NULL, *p; -#else - int p; -#endif struct addrinfo hints; int ret; GIT_SOCKET s = INVALID_SOCKET; memset(&hints, 0x0, sizeof(struct addrinfo)); hints.ai_socktype = SOCK_STREAM; -#ifndef NO_ADDRINFO hints.ai_family = AF_UNSPEC; if ((ret = getaddrinfo(host, port, &hints, &info)) < 0) { giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret)); return -1; } -#else - hints.ai_hostent = gethostbyname(host); - hints.ai_servent = getservbyname(port, 0); - - if(hints.ai_servent) - hints.ai_port = hints.ai_servent->s_port; - else - hints.ai_port = atol(port); -#endif -#ifndef NO_ADDRINFO for (p = info; p != NULL; p = p->ai_next) { s = socket(p->ai_family, p->ai_socktype, p->ai_protocol); -#else - for (p = 0; hints.ai_hostent->h_addr_list[p] != NULL; p++) { - s = socket(hints.ai_hostent->h_addrtype, hints.ai_socktype, 0); -#endif + if (s == INVALID_SOCKET) { net_set_error("error creating socket"); break; } -#ifndef NO_ADDRINFO + if (connect(s, p->ai_addr, (socklen_t)p->ai_addrlen) == 0) -#else - memcpy(&hints.ai_addr.sin_addr, hints.ai_hostent->h_addr_list[p], hints.ai_hostent->h_length); - hints.ai_addr.sin_family = hints.ai_hostent->h_addrtype; - hints.ai_addr.sin_port = hints.ai_port; - if (connect(s, (struct sockaddr *)&hints.ai_addr, sizeof(struct sockaddr_in)) == 0) -#endif break; /* If we can't connect, try the next one */ @@ -441,20 +498,14 @@ int gitno_connect(git_transport *t, const char *host, const char *port) } /* Oops, we couldn't connect to any address */ - if (s == INVALID_SOCKET && -#ifndef NO_ADDRINFO - p == NULL) { -#else - hints.ai_hostent->h_addr_list[p] == NULL) { -#endif + if (s == INVALID_SOCKET && p == NULL) { giterr_set(GITERR_OS, "Failed to connect to %s", host); return -1; } t->socket = s; -#ifndef NO_ADDRINFO freeaddrinfo(info); -#endif + if (t->encrypt && ssl_setup(t, host) < 0) return -1; From b6423939d5a40dc282f0f58c175f63015c4c229f Mon Sep 17 00:00:00 2001 From: Chris Young Date: Wed, 20 Jun 2012 20:35:13 +0100 Subject: [PATCH 031/123] more getaddrinfo compatibility --- src/netops.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/netops.c b/src/netops.c index 67c631cd0..2161dfab9 100644 --- a/src/netops.c +++ b/src/netops.c @@ -66,13 +66,16 @@ static int getaddrinfo(const char *host, const char *port, struct addrinfo *hint else ainfo->ai_port = atol(port); - ainfo->ai_addrlen = ainfo->ai_hostent->h_length; memcpy(&ainfo->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_length); - ainfo->ai_addr_in.sin_family = ainfo->ai_hostent->h_addrtype; + ainfo->ai_protocol = 0; + ainfo->ai_socktype = hints->ai_socktype; + ainfo->ai_family = ainfo->ai_hostent->h_addrtype; + ainfo->ai_addr_in.sin_family = ainfo->ai_family; ainfo->ai_addr_in.sin_port = ainfo->ai_port; ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; - + ainfo->ai_addrlen = sizeof(struct sockaddr_in); + *info = ainfo; if(ainfo->ai_hostent->h_addr_list[1] == NULL) { @@ -87,7 +90,6 @@ static int getaddrinfo(const char *host, const char *port, struct addrinfo *hint memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); memcpy(&ai->ai_next->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[p], ainfo->ai_hostent->h_length); ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; - ainfo->ai_addrlen = ainfo->ai_hostent->h_length; ai = ai->ai_next; } From dca6b228d1725ce9ce7b940a172770f0e58b76cd Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Wed, 20 Jun 2012 18:06:37 +0200 Subject: [PATCH 032/123] notes: fix memory leaks --- src/notes.c | 20 ++++++++------------ tests-clar/notes/notes.c | 2 ++ 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/notes.c b/src/notes.c index efbdbabeb..0dfd3f891 100644 --- a/src/notes.c +++ b/src/notes.c @@ -56,7 +56,7 @@ static int find_subtree_r(git_tree **out, git_tree *root, error = find_subtree_in_current_level(&subtree, repo, root, target, *fanout); if (error == GIT_EEXISTS) { - return git_tree_lookup(out, repo, git_object_id((const git_object *)root)); + return git_tree_lookup(out, repo, git_tree_id(root)); } if (error < 0) @@ -64,13 +64,7 @@ static int find_subtree_r(git_tree **out, git_tree *root, *fanout += 2; error = find_subtree_r(out, subtree, repo, target, fanout); - - /* - * root is not ours to free, and the last subtree is the - * one being returned => we only need to free the subtrees in-between - */ - if (*out != subtree) - git_tree_free(subtree); + git_tree_free(subtree); return error; } @@ -153,7 +147,7 @@ static int manipulate_note_in_tree_r( int current_error)) { int error = -1; - git_tree *subtree = NULL; + git_tree *subtree = NULL, *new = NULL; char subtree_name[3]; error = find_subtree_in_current_level( @@ -176,7 +170,7 @@ static int manipulate_note_in_tree_r( /* An existing fanout has been found, let's dig deeper */ error = manipulate_note_in_tree_r( - out, repo, subtree, note_oid, annotated_object_sha, + &new, repo, subtree, note_oid, annotated_object_sha, fanout + 2, note_exists_cb, note_notfound_cb); if (error < 0) @@ -185,10 +179,12 @@ static int manipulate_note_in_tree_r( strncpy(subtree_name, annotated_object_sha + fanout, 2); subtree_name[2] = '\0'; - error = tree_write(out, repo, parent, - git_object_id((const git_object *)(*out)), subtree_name, 0040000); + error = tree_write(out, repo, parent, git_tree_id(new), + subtree_name, 0040000); + cleanup: + git_tree_free(new); git_tree_free(subtree); return error; } diff --git a/tests-clar/notes/notes.c b/tests-clar/notes/notes.c index 5f7f5a9c3..e1387782e 100644 --- a/tests-clar/notes/notes.c +++ b/tests-clar/notes/notes.c @@ -23,6 +23,8 @@ static void assert_note_equal(git_note *note, char *message, git_oid *note_oid) cl_git_pass(git_blob_lookup(&blob, _repo, note_oid)); cl_assert_equal_s(git_note_message(note), (const char *)git_blob_rawcontent(blob)); + + git_blob_free(blob); } static void create_note(git_oid *note_oid, const char *canonical_namespace, const char *target_sha, const char *message) From f95121cb4f9da6c5b06c9d0b31c2c9a969c1c09d Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Wed, 20 Jun 2012 18:07:27 +0200 Subject: [PATCH 033/123] object: add missing git_odb_object_free --- src/object.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/object.c b/src/object.c index d3673eda0..14d64befe 100644 --- a/src/object.c +++ b/src/object.c @@ -156,8 +156,10 @@ int git_object_lookup_prefix( type = odb_obj->raw.type; - if (create_object(&object, type) < 0) + if (create_object(&object, type) < 0) { + git_odb_object_free(odb_obj); return -1; + } /* Initialize parent object */ git_oid_cpy(&object->cached.oid, &odb_obj->cached.oid); From dfa0b65c695c24512a60678587183d95de4c18fa Mon Sep 17 00:00:00 2001 From: liyuray Date: Thu, 21 Jun 2012 20:17:54 +0800 Subject: [PATCH 034/123] fix below issues on mingw: 1. compile warning: D:\libgit2.git\src\win32\posix_w32.c: In function 'p_open': D:\libgit2.git\src\win32\posix_w32.c:235:10: warning: 'mode_t' is promoted to 'int' when passed through '...' [enabled by default] D:\libgit2.git\src\win32\posix_w32.c:235:10: note: (so you should pass 'int' not 'mode_t' to 'va_arg') D:\libgit2.git\src\win32\posix_w32.c:235:10: note: if this code is reached, the program will abort 2. test crash. 3. the above two issues are same root cause. please see http://www.eskimo.com/~scs/cclass/int/sx11c.html --- src/win32/posix_w32.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c index 37956af85..4e0150fb5 100644 --- a/src/win32/posix_w32.c +++ b/src/win32/posix_w32.c @@ -232,7 +232,7 @@ int p_open(const char *path, int flags, ...) va_list arg_list; va_start(arg_list, flags); - mode = va_arg(arg_list, mode_t); + mode = (mode_t)va_arg(arg_list, int); va_end(arg_list); } From a8fd805e2ff73a3825ddfe6f290774ef5a217972 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 21 Jun 2012 18:29:38 +0200 Subject: [PATCH 035/123] branch: add git_branch_foreach() --- include/git2/branch.h | 25 ++++++ src/branch.c | 43 ++++++++++ tests-clar/refs/branches/foreach.c | 121 +++++++++++++++++++++++++++++ 3 files changed, 189 insertions(+) create mode 100644 tests-clar/refs/branches/foreach.c diff --git a/include/git2/branch.h b/include/git2/branch.h index e2432bcfc..f2239a207 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -95,6 +95,31 @@ GIT_EXTERN(int) git_branch_list( git_repository *repo, unsigned int list_flags); +/** + * Loop over all the branches and issue a callback for each one. + * + * @param repo Repository where to find the branches. + * + * @param list_flags Filtering flags for the branch + * listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE + * or a combination of the two. + * + * @param branch_cb Callback to invoke per found branch. + * + * @param payload Extra parameter to callback function. + * + * @return 0 or an error code. + */ +GIT_EXTERN(int) git_branch_foreach( + git_repository *repo, + unsigned int list_flags, + int (*branch_cb)( + const char *branch_name, + git_branch_t branch_type, + void *payload), + void *payload +); + /** * Move/rename an existing branch reference. * diff --git a/src/branch.c b/src/branch.c index 8b97a8206..94d9a955e 100644 --- a/src/branch.c +++ b/src/branch.c @@ -183,6 +183,49 @@ int git_branch_list(git_strarray *branch_names, git_repository *repo, unsigned i return 0; } +typedef struct { + int (*branch_cb)( + const char *branch_name, + git_branch_t branch_type, + void *payload); + void *callback_payload; + unsigned int branch_type; +} branch_foreach_filter; + +static int branch_foreach_cb(const char *branch_name, void *payload) +{ + branch_foreach_filter *filter = (branch_foreach_filter *)payload; + + if (filter->branch_type & GIT_BRANCH_LOCAL && + git__prefixcmp(branch_name, GIT_REFS_HEADS_DIR) == 0) + return filter->branch_cb(branch_name + strlen(GIT_REFS_HEADS_DIR), GIT_BRANCH_LOCAL, filter->callback_payload); + + if (filter->branch_type & GIT_BRANCH_REMOTE && + git__prefixcmp(branch_name, GIT_REFS_REMOTES_DIR) == 0) + return filter->branch_cb(branch_name + strlen(GIT_REFS_REMOTES_DIR), GIT_BRANCH_REMOTE, filter->callback_payload); + + return 0; +} + +int git_branch_foreach( + git_repository *repo, + unsigned int list_flags, + int (*branch_cb)( + const char *branch_name, + git_branch_t branch_type, + void *payload), + void *payload +) +{ + branch_foreach_filter filter; + + filter.branch_cb = branch_cb; + filter.branch_type = list_flags; + filter.callback_payload = payload; + + return git_reference_foreach(repo, GIT_REF_LISTALL, &branch_foreach_cb, (void *)&filter); +} + int git_branch_move(git_repository *repo, const char *old_branch_name, const char *new_branch_name, int force) { git_reference *reference = NULL; diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c new file mode 100644 index 000000000..60bf50bd5 --- /dev/null +++ b/tests-clar/refs/branches/foreach.c @@ -0,0 +1,121 @@ +#include "clar_libgit2.h" +#include "refs.h" +#include "branch.h" + +static git_repository *repo; +static git_reference *fake_remote; + +void test_refs_branches_foreach__initialize(void) +{ + git_oid id; + + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(git_repository_open(&repo, "testrepo.git")); + + cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_reference_create_oid(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); +} + +void test_refs_branches_foreach__cleanup(void) +{ + git_reference_free(fake_remote); + git_repository_free(repo); + + cl_fixture_cleanup("testrepo.git"); +} + +static int count_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) +{ + int *count = (int *)payload; + + (*count)++; + + return 0; +} + +static void assert_retrieval(unsigned int flags, unsigned int expected_count) +{ + int count = 0; + + cl_git_pass(git_branch_foreach(repo, flags, count_branch_list_cb, &count)); + + cl_assert_equal_i(expected_count, count); +} + +void test_refs_branches_foreach__retrieve_all_branches(void) +{ + assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 9); +} + +void test_refs_branches_foreach__retrieve_remote_branches(void) +{ + assert_retrieval(GIT_BRANCH_REMOTE, 2); +} + +void test_refs_branches_foreach__retrieve_local_branches(void) +{ + assert_retrieval(GIT_BRANCH_LOCAL, 7); +} + +struct expectations { + const char *branch_name; + int encounters; +}; + +static void assert_branch_has_been_found(struct expectations *findings, const char* expected_branch_name) +{ + int pos = 0; + + while (findings[pos].branch_name) + { + if (strcmp(expected_branch_name, findings[pos].branch_name) == 0) { + cl_assert_equal_i(1, findings[pos].encounters); + return; + } + + pos++; + } + + cl_fail("expected branch not found in list."); +} + +static int contains_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) +{ + int pos = 0; + + struct expectations *exp = (struct expectations *)payload; + + while (exp[pos].branch_name) + { + if (strcmp(branch_name, exp[pos].branch_name) == 0) + exp[pos].encounters++; + + pos++; + } + + return 0; +} + +/* + * $ git branch -r + * nulltoken/HEAD -> nulltoken/master + * nulltoken/master + */ +void test_refs_branches_foreach__retrieve_remote_symbolic_HEAD_when_present(void) +{ + struct expectations exp[] = { + { "nulltoken/HEAD", 0 }, + { "nulltoken/master", 0 }, + { NULL, 0 } + }; + + git_reference_free(fake_remote); + cl_git_pass(git_reference_create_symbolic(&fake_remote, repo, "refs/remotes/nulltoken/HEAD", "refs/remotes/nulltoken/master", 0)); + + assert_retrieval(GIT_BRANCH_REMOTE, 3); + + cl_git_pass(git_branch_foreach(repo, GIT_BRANCH_REMOTE, contains_branch_list_cb, &exp)); + + assert_branch_has_been_found(exp, "nulltoken/HEAD"); + assert_branch_has_been_found(exp, "nulltoken/HEAD"); +} From d4827081ea3ed869c92fcc414bea81be7aa3edfe Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 21 Jun 2012 18:48:36 +0200 Subject: [PATCH 036/123] branch: drop git_branch_list() --- include/git2/branch.h | 24 --------- src/branch.c | 43 ---------------- tests-clar/refs/branches/listall.c | 78 ------------------------------ 3 files changed, 145 deletions(-) delete mode 100644 tests-clar/refs/branches/listall.c diff --git a/include/git2/branch.h b/include/git2/branch.h index f2239a207..8884df15a 100644 --- a/include/git2/branch.h +++ b/include/git2/branch.h @@ -71,30 +71,6 @@ GIT_EXTERN(int) git_branch_delete( const char *branch_name, git_branch_t branch_type); -/** - * Fill a list with all the branches in the Repository - * - * The string array will be filled with the names of the - * matching branches; these values are owned by the user and - * should be free'd manually when no longer needed, using - * `git_strarray_free`. - * - * @param branch_names Pointer to a git_strarray structure - * where the branch names will be stored. - * - * @param repo Repository where to find the branches. - * - * @param list_flags Filtering flags for the branch - * listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE - * or a combination of the two. - * - * @return 0 or an error code. - */ -GIT_EXTERN(int) git_branch_list( - git_strarray *branch_names, - git_repository *repo, - unsigned int list_flags); - /** * Loop over all the branches and issue a callback for each one. * diff --git a/src/branch.c b/src/branch.c index 94d9a955e..671e42051 100644 --- a/src/branch.c +++ b/src/branch.c @@ -140,49 +140,6 @@ on_error: return -1; } -typedef struct { - git_vector *branchlist; - unsigned int branch_type; -} branch_filter_data; - -static int branch_list_cb(const char *branch_name, void *payload) -{ - branch_filter_data *filter = (branch_filter_data *)payload; - - if (filter->branch_type & GIT_BRANCH_LOCAL && git__prefixcmp(branch_name, GIT_REFS_HEADS_DIR) == 0) { - return git_vector_insert(filter->branchlist, git__strdup(branch_name +strlen(GIT_REFS_HEADS_DIR))); - } else if (filter->branch_type & GIT_BRANCH_REMOTE && git__prefixcmp(branch_name, GIT_REFS_REMOTES_DIR) == 0) { - return git_vector_insert(filter->branchlist, git__strdup(branch_name+strlen(GIT_REFS_DIR))); - } - - return 0; -} - -int git_branch_list(git_strarray *branch_names, git_repository *repo, unsigned int list_flags) -{ - int error; - branch_filter_data filter; - git_vector branchlist; - - assert(branch_names && repo); - - if (git_vector_init(&branchlist, 8, NULL) < 0) - return -1; - - filter.branchlist = &branchlist; - filter.branch_type = list_flags; - - error = git_reference_foreach(repo, GIT_REF_LISTALL, &branch_list_cb, (void *)&filter); - if (error < 0) { - git_vector_free(&branchlist); - return -1; - } - - branch_names->strings = (char **)branchlist.contents; - branch_names->count = branchlist.length; - return 0; -} - typedef struct { int (*branch_cb)( const char *branch_name, diff --git a/tests-clar/refs/branches/listall.c b/tests-clar/refs/branches/listall.c deleted file mode 100644 index 77f8270fb..000000000 --- a/tests-clar/refs/branches/listall.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "clar_libgit2.h" -#include "refs.h" -#include "branch.h" - -static git_repository *repo; -static git_strarray branch_list; -static git_reference *fake_remote; - -void test_refs_branches_listall__initialize(void) -{ - git_oid id; - - cl_fixture_sandbox("testrepo.git"); - cl_git_pass(git_repository_open(&repo, "testrepo.git")); - - cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); - cl_git_pass(git_reference_create_oid(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); -} - -void test_refs_branches_listall__cleanup(void) -{ - git_strarray_free(&branch_list); - git_reference_free(fake_remote); - git_repository_free(repo); - - cl_fixture_cleanup("testrepo.git"); -} - -static void assert_retrieval(unsigned int flags, unsigned int expected_count) -{ - cl_git_pass(git_branch_list(&branch_list, repo, flags)); - - cl_assert_equal_i(branch_list.count, expected_count); -} - -void test_refs_branches_listall__retrieve_all_branches(void) -{ - assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 9); -} - -void test_refs_branches_listall__retrieve_remote_branches(void) -{ - assert_retrieval(GIT_BRANCH_REMOTE, 2); -} - -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(3, branch_list.count); - assert_branch_list_contains(&branch_list, "remotes/nulltoken/HEAD"); - assert_branch_list_contains(&branch_list, "remotes/nulltoken/master"); -} From f7292a990c719ea379ee1f7b5dc512963d69ad8d Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Fri, 22 Jun 2012 10:13:50 +0200 Subject: [PATCH 037/123] tests-clar: mark unused variables --- tests-clar/refs/branches/foreach.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c index 60bf50bd5..6e3876e7e 100644 --- a/tests-clar/refs/branches/foreach.c +++ b/tests-clar/refs/branches/foreach.c @@ -28,6 +28,9 @@ static int count_branch_list_cb(const char *branch_name, git_branch_t branch_typ { int *count = (int *)payload; + GIT_UNUSED(branch_type); + GIT_UNUSED(branch_name); + (*count)++; return 0; @@ -83,6 +86,8 @@ static int contains_branch_list_cb(const char *branch_name, git_branch_t branch_ { int pos = 0; + GIT_UNUSED(branch_type); + struct expectations *exp = (struct expectations *)payload; while (exp[pos].branch_name) From 2c227b8b33b8179feb056e60b7c1502b9c4fcd4b Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 00:02:23 +0200 Subject: [PATCH 038/123] repository: fix configuration updating issue while reinitialization When the repository was reinitialized, every configuration change in repo_init_config() was directly performed against the file on the filesystem. However, a previous version of the configuration had previously been loaded in memory and attached to the repository, in repo_init_reinit(). The repository was unaware of the change and the stale cached version of the configuration never refreshed. --- src/repository.c | 47 +++++++++++++---------------------------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/src/repository.c b/src/repository.c index 23a95b23e..bee7b3ee6 100644 --- a/src/repository.c +++ b/src/repository.c @@ -602,14 +602,10 @@ void git_repository_set_index(git_repository *repo, git_index *index) GIT_REFCOUNT_INC(index); } -static int check_repositoryformatversion(git_repository *repo) +static int check_repositoryformatversion(git_config *config) { - git_config *config; int version; - if (git_repository_config__weakptr(&config, repo) < 0) - return -1; - if (git_config_get_int32(&version, config, "core.repositoryformatversion") < 0) return -1; @@ -623,26 +619,6 @@ static int check_repositoryformatversion(git_repository *repo) return 0; } -static int repo_init_reinit(git_repository **repo_out, const char *repository_path, int is_bare) -{ - git_repository *repo = NULL; - - GIT_UNUSED(is_bare); - - if (git_repository_open(&repo, repository_path) < 0) - return -1; - - if (check_repositoryformatversion(repo) < 0) { - git_repository_free(repo); - return -1; - } - - /* TODO: reinitialize the templates */ - - *repo_out = repo; - return 0; -} - static int repo_init_createhead(const char *git_dir) { git_buf ref_path = GIT_BUF_INIT; @@ -717,6 +693,12 @@ static int repo_init_config(const char *git_dir, bool is_bare, bool is_reinit) return -1; } + if (is_reinit && check_repositoryformatversion(config) < 0) { + git_buf_free(&cfg_path); + git_config_free(config); + return -1; + } + SET_REPO_CONFIG(bool, "core.bare", is_bare); SET_REPO_CONFIG(int32, "core.repositoryformatversion", GIT_REPO_VERSION); SET_REPO_CONFIG(bool, "core.filemode", is_chmod_supported(git_buf_cstr(&cfg_path))); @@ -850,21 +832,18 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is is_reinit = git_path_isdir(repository_path.ptr) && valid_repository_path(&repository_path); if (is_reinit) { - if (repo_init_reinit(repo_out, repository_path.ptr, is_bare) < 0) + /* TODO: reinitialize the templates */ + + if (repo_init_config(repository_path.ptr, is_bare, is_reinit) < 0) goto cleanup; - result = repo_init_config(repository_path.ptr, is_bare, is_reinit); - goto cleanup; - } - - if (repo_init_structure(repository_path.ptr, is_bare) < 0 || + } else if (repo_init_structure(repository_path.ptr, is_bare) < 0 || repo_init_config(repository_path.ptr, is_bare, is_reinit) < 0 || - repo_init_createhead(repository_path.ptr) < 0 || - git_repository_open(repo_out, repository_path.ptr) < 0) { + repo_init_createhead(repository_path.ptr) < 0) { goto cleanup; } - result = 0; + result = git_repository_open(repo_out, repository_path.ptr); cleanup: git_buf_free(&repository_path); From dbb24a3962bd1dcd006c2f615b2cda1dcd1d042e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 11:30:43 +0200 Subject: [PATCH 039/123] repository: enhance reinitialization test coverage --- tests-clar/repo/init.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c index 1ba355ed6..f9e781e5f 100644 --- a/tests-clar/repo/init.c +++ b/tests-clar/repo/init.c @@ -242,6 +242,37 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) git_config_free(config); } +void test_repo_init__reinit_overwrites_filemode(void) +{ + git_config *config; + int expected, current_value; + +#ifdef GIT_WIN32 + expected = false; +#else + expected = true; +#endif + + /* Init a new repo */ + cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1)); + + /* Change the "core.filemode" config value to something unlikely */ + git_repository_config(&config, _repo); + git_config_set_bool(config, "core.filemode", !expected); + git_config_free(config); + git_repository_free(_repo); + + /* Reinit the repository */ + cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1)); + git_repository_config(&config, _repo); + + /* Ensure the "core.filemode" config value has been reset */ + cl_git_pass(git_config_get_bool(¤t_value, config, "core.filemode")); + cl_assert_equal_i(expected, current_value); + + git_config_free(config); +} + void test_repo_init__sets_logAllRefUpdates_according_to_type_of_repository(void) { assert_config_entry_on_init_bytype("core.logallrefupdates", GIT_ENOTFOUND, true); From d6d8cc276d986a4b8eb606527607ffa9292ff97f Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 13:41:26 +0200 Subject: [PATCH 040/123] tests-clar: fix isolation of repo initialization tests --- tests-clar/repo/init.c | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c index f9e781e5f..556a22b6f 100644 --- a/tests-clar/repo/init.c +++ b/tests-clar/repo/init.c @@ -170,10 +170,21 @@ static void assert_config_entry_on_init_bytype(const char *config_key, int expec { git_config *config; int current_value; + git_buf repo_path = GIT_BUF_INIT; cl_set_cleanup(&cleanup_repository, "config_entry"); - - cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", is_bare)); + + cl_git_pass(git_buf_puts(&repo_path, "config_entry/test.")); + + if (!is_bare) + cl_git_pass(git_buf_puts(&repo_path, "non.")); + + cl_git_pass(git_buf_puts(&repo_path, "bare.git")); + + cl_git_pass(git_repository_init(&_repo, git_buf_cstr(&repo_path), is_bare)); + + git_buf_free(&repo_path); + git_repository_config(&config, _repo); if (expected_value >= 0) { @@ -223,7 +234,7 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) int current_value; /* Init a new repo */ - test_repo_init__detect_ignorecase(); + cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); /* Change the "core.ignorecase" config value to something unlikely */ git_repository_config(&config, _repo); @@ -232,7 +243,7 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) git_repository_free(_repo); /* Reinit the repository */ - cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1)); + cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); git_repository_config(&config, _repo); /* Ensure the "core.ignorecase" config value hasn't been updated */ @@ -254,7 +265,7 @@ void test_repo_init__reinit_overwrites_filemode(void) #endif /* Init a new repo */ - cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1)); + cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); /* Change the "core.filemode" config value to something unlikely */ git_repository_config(&config, _repo); @@ -263,7 +274,7 @@ void test_repo_init__reinit_overwrites_filemode(void) git_repository_free(_repo); /* Reinit the repository */ - cl_git_pass(git_repository_init(&_repo, "config_entry/test.git", 1)); + cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); git_repository_config(&config, _repo); /* Ensure the "core.filemode" config value has been reset */ From d046945cefc34c8caafde53e20e1a064576e587e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 16:42:37 +0300 Subject: [PATCH 041/123] Fix MSVC compilation errors --- tests-clar/refs/branches/foreach.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c index 6e3876e7e..51e3381f8 100644 --- a/tests-clar/refs/branches/foreach.c +++ b/tests-clar/refs/branches/foreach.c @@ -26,11 +26,12 @@ void test_refs_branches_foreach__cleanup(void) static int count_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) { - int *count = (int *)payload; + int *count; GIT_UNUSED(branch_type); GIT_UNUSED(branch_name); + count = (int *)payload; (*count)++; return 0; @@ -85,10 +86,11 @@ static void assert_branch_has_been_found(struct expectations *findings, const ch static int contains_branch_list_cb(const char *branch_name, git_branch_t branch_type, void *payload) { int pos = 0; + struct expectations *exp; GIT_UNUSED(branch_type); - struct expectations *exp = (struct expectations *)payload; + exp = (struct expectations *)payload; while (exp[pos].branch_name) { From 798e4d53dcd2f5340782083130c0fb5227d596ac Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 22 Jun 2012 21:25:17 +0200 Subject: [PATCH 042/123] amigaos: Cleanup --- include/git2/errors.h | 40 +---------------- src/netops.c | 100 ++---------------------------------------- src/posix.c | 93 ++++++++++++++++++++++++++++++++++++++- src/posix.h | 32 ++++++++++++-- 4 files changed, 125 insertions(+), 140 deletions(-) diff --git a/include/git2/errors.h b/include/git2/errors.h index b4809fe15..ca7f0de6e 100644 --- a/include/git2/errors.h +++ b/include/git2/errors.h @@ -17,44 +17,6 @@ */ GIT_BEGIN_DECL -#ifdef GIT_OLD_ERRORS -enum { - GIT_SUCCESS = 0, - GIT_ERROR = -1, - GIT_ENOTOID = -2, - GIT_ENOTFOUND = -3, - 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, - GIT_EOVERFLOW = -24, - GIT_ENOTNUM = -25, - GIT_ESTREAM = -26, - GIT_EINVALIDARGS = -27, - GIT_EOBJCORRUPTED = -28, - GIT_EAMBIGUOUS = -29, - GIT_EPASSTHROUGH = -30, - GIT_ENOMATCH = -31, - GIT_ESHORTBUFFER = -32, -}; -#else - /** Generic return codes */ enum { GIT_OK = 0, @@ -67,13 +29,13 @@ enum { GIT_PASSTHROUGH = -30, GIT_REVWALKOVER = -31, }; -#endif typedef struct { char *message; int klass; } git_error; +/** Error classes */ typedef enum { GITERR_NOMEMORY, GITERR_OS, diff --git a/src/netops.c b/src/netops.c index 0342d7fa1..b369e5106 100644 --- a/src/netops.c +++ b/src/netops.c @@ -32,99 +32,6 @@ #include "buffer.h" #include "transport.h" -#ifdef NO_ADDRINFO -struct addrinfo { - struct hostent *ai_hostent; - struct servent *ai_servent; - struct sockaddr_in ai_addr_in; - struct sockaddr *ai_addr; - size_t ai_addrlen; - int ai_family; - int ai_socktype; - int ai_protocol; - long ai_port; - struct addrinfo *ai_next; -}; - -static int getaddrinfo(const char *host, const char *port, struct addrinfo *hints, struct addrinfo **info) { - GIT_UNUSED(hints); - - struct addrinfo *ainfo, *ai; - int p = 0; - - if((ainfo = malloc(sizeof(struct addrinfo))) == NULL) - return -1; - - if((ainfo->ai_hostent = gethostbyname(host)) == NULL) - return -2; - - ainfo->ai_servent = getservbyname(port, 0); - - if(ainfo->ai_servent) - ainfo->ai_port = ainfo->ai_servent->s_port; - else - ainfo->ai_port = atol(port); - - - memcpy(&ainfo->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[0], ainfo->ai_hostent->h_length); - ainfo->ai_protocol = 0; - ainfo->ai_socktype = hints->ai_socktype; - ainfo->ai_family = ainfo->ai_hostent->h_addrtype; - ainfo->ai_addr_in.sin_family = ainfo->ai_family; - ainfo->ai_addr_in.sin_port = ainfo->ai_port; - ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; - ainfo->ai_addrlen = sizeof(struct sockaddr_in); - - *info = ainfo; - - if(ainfo->ai_hostent->h_addr_list[1] == NULL) { - ainfo->ai_next = NULL; - return 0; - } - - ai = ainfo; - - for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { - ai->ai_next = malloc(sizeof(struct addrinfo)); - memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); - memcpy(&ai->ai_next->ai_addr_in.sin_addr, ainfo->ai_hostent->h_addr_list[p], ainfo->ai_hostent->h_length); - ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; - ai = ai->ai_next; - } - - ai->ai_next = NULL; - return 0; -} - -static void freeaddrinfo(struct addrinfo *info) { - struct addrinfo *p, *next; - - p = info; - - while(p != NULL) { - next = p->ai_next; - free(p); - p = next; - } -} - -static const char *gai_strerror(int ret) { - switch(ret) { - case -1: - return "Out of memory"; - break; - - case -2: - return "Address lookup failed"; - break; - - default: - return "Unknown error"; - break; - } -} -#endif - #ifdef GIT_WIN32 static void net_set_error(const char *str) { @@ -477,8 +384,9 @@ int gitno_connect(git_transport *t, const char *host, const char *port) hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_UNSPEC; - if ((ret = getaddrinfo(host, port, &hints, &info)) < 0) { - giterr_set(GITERR_NET, "Failed to resolve address for %s: %s", host, gai_strerror(ret)); + if ((ret = p_getaddrinfo(host, port, &hints, &info)) < 0) { + giterr_set(GITERR_NET, + "Failed to resolve address for %s: %s", host, p_gai_strerror(ret)); return -1; } @@ -505,7 +413,7 @@ int gitno_connect(git_transport *t, const char *host, const char *port) } t->socket = s; - freeaddrinfo(info); + p_freeaddrinfo(info); if (t->encrypt && ssl_setup(t, host) < 0) return -1; diff --git a/src/posix.c b/src/posix.c index a9a6af984..985221dd5 100644 --- a/src/posix.c +++ b/src/posix.c @@ -12,6 +12,97 @@ #ifndef GIT_WIN32 +#ifdef NO_ADDRINFO +int p_getaddrinfo( + const char *host, + const char *port, + struct addrinfo *hints, + struct addrinfo **info) +{ + GIT_UNUSED(hints); + + struct addrinfo *ainfo, *ai; + int p = 0; + + if ((ainfo = malloc(sizeof(struct addrinfo))) == NULL) + return -1; + + if ((ainfo->ai_hostent = gethostbyname(host)) == NULL) + return -2; + + ainfo->ai_servent = getservbyname(port, 0); + + if (ainfo->ai_servent) + ainfo->ai_port = ainfo->ai_servent->s_port; + else + ainfo->ai_port = atol(port); + + memcpy(&ainfo->ai_addr_in.sin_addr, + ainfo->ai_hostent->h_addr_list[0], + ainfo->ai_hostent->h_length); + + ainfo->ai_protocol = 0; + ainfo->ai_socktype = hints->ai_socktype; + ainfo->ai_family = ainfo->ai_hostent->h_addrtype; + ainfo->ai_addr_in.sin_family = ainfo->ai_family; + ainfo->ai_addr_in.sin_port = ainfo->ai_port; + ainfo->ai_addr = (struct addrinfo *)&ainfo->ai_addr_in; + ainfo->ai_addrlen = sizeof(struct sockaddr_in); + + *info = ainfo; + + if (ainfo->ai_hostent->h_addr_list[1] == NULL) { + ainfo->ai_next = NULL; + return 0; + } + + ai = ainfo; + + for (p = 1; ainfo->ai_hostent->h_addr_list[p] != NULL; p++) { + ai->ai_next = malloc(sizeof(struct addrinfo)); + memcpy(&ai->ai_next, ainfo, sizeof(struct addrinfo)); + memcpy(&ai->ai_next->ai_addr_in.sin_addr, + ainfo->ai_hostent->h_addr_list[p], + ainfo->ai_hostent->h_length); + ai->ai_next->ai_addr = (struct addrinfo *)&ai->ai_next->ai_addr_in; + ai = ai->ai_next; + } + + ai->ai_next = NULL; + return 0; +} + +void p_freeaddrinfo(struct addrinfo *info) +{ + struct addrinfo *p, *next; + + p = info; + + while(p != NULL) { + next = p->ai_next; + free(p); + p = next; + } +} + +const char *p_gai_strerror(int ret) +{ + switch(ret) { + case -1: + return "Out of memory"; + break; + + case -2: + return "Address lookup failed"; + break; + + default: + return "Unknown error"; + break; + } +} +#endif /* NO_ADDRINFO */ + int p_open(const char *path, int flags, ...) { mode_t mode = 0; @@ -63,7 +154,7 @@ int p_rename(const char *from, const char *to) return -1; } -#endif +#endif /* GIT_WIN32 */ int p_read(git_file fd, void *buf, size_t cnt) { diff --git a/src/posix.h b/src/posix.h index d423b7e07..76f3b942e 100644 --- a/src/posix.h +++ b/src/posix.h @@ -83,16 +83,40 @@ extern int p_gettimeofday(struct timeval *tv, struct timezone *tz); # include "unix/posix.h" #endif -#ifndef NO_READDIR_R -#define p_readdir_r(d,e,r) readdir_r(d,e,r) -#else -#include +#ifdef NO_READDIR_R +# include GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) { GIT_UNUSED(entry); *result = readdir(dirp); return 0; } +#else /* NO_READDIR_R */ +# define p_readdir_r(d,e,r) readdir_r(d,e,r) #endif +#ifdef NO_ADDRINFO +struct addrinfo { + struct hostent *ai_hostent; + struct servent *ai_servent; + struct sockaddr_in ai_addr_in; + struct sockaddr *ai_addr; + size_t ai_addrlen; + int ai_family; + int ai_socktype; + int ai_protocol; + long ai_port; + struct addrinfo *ai_next; +}; + +extern int p_getaddrinfo(const char *host, const char *port, + struct addrinfo *hints, struct addrinfo **info); +extern void p_freeaddrinfo(struct addrinfo *info); +extern const char *p_gai_strerror(int ret); +#else +# define p_getaddrinfo(a, b, c, d) getaddrinfo(a, b, c, d) +# define p_freeaddrinfo(a) freeaddrinfo(a) +# define p_gai_strerror(c) gai_strerror(c) +#endif /* NO_ADDRINFO */ + #endif From 527ed55448fb8fceb93837426c60bb401b8e32ab Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 15:51:44 +0200 Subject: [PATCH 043/123] references: introduce git_reference_foreach_glob() --- include/git2/refs.h | 31 +++++++++++++++- src/refs.c | 37 ++++++++++++++++++ tests-clar/refs/foreachglob.c | 70 +++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 tests-clar/refs/foreachglob.c diff --git a/include/git2/refs.h b/include/git2/refs.h index 2918215aa..2aa0ac267 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -258,7 +258,6 @@ GIT_EXTERN(int) git_reference_packall(git_repository *repo); */ GIT_EXTERN(int) git_reference_list(git_strarray *array, git_repository *repo, unsigned int list_flags); - /** * Perform an operation on each reference in the repository * @@ -324,6 +323,36 @@ GIT_EXTERN(void) git_reference_free(git_reference *ref); */ GIT_EXTERN(int) git_reference_cmp(git_reference *ref1, git_reference *ref2); +/** + * Loop over all the references and issue a callback for each one + * which name matches the given glob pattern. + * + * The processed references may be filtered by type, or using + * a bitwise OR of several types. Use the magic value + * `GIT_REF_LISTALL` to obtain all references, including + * packed ones. + * + * @param repo Repository where to find the references. + * + * @param list_flags Filtering flags for the reference + * listing. + * + * @param callback Callback to invoke per found reference. + * + * @param payload Extra parameter to callback function. + * + * @return 0 or an error code. + */ +GIT_EXTERN(int) git_reference_foreach_glob( + git_repository *repo, + const char *glob, + unsigned int list_flags, + int (*callback)( + const char *reference_name, + void *payload), + void *payload +); + /** @} */ GIT_END_DECL #endif diff --git a/src/refs.c b/src/refs.c index 104685793..ee076b3b8 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1764,3 +1764,40 @@ int git_reference__update(git_repository *repo, const git_oid *oid, const char * git_reference_free(ref); return res; } + +struct glob_cb_data { + const char *glob; + int (*callback)(const char *, void *); + void *payload; +}; + +static int fromglob_cb(const char *reference_name, void *payload) +{ + struct glob_cb_data *data = (struct glob_cb_data *)payload; + + if (!p_fnmatch(data->glob, reference_name, 0)) + return data->callback(reference_name, data->payload); + + return 0; +} + +int git_reference_foreach_glob( + git_repository *repo, + const char *glob, + unsigned int list_flags, + int (*callback)( + const char *reference_name, + void *payload), + void *payload) +{ + struct glob_cb_data data; + + assert(repo && glob && callback); + + data.glob = glob; + data.callback = callback; + data.payload = payload; + + return git_reference_foreach( + repo, list_flags, fromglob_cb, &data); +} diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c new file mode 100644 index 000000000..8bbcd71ed --- /dev/null +++ b/tests-clar/refs/foreachglob.c @@ -0,0 +1,70 @@ +#include "clar_libgit2.h" +#include "refs.h" + +static git_repository *repo; +static git_reference *fake_remote; + +void test_refs_foreachglob__initialize(void) +{ + git_oid id; + + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(git_repository_open(&repo, "testrepo.git")); + + cl_git_pass(git_oid_fromstr(&id, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644")); + cl_git_pass(git_reference_create_oid(&fake_remote, repo, "refs/remotes/nulltoken/master", &id, 0)); +} + +void test_refs_foreachglob__cleanup(void) +{ + git_reference_free(fake_remote); + git_repository_free(repo); + + cl_fixture_cleanup("testrepo.git"); +} + +static int count_cb(const char *reference_name, void *payload) +{ + int *count = (int *)payload; + + GIT_UNUSED(reference_name); + + (*count)++; + + return 0; +} + +static void assert_retrieval(const char *glob, unsigned int flags, int expected_count) +{ + int count = 0; + + cl_git_pass(git_reference_foreach_glob(repo, glob, flags, count_cb, &count)); + + cl_assert_equal_i(expected_count, count); +} + +void test_refs_foreachglob__retrieve_all_refs(void) +{ + /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */ + assert_retrieval("*", GIT_REF_LISTALL, 16); +} + +void test_refs_foreachglob__retrieve_remote_branches(void) +{ + assert_retrieval("refs/remotes/*", GIT_REF_LISTALL, 2); +} + +void test_refs_foreachglob__retrieve_local_branches(void) +{ + assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 7); +} + +void test_refs_foreachglob__retrieve_partially_named_references(void) +{ + /* + * refs/heads/packed-test, refs/heads/test + * refs/remotes/test/master, refs/tags/test + */ + + assert_retrieval("*test*", GIT_REF_LISTALL, 4); +} From 1163434646bfd27ffc4364754235d745a6384195 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 22 Jun 2012 17:04:16 +0200 Subject: [PATCH 044/123] revwalk: make git_revwalk_(push|hide)_glob() leverage git_reference_foreach_glob() --- src/revwalk.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/revwalk.c b/src/revwalk.c index 13d54b725..7bcdc4af8 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -540,7 +540,6 @@ static int push_ref(git_revwalk *walk, const char *refname, int hide) struct push_cb_data { git_revwalk *walk; - const char *glob; int hide; }; @@ -548,10 +547,7 @@ static int push_glob_cb(const char *refname, void *data_) { struct push_cb_data *data = (struct push_cb_data *)data_; - if (!p_fnmatch(data->glob, refname, 0)) - return push_ref(data->walk, refname, data->hide); - - return 0; + return push_ref(data->walk, refname, data->hide); } static int push_glob(git_revwalk *walk, const char *glob, int hide) @@ -584,11 +580,10 @@ static int push_glob(git_revwalk *walk, const char *glob, int hide) goto on_error; data.walk = walk; - data.glob = git_buf_cstr(&buf); data.hide = hide; - if (git_reference_foreach( - walk->repo, GIT_REF_LISTALL, push_glob_cb, &data) < 0) + if (git_reference_foreach_glob( + walk->repo, git_buf_cstr(&buf), GIT_REF_LISTALL, push_glob_cb, &data) < 0) goto on_error; regfree(&preg); From 60029f499e147bb4e03c419e3e7d235cd8120609 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 24 Jun 2012 16:56:32 +0200 Subject: [PATCH 045/123] amigaos: Add missing include --- src/posix.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/posix.h b/src/posix.h index 76f3b942e..d35fe08a5 100644 --- a/src/posix.h +++ b/src/posix.h @@ -96,6 +96,7 @@ GIT_INLINE(int) p_readdir_r(DIR *dirp, struct dirent *entry, struct dirent **res #endif #ifdef NO_ADDRINFO +# include struct addrinfo { struct hostent *ai_hostent; struct servent *ai_servent; From f9fd7105818dfd56cfce578bd1b58dd5dd8c839a Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Mon, 25 Jun 2012 15:26:38 +0200 Subject: [PATCH 046/123] indexer: start parsing input data immediately Currently, the first call of git_indexer_stream_add adds the data to the underlying pack file and opens it for later use, but doesn't start parsing the already available data. This means, git_indexer_stream_finalize only works if git_indexer_stream_add was called at least twice. Kill this limitation by parsing available data immediately. --- src/indexer.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index 565d9ea0e..1b0a20321 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -313,8 +313,6 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz mwf = &idx->pack->mwf; if (git_mwindow_file_register(&idx->pack->mwf) < 0) return -1; - - return 0; } if (!idx->parsed_header) { From 371599576a82b43ab30fe66feadcfb3045e649ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 28 Jun 2012 09:33:08 +0200 Subject: [PATCH 047/123] indexer: don't use '/objects/pack/' unconditionally Not everyone who indexes a packfile wants to put it in the standard git repository location. --- examples/network/Makefile | 2 +- examples/network/index-pack.c | 2 +- include/git2/indexer.h | 4 ++-- src/fetch.c | 9 +++++++-- src/indexer.c | 2 +- src/transports/http.c | 7 ++++++- 6 files changed, 18 insertions(+), 8 deletions(-) diff --git a/examples/network/Makefile b/examples/network/Makefile index 298b1dc86..9afd49e5d 100644 --- a/examples/network/Makefile +++ b/examples/network/Makefile @@ -2,7 +2,7 @@ default: all CC = gcc CFLAGS += -g -CFLAGS += -I../../include -L../../build -lgit2 -lpthread +CFLAGS += -I../../include -L../../build -L../.. -lgit2 -lpthread OBJECTS = \ git2.o \ diff --git a/examples/network/index-pack.c b/examples/network/index-pack.c index 5824fc555..ef5a35957 100644 --- a/examples/network/index-pack.c +++ b/examples/network/index-pack.c @@ -25,7 +25,7 @@ int index_pack(git_repository *repo, int argc, char **argv) return EXIT_FAILURE; } - if (git_indexer_stream_new(&idx, ".git") < 0) { + if (git_indexer_stream_new(&idx, ".") < 0) { puts("bad idx"); return -1; } diff --git a/include/git2/indexer.h b/include/git2/indexer.h index 626377701..d300ba01a 100644 --- a/include/git2/indexer.h +++ b/include/git2/indexer.h @@ -29,9 +29,9 @@ typedef struct git_indexer_stream git_indexer_stream; * Create a new streaming indexer instance * * @param out where to store the indexer instance - * @param path to the gitdir (metadata directory) + * @param path to the directory where the packfile should be stored */ -GIT_EXTERN(int) git_indexer_stream_new(git_indexer_stream **out, const char *gitdir); +GIT_EXTERN(int) git_indexer_stream_new(git_indexer_stream **out, const char *path); /** * Add data to the indexer diff --git a/src/fetch.c b/src/fetch.c index 96b263faa..603284842 100644 --- a/src/fetch.c +++ b/src/fetch.c @@ -118,7 +118,8 @@ int git_fetch__download_pack( int recvd; char buff[1024]; gitno_buffer buf; - git_indexer_stream *idx; + git_buf path = GIT_BUF_INIT; + git_indexer_stream *idx = NULL; gitno_buffer_setup(t, &buf, buff, sizeof(buff)); @@ -127,9 +128,12 @@ int git_fetch__download_pack( return -1; } - if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0) + if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0) return -1; + if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0) + goto on_error; + memset(stats, 0, sizeof(git_indexer_stats)); if (git_indexer_stream_add(idx, buffered, buffered_size, stats) < 0) goto on_error; @@ -154,6 +158,7 @@ int git_fetch__download_pack( return 0; on_error: + git_buf_free(&path); git_indexer_stream_free(idx); return -1; } diff --git a/src/indexer.c b/src/indexer.c index 1b0a20321..b4312e15a 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -142,7 +142,7 @@ int git_indexer_stream_new(git_indexer_stream **out, const char *prefix) { git_indexer_stream *idx; git_buf path = GIT_BUF_INIT; - static const char suff[] = "/objects/pack/pack-received"; + static const char suff[] = "/pack"; int error; idx = git__calloc(1, sizeof(git_indexer_stream)); diff --git a/src/transports/http.c b/src/transports/http.c index 4139a2fa6..f25d639f3 100644 --- a/src/transports/http.c +++ b/src/transports/http.c @@ -545,6 +545,7 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi http_parser_settings settings; char buffer[1024]; gitno_buffer buf; + git_buf path = GIT_BUF_INIT; git_indexer_stream *idx = NULL; download_pack_cbdata data; @@ -555,7 +556,10 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi return -1; } - if (git_indexer_stream_new(&idx, git_repository_path(repo)) < 0) + if (git_buf_joinpath(&path, git_repository_path(repo), "objects/pack") < 0) + return -1; + + if (git_indexer_stream_new(&idx, git_buf_cstr(&path)) < 0) return -1; /* @@ -600,6 +604,7 @@ static int http_download_pack(git_transport *transport, git_repository *repo, gi on_error: git_indexer_stream_free(idx); + git_buf_free(&path); return -1; } From 1d8943c640bad4425b8578aae6f680fa8e513bc7 Mon Sep 17 00:00:00 2001 From: Carlos Martin Nieto Date: Thu, 28 Jun 2012 12:05:49 +0200 Subject: [PATCH 048/123] mwindow: allow memory-window files to deregister Once a file is registered, there is no way to deregister it, even after the structure that contains it is no longer needed and has been freed. This may be the source of #624. Allow and use the deregister function to remove our file from the global list. --- src/indexer.c | 2 ++ src/mwindow.c | 17 +++++++++++++++++ src/mwindow.h | 1 + src/pack.c | 1 + 4 files changed, 21 insertions(+) diff --git a/src/indexer.c b/src/indexer.c index b4312e15a..1f0ca82a2 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -773,6 +773,7 @@ int git_indexer_write(git_indexer *idx) cleanup: git_mwindow_free_all(&idx->pack->mwf); + git_mwindow_file_deregister(&idx->pack->mwf); if (error < 0) git_filebuf_cleanup(&idx->file); git_buf_free(&filename); @@ -886,6 +887,7 @@ void git_indexer_free(git_indexer *idx) return; p_close(idx->pack->mwf.fd); + git_mwindow_file_deregister(&idx->pack->mwf); git_vector_foreach(&idx->objects, i, e) git__free(e); git_vector_free(&idx->objects); diff --git a/src/mwindow.c b/src/mwindow.c index 74fbf7834..1a5446b9c 100644 --- a/src/mwindow.c +++ b/src/mwindow.c @@ -261,6 +261,23 @@ int git_mwindow_file_register(git_mwindow_file *mwf) return git_vector_insert(&ctl->windowfiles, mwf); } +int git_mwindow_file_deregister(git_mwindow_file *mwf) +{ + git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl; + git_mwindow_file *cur; + unsigned int i; + + git_vector_foreach(&ctl->windowfiles, i, cur) { + if (cur == mwf) { + git_vector_remove(&ctl->windowfiles, i); + return 0; + } + } + + giterr_set(GITERR_ODB, "Failed to find the memory window file to deregister"); + return -1; +} + void git_mwindow_close(git_mwindow **window) { git_mwindow *w = *window; diff --git a/src/mwindow.h b/src/mwindow.h index 058027251..d4fd19569 100644 --- a/src/mwindow.h +++ b/src/mwindow.h @@ -40,6 +40,7 @@ void git_mwindow_free_all(git_mwindow_file *mwf); unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor, git_off_t offset, size_t extra, unsigned int *left); void git_mwindow_scan_lru(git_mwindow_file *mwf, git_mwindow **lru_w, git_mwindow **lru_l); int git_mwindow_file_register(git_mwindow_file *mwf); +int git_mwindow_file_deregister(git_mwindow_file *mwf); void git_mwindow_close(git_mwindow **w_cursor); #endif diff --git a/src/pack.c b/src/pack.c index 9b5e0e18f..808ceb70c 100644 --- a/src/pack.c +++ b/src/pack.c @@ -535,6 +535,7 @@ void packfile_free(struct git_pack_file *p) /* clear_delta_base_cache(); */ git_mwindow_free_all(&p->mwf); + git_mwindow_file_deregister(&p->mwf); if (p->mwf.fd != -1) p_close(p->mwf.fd); From e28dd29b6ec9cfce63cb5db02d964376cb713bfd Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 28 Jun 2012 07:50:16 +0200 Subject: [PATCH 049/123] revparse: replace spaces with tabs --- src/revparse.c | 1196 ++++++++++++++++++------------------ tests-clar/refs/revparse.c | 172 +++--- 2 files changed, 684 insertions(+), 684 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 3f210d11b..bc750f441 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -14,747 +14,747 @@ #include "git2.h" typedef enum { - REVPARSE_STATE_INIT, - REVPARSE_STATE_CARET, - REVPARSE_STATE_LINEAR, - REVPARSE_STATE_COLON, - REVPARSE_STATE_DONE, + REVPARSE_STATE_INIT, + REVPARSE_STATE_CARET, + REVPARSE_STATE_LINEAR, + REVPARSE_STATE_COLON, + REVPARSE_STATE_DONE, } revparse_state; static void set_invalid_syntax_err(const char *spec) { - giterr_set(GITERR_INVALID, "Refspec '%s' is not valid.", spec); + giterr_set(GITERR_INVALID, "Refspec '%s' is not valid.", spec); } static int revparse_lookup_fully_qualifed_ref(git_object **out, git_repository *repo, const char*spec) { - git_oid resolved; + git_oid resolved; - if (git_reference_name_to_oid(&resolved, repo, spec) < 0) - return GIT_ERROR; + if (git_reference_name_to_oid(&resolved, repo, spec) < 0) + return GIT_ERROR; - return git_object_lookup(out, repo, &resolved, GIT_OBJ_ANY); + return git_object_lookup(out, repo, &resolved, GIT_OBJ_ANY); } /* Returns non-zero if yes */ static int spec_looks_like_describe_output(const char *spec) { - regex_t regex; - int regex_error, retcode; + regex_t regex; + int regex_error, retcode; - regex_error = regcomp(®ex, ".+-[0-9]+-g[0-9a-fA-F]+", REG_EXTENDED); - if (regex_error != 0) { - giterr_set_regex(®ex, regex_error); - return 1; /* To be safe */ - } - retcode = regexec(®ex, spec, 0, NULL, 0); - regfree(®ex); - return retcode == 0; + regex_error = regcomp(®ex, ".+-[0-9]+-g[0-9a-fA-F]+", REG_EXTENDED); + if (regex_error != 0) { + giterr_set_regex(®ex, regex_error); + return 1; /* To be safe */ + } + retcode = regexec(®ex, spec, 0, NULL, 0); + regfree(®ex); + return retcode == 0; } static int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) { - size_t speclen = strlen(spec); - git_object *obj = NULL; - git_oid oid; - git_buf refnamebuf = GIT_BUF_INIT; - static const char* formatters[] = { - "refs/%s", - "refs/tags/%s", - "refs/heads/%s", - "refs/remotes/%s", - "refs/remotes/%s/HEAD", - NULL - }; - unsigned int i; - const char *substr; + size_t speclen = strlen(spec); + git_object *obj = NULL; + git_oid oid; + git_buf refnamebuf = GIT_BUF_INIT; + static const char* formatters[] = { + "refs/%s", + "refs/tags/%s", + "refs/heads/%s", + "refs/remotes/%s", + "refs/remotes/%s/HEAD", + NULL + }; + unsigned int i; + const char *substr; - /* "git describe" output; snip everything before/including "-g" */ - substr = strstr(spec, "-g"); - if (substr && - spec_looks_like_describe_output(spec) && - !revparse_lookup_object(out, repo, substr+2)) { - return 0; - } + /* "git describe" output; snip everything before/including "-g" */ + substr = strstr(spec, "-g"); + if (substr && + spec_looks_like_describe_output(spec) && + !revparse_lookup_object(out, repo, substr+2)) { + return 0; + } - /* SHA or prefix */ - if (!git_oid_fromstrn(&oid, spec, speclen)) { - if (!git_object_lookup_prefix(&obj, repo, &oid, speclen, GIT_OBJ_ANY)) { - *out = obj; - return 0; - } - } + /* SHA or prefix */ + if (!git_oid_fromstrn(&oid, spec, speclen)) { + if (!git_object_lookup_prefix(&obj, repo, &oid, speclen, GIT_OBJ_ANY)) { + *out = obj; + return 0; + } + } - /* Fully-named ref */ - if (!revparse_lookup_fully_qualifed_ref(&obj, repo, spec)) { - *out = obj; - return 0; - } + /* Fully-named ref */ + if (!revparse_lookup_fully_qualifed_ref(&obj, repo, spec)) { + *out = obj; + return 0; + } - /* Partially-named ref; match in this order: */ - for (i=0; formatters[i]; i++) { - git_buf_clear(&refnamebuf); - if (git_buf_printf(&refnamebuf, formatters[i], spec) < 0) { - return GIT_ERROR; - } + /* Partially-named ref; match in this order: */ + for (i=0; formatters[i]; i++) { + git_buf_clear(&refnamebuf); + if (git_buf_printf(&refnamebuf, formatters[i], spec) < 0) { + return GIT_ERROR; + } - if (!revparse_lookup_fully_qualifed_ref(&obj, repo, git_buf_cstr(&refnamebuf))) { - git_buf_free(&refnamebuf); - *out = obj; - return 0; - } - } - git_buf_free(&refnamebuf); + if (!revparse_lookup_fully_qualifed_ref(&obj, repo, git_buf_cstr(&refnamebuf))) { + git_buf_free(&refnamebuf); + *out = obj; + return 0; + } + } + git_buf_free(&refnamebuf); - giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); - return GIT_ERROR; + giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); + return GIT_ERROR; } static int all_chars_are_digits(const char *str, size_t len) { - size_t i=0; - for (i=0; i '9') return 0; - } - return 1; + size_t i=0; + for (i=0; i '9') return 0; + } + return 1; } static void normalize_maybe_empty_refname(git_buf *buf, git_repository *repo, const char *refspec, size_t refspeclen) { - git_reference *ref; + git_reference *ref; - if (!refspeclen) { - /* Empty refspec means current branch (target of HEAD) */ - git_reference_lookup(&ref, repo, "HEAD"); - git_buf_puts(buf, git_reference_target(ref)); - git_reference_free(ref); - } else if (strstr(refspec, "HEAD")) { - /* Explicit head */ - git_buf_puts(buf, refspec); - }else { - if (git__prefixcmp(refspec, "refs/heads/") != 0) { - git_buf_printf(buf, "refs/heads/%s", refspec); - } else { - git_buf_puts(buf, refspec); - } - } + if (!refspeclen) { + /* Empty refspec means current branch (target of HEAD) */ + git_reference_lookup(&ref, repo, "HEAD"); + git_buf_puts(buf, git_reference_target(ref)); + git_reference_free(ref); + } else if (strstr(refspec, "HEAD")) { + /* Explicit head */ + git_buf_puts(buf, refspec); + }else { + if (git__prefixcmp(refspec, "refs/heads/") != 0) { + git_buf_printf(buf, "refs/heads/%s", refspec); + } else { + git_buf_puts(buf, refspec); + } + } } static int walk_ref_history(git_object **out, git_repository *repo, const char *refspec, const char *reflogspec) { - git_reference *ref; - git_reflog *reflog = NULL; - int n, retcode = GIT_ERROR; - int i, refloglen; - const git_reflog_entry *entry; - git_buf buf = GIT_BUF_INIT; - size_t refspeclen = strlen(refspec); - size_t reflogspeclen = strlen(reflogspec); + git_reference *ref; + git_reflog *reflog = NULL; + int n, retcode = GIT_ERROR; + int i, refloglen; + const git_reflog_entry *entry; + git_buf buf = GIT_BUF_INIT; + size_t refspeclen = strlen(refspec); + size_t reflogspeclen = strlen(reflogspec); - if (git__prefixcmp(reflogspec, "@{") != 0 || - git__suffixcmp(reflogspec, "}") != 0) { - giterr_set(GITERR_INVALID, "Bad reflogspec '%s'", reflogspec); - return GIT_ERROR; - } + if (git__prefixcmp(reflogspec, "@{") != 0 || + git__suffixcmp(reflogspec, "}") != 0) { + giterr_set(GITERR_INVALID, "Bad reflogspec '%s'", reflogspec); + return GIT_ERROR; + } - /* "@{-N}" form means walk back N checkouts. That means the HEAD log. */ - if (refspeclen == 0 && !git__prefixcmp(reflogspec, "@{-")) { - regex_t regex; - int regex_error; + /* "@{-N}" form means walk back N checkouts. That means the HEAD log. */ + if (refspeclen == 0 && !git__prefixcmp(reflogspec, "@{-")) { + regex_t regex; + int regex_error; - if (git__strtol32(&n, reflogspec+3, NULL, 0) < 0 || - n < 1) { - giterr_set(GITERR_INVALID, "Invalid reflogspec %s", reflogspec); - return GIT_ERROR; - } + if (git__strtol32(&n, reflogspec+3, NULL, 0) < 0 || + n < 1) { + giterr_set(GITERR_INVALID, "Invalid reflogspec %s", reflogspec); + return GIT_ERROR; + } - if (!git_reference_lookup(&ref, repo, "HEAD")) { - if (!git_reflog_read(&reflog, ref)) { - regex_error = regcomp(®ex, "checkout: moving from (.*) to .*", REG_EXTENDED); - if (regex_error != 0) { - giterr_set_regex(®ex, regex_error); - } else { - regmatch_t regexmatches[2]; + if (!git_reference_lookup(&ref, repo, "HEAD")) { + if (!git_reflog_read(&reflog, ref)) { + regex_error = regcomp(®ex, "checkout: moving from (.*) to .*", REG_EXTENDED); + if (regex_error != 0) { + giterr_set_regex(®ex, regex_error); + } else { + regmatch_t regexmatches[2]; - refloglen = git_reflog_entrycount(reflog); - for (i=refloglen-1; i >= 0; i--) { - const char *msg; - entry = git_reflog_entry_byindex(reflog, i); + refloglen = git_reflog_entrycount(reflog); + for (i=refloglen-1; i >= 0; i--) { + const char *msg; + entry = git_reflog_entry_byindex(reflog, i); - msg = git_reflog_entry_msg(entry); - if (!regexec(®ex, msg, 2, regexmatches, 0)) { - n--; - if (!n) { - git_buf_put(&buf, msg+regexmatches[1].rm_so, regexmatches[1].rm_eo - regexmatches[1].rm_so); - retcode = revparse_lookup_object(out, repo, git_buf_cstr(&buf)); - break; - } - } - } - regfree(®ex); - } - } - git_reference_free(ref); - } - } else { - int date_error = 0; - git_time_t timestamp; - git_buf datebuf = GIT_BUF_INIT; + msg = git_reflog_entry_msg(entry); + if (!regexec(®ex, msg, 2, regexmatches, 0)) { + n--; + if (!n) { + git_buf_put(&buf, msg+regexmatches[1].rm_so, regexmatches[1].rm_eo - regexmatches[1].rm_so); + retcode = revparse_lookup_object(out, repo, git_buf_cstr(&buf)); + break; + } + } + } + regfree(®ex); + } + } + git_reference_free(ref); + } + } else { + int date_error = 0; + git_time_t timestamp; + git_buf datebuf = GIT_BUF_INIT; - git_buf_put(&datebuf, reflogspec+2, reflogspeclen-3); - date_error = git__date_parse(×tamp, git_buf_cstr(&datebuf)); + git_buf_put(&datebuf, reflogspec+2, reflogspeclen-3); + date_error = git__date_parse(×tamp, git_buf_cstr(&datebuf)); - /* @{u} or @{upstream} -> upstream branch, for a tracking branch. This is stored in the config. */ - if (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}")) { - git_config *cfg; - if (!git_repository_config(&cfg, repo)) { - /* Is the ref a tracking branch? */ - const char *remote; - git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.remote", refspec); - if (!git_config_get_string(&remote, cfg, git_buf_cstr(&buf))) { - /* Yes. Find the first merge target name. */ - const char *mergetarget; - git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.merge", refspec); - if (!git_config_get_string(&mergetarget, cfg, git_buf_cstr(&buf)) && - !git__prefixcmp(mergetarget, "refs/heads/")) { - /* Success. Look up the target and fetch the object. */ - git_buf_clear(&buf); - git_buf_printf(&buf, "refs/remotes/%s/%s", remote, mergetarget+11); - retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); - } - } - git_config_free(cfg); - } - } + /* @{u} or @{upstream} -> upstream branch, for a tracking branch. This is stored in the config. */ + if (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}")) { + git_config *cfg; + if (!git_repository_config(&cfg, repo)) { + /* Is the ref a tracking branch? */ + const char *remote; + git_buf_clear(&buf); + git_buf_printf(&buf, "branch.%s.remote", refspec); + if (!git_config_get_string(&remote, cfg, git_buf_cstr(&buf))) { + /* Yes. Find the first merge target name. */ + const char *mergetarget; + git_buf_clear(&buf); + git_buf_printf(&buf, "branch.%s.merge", refspec); + if (!git_config_get_string(&mergetarget, cfg, git_buf_cstr(&buf)) && + !git__prefixcmp(mergetarget, "refs/heads/")) { + /* Success. Look up the target and fetch the object. */ + git_buf_clear(&buf); + git_buf_printf(&buf, "refs/remotes/%s/%s", remote, mergetarget+11); + retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); + } + } + git_config_free(cfg); + } + } - /* @{N} -> Nth prior value for the ref (from reflog) */ - else if (all_chars_are_digits(reflogspec+2, reflogspeclen-3) && - !git__strtol32(&n, reflogspec+2, NULL, 0) && - n <= 100000000) { /* Allow integer time */ - normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); + /* @{N} -> Nth prior value for the ref (from reflog) */ + else if (all_chars_are_digits(reflogspec+2, reflogspeclen-3) && + !git__strtol32(&n, reflogspec+2, NULL, 0) && + n <= 100000000) { /* Allow integer time */ + normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); - if (n == 0) { - retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); - } else if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { - if (!git_reflog_read(&reflog, ref)) { - int numentries = git_reflog_entrycount(reflog); - if (numentries < n) { - giterr_set(GITERR_REFERENCE, "Reflog for '%s' has only %d entries, asked for %d", - git_buf_cstr(&buf), numentries, n); - retcode = GIT_ERROR; - } else { - const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, n); - const git_oid *oid = git_reflog_entry_oidold(entry); - retcode = git_object_lookup(out, repo, oid, GIT_OBJ_ANY); - } - } - git_reference_free(ref); - } - } + if (n == 0) { + retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); + } else if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { + if (!git_reflog_read(&reflog, ref)) { + int numentries = git_reflog_entrycount(reflog); + if (numentries < n) { + giterr_set(GITERR_REFERENCE, "Reflog for '%s' has only %d entries, asked for %d", + git_buf_cstr(&buf), numentries, n); + retcode = GIT_ERROR; + } else { + const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, n); + const git_oid *oid = git_reflog_entry_oidold(entry); + retcode = git_object_lookup(out, repo, oid, GIT_OBJ_ANY); + } + } + git_reference_free(ref); + } + } - else if (!date_error) { - /* Ref as it was on a certain date */ - normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); + else if (!date_error) { + /* Ref as it was on a certain date */ + normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); - if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { - git_reflog *reflog; - if (!git_reflog_read(&reflog, ref)) { - /* Keep walking until we find an entry older than the given date */ - int numentries = git_reflog_entrycount(reflog); - int i; + if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { + git_reflog *reflog; + if (!git_reflog_read(&reflog, ref)) { + /* Keep walking until we find an entry older than the given date */ + int numentries = git_reflog_entrycount(reflog); + int i; - /* TODO: clunky. Factor "now" into a utility */ - git_signature *sig; - git_time as_of; + /* TODO: clunky. Factor "now" into a utility */ + git_signature *sig; + git_time as_of; - git_signature_now(&sig, "blah", "blah"); - as_of = sig->when; - git_signature_free(sig); + git_signature_now(&sig, "blah", "blah"); + as_of = sig->when; + git_signature_free(sig); - as_of.time = (timestamp > 0) - ? timestamp - : sig->when.time + timestamp; + as_of.time = (timestamp > 0) + ? timestamp + : sig->when.time + timestamp; - for (i=numentries-1; i>0; i--) { - const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); - git_time commit_time = git_reflog_entry_committer(entry)->when; - if (git__time_cmp(&commit_time, &as_of) <= 0 ) { - retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); - break; - } - } + for (i=numentries-1; i>0; i--) { + const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); + git_time commit_time = git_reflog_entry_committer(entry)->when; + if (git__time_cmp(&commit_time, &as_of) <= 0 ) { + retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); + break; + } + } - if (!i) { - /* Didn't find a match. Use the oldest revision in the reflog. */ - const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, 0); - retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); - } + if (!i) { + /* Didn't find a match. Use the oldest revision in the reflog. */ + const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, 0); + retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); + } - git_reflog_free(reflog); - } + git_reflog_free(reflog); + } - git_reference_free(ref); - } - } + git_reference_free(ref); + } + } - git_buf_free(&datebuf); - } + git_buf_free(&datebuf); + } - if (reflog) git_reflog_free(reflog); - git_buf_free(&buf); - return retcode; + if (reflog) git_reflog_free(reflog); + git_buf_free(&buf); + return retcode; } static git_object* dereference_object(git_object *obj) { - git_otype type = git_object_type(obj); + git_otype type = git_object_type(obj); - switch (type) { - case GIT_OBJ_COMMIT: - { - git_tree *tree = NULL; - if (0 == git_commit_tree(&tree, (git_commit*)obj)) { - return (git_object*)tree; - } - } - break; - case GIT_OBJ_TAG: - { - git_object *newobj = NULL; - if (0 == git_tag_target(&newobj, (git_tag*)obj)) { - return newobj; - } - } - break; + switch (type) { + case GIT_OBJ_COMMIT: + { + git_tree *tree = NULL; + if (0 == git_commit_tree(&tree, (git_commit*)obj)) { + return (git_object*)tree; + } + } + break; + case GIT_OBJ_TAG: + { + git_object *newobj = NULL; + if (0 == git_tag_target(&newobj, (git_tag*)obj)) { + return newobj; + } + } + break; - default: - case GIT_OBJ_TREE: - case GIT_OBJ_BLOB: - case GIT_OBJ_OFS_DELTA: - case GIT_OBJ_REF_DELTA: - break; - } + default: + case GIT_OBJ_TREE: + case GIT_OBJ_BLOB: + case GIT_OBJ_OFS_DELTA: + case GIT_OBJ_REF_DELTA: + break; + } - /* Can't dereference some types */ - return NULL; + /* Can't dereference some types */ + return NULL; } static int dereference_to_type(git_object **out, git_object *obj, git_otype target_type) { - int retcode = 1; - git_object *obj1 = obj, *obj2 = obj; + int retcode = 1; + git_object *obj1 = obj, *obj2 = obj; - while (retcode > 0) { - git_otype this_type = git_object_type(obj1); + while (retcode > 0) { + git_otype this_type = git_object_type(obj1); - if (this_type == target_type) { - *out = obj1; - retcode = 0; - } else { - /* Dereference once, if possible. */ - obj2 = dereference_object(obj1); - if (!obj2) { - giterr_set(GITERR_REFERENCE, "Can't dereference to type"); - retcode = GIT_ERROR; - } - } - if (obj1 != obj && obj1 != obj2) { - git_object_free(obj1); - } - obj1 = obj2; - } - return retcode; + if (this_type == target_type) { + *out = obj1; + retcode = 0; + } else { + /* Dereference once, if possible. */ + obj2 = dereference_object(obj1); + if (!obj2) { + giterr_set(GITERR_REFERENCE, "Can't dereference to type"); + retcode = GIT_ERROR; + } + } + if (obj1 != obj && obj1 != obj2) { + git_object_free(obj1); + } + obj1 = obj2; + } + return retcode; } static git_otype parse_obj_type(const char *str) { - if (!strcmp(str, "{commit}")) return GIT_OBJ_COMMIT; - if (!strcmp(str, "{tree}")) return GIT_OBJ_TREE; - if (!strcmp(str, "{blob}")) return GIT_OBJ_BLOB; - if (!strcmp(str, "{tag}")) return GIT_OBJ_TAG; - return GIT_OBJ_BAD; + if (!strcmp(str, "{commit}")) return GIT_OBJ_COMMIT; + if (!strcmp(str, "{tree}")) return GIT_OBJ_TREE; + if (!strcmp(str, "{blob}")) return GIT_OBJ_BLOB; + if (!strcmp(str, "{tag}")) return GIT_OBJ_TAG; + return GIT_OBJ_BAD; } static int handle_caret_syntax(git_object **out, git_repository *repo, git_object *obj, const char *movement) { - git_commit *commit; - size_t movementlen = strlen(movement); - int n; + git_commit *commit; + size_t movementlen = strlen(movement); + int n; - if (*movement == '{') { - if (movement[movementlen-1] != '}') { - set_invalid_syntax_err(movement); - return GIT_ERROR; - } + if (*movement == '{') { + if (movement[movementlen-1] != '}') { + set_invalid_syntax_err(movement); + return GIT_ERROR; + } - /* {} -> Dereference until we reach an object that isn't a tag. */ - if (movementlen == 2) { - git_object *newobj = obj; - git_object *newobj2 = newobj; - while (git_object_type(newobj2) == GIT_OBJ_TAG) { - newobj2 = dereference_object(newobj); - if (newobj != obj) git_object_free(newobj); - if (!newobj2) { - giterr_set(GITERR_REFERENCE, "Couldn't find object of target type."); - return GIT_ERROR; - } - newobj = newobj2; - } - *out = newobj2; - return 0; - } + /* {} -> Dereference until we reach an object that isn't a tag. */ + if (movementlen == 2) { + git_object *newobj = obj; + git_object *newobj2 = newobj; + while (git_object_type(newobj2) == GIT_OBJ_TAG) { + newobj2 = dereference_object(newobj); + if (newobj != obj) git_object_free(newobj); + if (!newobj2) { + giterr_set(GITERR_REFERENCE, "Couldn't find object of target type."); + return GIT_ERROR; + } + newobj = newobj2; + } + *out = newobj2; + return 0; + } - /* {/...} -> Walk all commits until we see a commit msg that matches the phrase. */ - if (movement[1] == '/') { - int retcode = GIT_ERROR; - git_revwalk *walk; - if (!git_revwalk_new(&walk, repo)) { - git_oid oid; - regex_t preg; - int reg_error; - git_buf buf = GIT_BUF_INIT; + /* {/...} -> Walk all commits until we see a commit msg that matches the phrase. */ + if (movement[1] == '/') { + int retcode = GIT_ERROR; + git_revwalk *walk; + if (!git_revwalk_new(&walk, repo)) { + git_oid oid; + regex_t preg; + int reg_error; + git_buf buf = GIT_BUF_INIT; - git_revwalk_sorting(walk, GIT_SORT_TIME); - git_revwalk_push(walk, git_object_id(obj)); + git_revwalk_sorting(walk, GIT_SORT_TIME); + git_revwalk_push(walk, git_object_id(obj)); - /* Extract the regex from the movement string */ - git_buf_put(&buf, movement+2, strlen(movement)-3); + /* Extract the regex from the movement string */ + git_buf_put(&buf, movement+2, strlen(movement)-3); - reg_error = regcomp(&preg, git_buf_cstr(&buf), REG_EXTENDED); - if (reg_error != 0) { - giterr_set_regex(&preg, reg_error); - } else { - while(!git_revwalk_next(&oid, walk)) { - git_object *walkobj; + reg_error = regcomp(&preg, git_buf_cstr(&buf), REG_EXTENDED); + if (reg_error != 0) { + giterr_set_regex(&preg, reg_error); + } else { + while(!git_revwalk_next(&oid, walk)) { + git_object *walkobj; - /* Fetch the commit object, and check for matches in the message */ - if (!git_object_lookup(&walkobj, repo, &oid, GIT_OBJ_COMMIT)) { - if (!regexec(&preg, git_commit_message((git_commit*)walkobj), 0, NULL, 0)) { - /* Found it! */ - retcode = 0; - *out = walkobj; - if (obj == walkobj) { - /* Avoid leaking an object */ - git_object_free(walkobj); - } - break; - } - git_object_free(walkobj); - } - } - if (retcode < 0) { - giterr_set(GITERR_REFERENCE, "Couldn't find a match for %s", movement); - } - regfree(&preg); - } + /* Fetch the commit object, and check for matches in the message */ + if (!git_object_lookup(&walkobj, repo, &oid, GIT_OBJ_COMMIT)) { + if (!regexec(&preg, git_commit_message((git_commit*)walkobj), 0, NULL, 0)) { + /* Found it! */ + retcode = 0; + *out = walkobj; + if (obj == walkobj) { + /* Avoid leaking an object */ + git_object_free(walkobj); + } + break; + } + git_object_free(walkobj); + } + } + if (retcode < 0) { + giterr_set(GITERR_REFERENCE, "Couldn't find a match for %s", movement); + } + regfree(&preg); + } - git_buf_free(&buf); - git_revwalk_free(walk); - } - return retcode; - } + git_buf_free(&buf); + git_revwalk_free(walk); + } + return retcode; + } - /* {...} -> Dereference until we reach an object of a certain type. */ - if (dereference_to_type(out, obj, parse_obj_type(movement)) < 0) { - return GIT_ERROR; - } - return 0; - } + /* {...} -> Dereference until we reach an object of a certain type. */ + if (dereference_to_type(out, obj, parse_obj_type(movement)) < 0) { + return GIT_ERROR; + } + return 0; + } - /* Dereference until we reach a commit. */ - if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { - /* Can't dereference to a commit; fail */ - return GIT_ERROR; - } + /* Dereference until we reach a commit. */ + if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { + /* Can't dereference to a commit; fail */ + return GIT_ERROR; + } - /* "^" is the same as "^1" */ - if (movementlen == 0) { - n = 1; - } else { - git__strtol32(&n, movement, NULL, 0); - } - commit = (git_commit*)obj; + /* "^" is the same as "^1" */ + if (movementlen == 0) { + n = 1; + } else { + git__strtol32(&n, movement, NULL, 0); + } + commit = (git_commit*)obj; - /* "^0" just returns the input */ - if (n == 0) { - *out = obj; - return 0; - } + /* "^0" just returns the input */ + if (n == 0) { + *out = obj; + return 0; + } - if (git_commit_parent(&commit, commit, n-1) < 0) { - return GIT_ERROR; - } + if (git_commit_parent(&commit, commit, n-1) < 0) { + return GIT_ERROR; + } - *out = (git_object*)commit; - return 0; + *out = (git_object*)commit; + return 0; } static int handle_linear_syntax(git_object **out, git_object *obj, const char *movement) { - git_commit *commit1, *commit2; - int i, n; + git_commit *commit1, *commit2; + int i, n; - /* Dereference until we reach a commit. */ - if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { - /* Can't dereference to a commit; fail */ - return GIT_ERROR; - } + /* Dereference until we reach a commit. */ + if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { + /* Can't dereference to a commit; fail */ + return GIT_ERROR; + } - /* "~" is the same as "~1" */ - if (*movement == '\0') { - n = 1; - } else if (git__strtol32(&n, movement, NULL, 0) < 0) { - return GIT_ERROR; - } - commit1 = (git_commit*)obj; + /* "~" is the same as "~1" */ + if (*movement == '\0') { + n = 1; + } else if (git__strtol32(&n, movement, NULL, 0) < 0) { + return GIT_ERROR; + } + commit1 = (git_commit*)obj; - /* "~0" just returns the input */ - if (n == 0) { - *out = obj; - return 0; - } + /* "~0" just returns the input */ + if (n == 0) { + *out = obj; + return 0; + } - for (i=0; ioid) < 0) { - git__free(alloc); - return GIT_ERROR; - } - } - } + while ((tok = git__strtok(&str, "/\\")) != NULL) { + entry = git_tree_entry_byname(tree2, tok); + if (tree2 != tree) git_tree_free(tree2); + if (git_tree_entry__is_tree(entry)) { + if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) { + git__free(alloc); + return GIT_ERROR; + } + } + } - if (!entry) { - giterr_set(GITERR_INVALID, "Invalid tree path '%s'", path); - git__free(alloc); - return GIT_ERROR; - } + if (!entry) { + giterr_set(GITERR_INVALID, "Invalid tree path '%s'", path); + git__free(alloc); + return GIT_ERROR; + } - git_oid_cpy(out, git_tree_entry_id(entry)); - git__free(alloc); - return 0; + git_oid_cpy(out, git_tree_entry_id(entry)); + git__free(alloc); + return 0; } static int handle_colon_syntax(git_object **out, - git_repository *repo, - git_object *obj, - const char *path) + git_repository *repo, + git_object *obj, + const char *path) { - git_tree *tree; - git_oid oid; - int error; + git_tree *tree; + git_oid oid; + int error; - /* Dereference until we reach a tree. */ - if (dereference_to_type(&obj, obj, GIT_OBJ_TREE) < 0) { - return GIT_ERROR; - } - tree = (git_tree*)obj; + /* Dereference until we reach a tree. */ + if (dereference_to_type(&obj, obj, GIT_OBJ_TREE) < 0) { + return GIT_ERROR; + } + tree = (git_tree*)obj; - /* Find the blob at the given path. */ - error = oid_for_tree_path(&oid, tree, repo, path); - git_tree_free(tree); + /* Find the blob at the given path. */ + error = oid_for_tree_path(&oid, tree, repo, path); + git_tree_free(tree); - if (error < 0) - return error; + if (error < 0) + return error; - return git_object_lookup(out, repo, &oid, GIT_OBJ_ANY); + return git_object_lookup(out, repo, &oid, GIT_OBJ_ANY); } static int revparse_global_grep(git_object **out, git_repository *repo, const char *pattern) { - git_revwalk *walk; - int retcode = GIT_ERROR; + git_revwalk *walk; + int retcode = GIT_ERROR; - if (!pattern[0]) { - giterr_set(GITERR_REGEX, "Empty pattern"); - return GIT_ERROR; - } + if (!pattern[0]) { + giterr_set(GITERR_REGEX, "Empty pattern"); + return GIT_ERROR; + } - if (!git_revwalk_new(&walk, repo)) { - regex_t preg; - int reg_error; - git_oid oid; + if (!git_revwalk_new(&walk, repo)) { + regex_t preg; + int reg_error; + git_oid oid; - git_revwalk_sorting(walk, GIT_SORT_TIME); - git_revwalk_push_glob(walk, "refs/heads/*"); + git_revwalk_sorting(walk, GIT_SORT_TIME); + git_revwalk_push_glob(walk, "refs/heads/*"); - reg_error = regcomp(&preg, pattern, REG_EXTENDED); - if (reg_error != 0) { - giterr_set_regex(&preg, reg_error); - } else { - git_object *walkobj = NULL, *resultobj = NULL; - while(!git_revwalk_next(&oid, walk)) { - /* Fetch the commit object, and check for matches in the message */ - if (walkobj != resultobj) git_object_free(walkobj); - if (!git_object_lookup(&walkobj, repo, &oid, GIT_OBJ_COMMIT)) { - if (!regexec(&preg, git_commit_message((git_commit*)walkobj), 0, NULL, 0)) { - /* Match! */ - resultobj = walkobj; - retcode = 0; - break; - } - } - } - if (!resultobj) { - giterr_set(GITERR_REFERENCE, "Couldn't find a match for %s", pattern); - git_object_free(walkobj); - } else { - *out = resultobj; - } - regfree(&preg); - git_revwalk_free(walk); - } - } + reg_error = regcomp(&preg, pattern, REG_EXTENDED); + if (reg_error != 0) { + giterr_set_regex(&preg, reg_error); + } else { + git_object *walkobj = NULL, *resultobj = NULL; + while(!git_revwalk_next(&oid, walk)) { + /* Fetch the commit object, and check for matches in the message */ + if (walkobj != resultobj) git_object_free(walkobj); + if (!git_object_lookup(&walkobj, repo, &oid, GIT_OBJ_COMMIT)) { + if (!regexec(&preg, git_commit_message((git_commit*)walkobj), 0, NULL, 0)) { + /* Match! */ + resultobj = walkobj; + retcode = 0; + break; + } + } + } + if (!resultobj) { + giterr_set(GITERR_REFERENCE, "Couldn't find a match for %s", pattern); + git_object_free(walkobj); + } else { + *out = resultobj; + } + regfree(&preg); + git_revwalk_free(walk); + } + } - return retcode; + return retcode; } int git_revparse_single(git_object **out, git_repository *repo, const char *spec) { - revparse_state current_state = REVPARSE_STATE_INIT, next_state = REVPARSE_STATE_INIT; - const char *spec_cur = spec; - git_object *cur_obj = NULL, *next_obj = NULL; - git_buf specbuffer = GIT_BUF_INIT, stepbuffer = GIT_BUF_INIT; - int retcode = 0; + revparse_state current_state = REVPARSE_STATE_INIT, next_state = REVPARSE_STATE_INIT; + const char *spec_cur = spec; + git_object *cur_obj = NULL, *next_obj = NULL; + git_buf specbuffer = GIT_BUF_INIT, stepbuffer = GIT_BUF_INIT; + int retcode = 0; - assert(out && repo && spec); + assert(out && repo && spec); - if (spec[0] == ':') { - if (spec[1] == '/') { - return revparse_global_grep(out, repo, spec+2); - } - /* TODO: support merge-stage path lookup (":2:Makefile"). */ - giterr_set(GITERR_INVALID, "Unimplemented"); - return GIT_ERROR; - } + if (spec[0] == ':') { + if (spec[1] == '/') { + return revparse_global_grep(out, repo, spec+2); + } + /* TODO: support merge-stage path lookup (":2:Makefile"). */ + giterr_set(GITERR_INVALID, "Unimplemented"); + return GIT_ERROR; + } - while (current_state != REVPARSE_STATE_DONE) { - switch (current_state) { - case REVPARSE_STATE_INIT: - if (!*spec_cur) { - /* No operators, just a name. Find it and return. */ - retcode = revparse_lookup_object(out, repo, spec); - next_state = REVPARSE_STATE_DONE; - } else if (*spec_cur == '@') { - /* '@' syntax doesn't allow chaining */ - git_buf_puts(&stepbuffer, spec_cur); - retcode = walk_ref_history(out, repo, git_buf_cstr(&specbuffer), git_buf_cstr(&stepbuffer)); - next_state = REVPARSE_STATE_DONE; - } else if (*spec_cur == '^') { - next_state = REVPARSE_STATE_CARET; - } else if (*spec_cur == '~') { - next_state = REVPARSE_STATE_LINEAR; - } else if (*spec_cur == ':') { - next_state = REVPARSE_STATE_COLON; - } else { - git_buf_putc(&specbuffer, *spec_cur); - } - spec_cur++; + while (current_state != REVPARSE_STATE_DONE) { + switch (current_state) { + case REVPARSE_STATE_INIT: + if (!*spec_cur) { + /* No operators, just a name. Find it and return. */ + retcode = revparse_lookup_object(out, repo, spec); + next_state = REVPARSE_STATE_DONE; + } else if (*spec_cur == '@') { + /* '@' syntax doesn't allow chaining */ + git_buf_puts(&stepbuffer, spec_cur); + retcode = walk_ref_history(out, repo, git_buf_cstr(&specbuffer), git_buf_cstr(&stepbuffer)); + next_state = REVPARSE_STATE_DONE; + } else if (*spec_cur == '^') { + next_state = REVPARSE_STATE_CARET; + } else if (*spec_cur == '~') { + next_state = REVPARSE_STATE_LINEAR; + } else if (*spec_cur == ':') { + next_state = REVPARSE_STATE_COLON; + } else { + git_buf_putc(&specbuffer, *spec_cur); + } + spec_cur++; - if (current_state != next_state && next_state != REVPARSE_STATE_DONE) { - /* Leaving INIT state, find the object specified, in case that state needs it */ - if (revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer)) < 0) { - retcode = GIT_ERROR; - next_state = REVPARSE_STATE_DONE; - } - } - break; + if (current_state != next_state && next_state != REVPARSE_STATE_DONE) { + /* Leaving INIT state, find the object specified, in case that state needs it */ + if (revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer)) < 0) { + retcode = GIT_ERROR; + next_state = REVPARSE_STATE_DONE; + } + } + break; - case REVPARSE_STATE_CARET: - /* Gather characters until NULL, '~', or '^' */ - if (!*spec_cur) { - retcode = handle_caret_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer)); - next_state = REVPARSE_STATE_DONE; - } else if (*spec_cur == '~') { - retcode = handle_caret_syntax(&next_obj, repo, cur_obj, git_buf_cstr(&stepbuffer)); - git_buf_clear(&stepbuffer); - next_state = !retcode ? REVPARSE_STATE_LINEAR : REVPARSE_STATE_DONE; - } else if (*spec_cur == '^') { - retcode = handle_caret_syntax(&next_obj, repo, cur_obj, git_buf_cstr(&stepbuffer)); - git_buf_clear(&stepbuffer); - if (retcode < 0) { - next_state = REVPARSE_STATE_DONE; - } - } else { - git_buf_putc(&stepbuffer, *spec_cur); - } - spec_cur++; - break; + case REVPARSE_STATE_CARET: + /* Gather characters until NULL, '~', or '^' */ + if (!*spec_cur) { + retcode = handle_caret_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer)); + next_state = REVPARSE_STATE_DONE; + } else if (*spec_cur == '~') { + retcode = handle_caret_syntax(&next_obj, repo, cur_obj, git_buf_cstr(&stepbuffer)); + git_buf_clear(&stepbuffer); + next_state = !retcode ? REVPARSE_STATE_LINEAR : REVPARSE_STATE_DONE; + } else if (*spec_cur == '^') { + retcode = handle_caret_syntax(&next_obj, repo, cur_obj, git_buf_cstr(&stepbuffer)); + git_buf_clear(&stepbuffer); + if (retcode < 0) { + next_state = REVPARSE_STATE_DONE; + } + } else { + git_buf_putc(&stepbuffer, *spec_cur); + } + spec_cur++; + break; - case REVPARSE_STATE_LINEAR: - if (!*spec_cur) { - retcode = handle_linear_syntax(out, cur_obj, git_buf_cstr(&stepbuffer)); - next_state = REVPARSE_STATE_DONE; - } else if (*spec_cur == '~') { - retcode = handle_linear_syntax(&next_obj, cur_obj, git_buf_cstr(&stepbuffer)); - git_buf_clear(&stepbuffer); - if (retcode < 0) { - next_state = REVPARSE_STATE_DONE; - } - } else if (*spec_cur == '^') { - retcode = handle_linear_syntax(&next_obj, cur_obj, git_buf_cstr(&stepbuffer)); - git_buf_clear(&stepbuffer); - next_state = !retcode ? REVPARSE_STATE_CARET : REVPARSE_STATE_DONE; - } else { - git_buf_putc(&stepbuffer, *spec_cur); - } - spec_cur++; - break; + case REVPARSE_STATE_LINEAR: + if (!*spec_cur) { + retcode = handle_linear_syntax(out, cur_obj, git_buf_cstr(&stepbuffer)); + next_state = REVPARSE_STATE_DONE; + } else if (*spec_cur == '~') { + retcode = handle_linear_syntax(&next_obj, cur_obj, git_buf_cstr(&stepbuffer)); + git_buf_clear(&stepbuffer); + if (retcode < 0) { + next_state = REVPARSE_STATE_DONE; + } + } else if (*spec_cur == '^') { + retcode = handle_linear_syntax(&next_obj, cur_obj, git_buf_cstr(&stepbuffer)); + git_buf_clear(&stepbuffer); + next_state = !retcode ? REVPARSE_STATE_CARET : REVPARSE_STATE_DONE; + } else { + git_buf_putc(&stepbuffer, *spec_cur); + } + spec_cur++; + break; - case REVPARSE_STATE_COLON: - if (*spec_cur) { - git_buf_putc(&stepbuffer, *spec_cur); - } else { - retcode = handle_colon_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer)); - next_state = REVPARSE_STATE_DONE; - } - spec_cur++; - break; + case REVPARSE_STATE_COLON: + if (*spec_cur) { + git_buf_putc(&stepbuffer, *spec_cur); + } else { + retcode = handle_colon_syntax(out, repo, cur_obj, git_buf_cstr(&stepbuffer)); + next_state = REVPARSE_STATE_DONE; + } + spec_cur++; + break; - case REVPARSE_STATE_DONE: - if (cur_obj && *out != cur_obj) git_object_free(cur_obj); - if (next_obj && *out != next_obj) git_object_free(next_obj); - break; - } + case REVPARSE_STATE_DONE: + if (cur_obj && *out != cur_obj) git_object_free(cur_obj); + if (next_obj && *out != next_obj) git_object_free(next_obj); + break; + } - current_state = next_state; - if (cur_obj != next_obj) { - if (cur_obj) git_object_free(cur_obj); - cur_obj = next_obj; - } - } + current_state = next_state; + if (cur_obj != next_obj) { + if (cur_obj) git_object_free(cur_obj); + cur_obj = next_obj; + } + } - if (*out != cur_obj) git_object_free(cur_obj); - if (*out != next_obj && next_obj != cur_obj) git_object_free(next_obj); + if (*out != cur_obj) git_object_free(cur_obj); + if (*out != next_obj && next_obj != cur_obj) git_object_free(next_obj); - git_buf_free(&specbuffer); - git_buf_free(&stepbuffer); - return retcode; + git_buf_free(&specbuffer); + git_buf_free(&stepbuffer); + return retcode; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 2ee72f206..a468a4cac 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -11,168 +11,168 @@ static char g_orig_tz[16] = {0}; /* Helpers */ static void test_object(const char *spec, const char *expected_oid) { - char objstr[64] = {0}; + char objstr[64] = {0}; - cl_git_pass(git_revparse_single(&g_obj, g_repo, spec)); - git_oid_fmt(objstr, git_object_id(g_obj)); - cl_assert_equal_s(objstr, expected_oid); + cl_git_pass(git_revparse_single(&g_obj, g_repo, spec)); + git_oid_fmt(objstr, git_object_id(g_obj)); + cl_assert_equal_s(objstr, expected_oid); - git_object_free(g_obj); - g_obj = NULL; + git_object_free(g_obj); + g_obj = NULL; } void test_refs_revparse__initialize(void) { - char *tz = cl_getenv("TZ"); - if (tz) - strcpy(g_orig_tz, tz); - cl_setenv("TZ", "UTC"); - g_repo = cl_git_sandbox_init("testrepo.git"); + char *tz = cl_getenv("TZ"); + if (tz) + strcpy(g_orig_tz, tz); + cl_setenv("TZ", "UTC"); + g_repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_revparse__cleanup(void) { - cl_git_sandbox_cleanup(); - g_obj = NULL; - cl_setenv("TZ", g_orig_tz); + cl_git_sandbox_cleanup(); + g_obj = NULL; + cl_setenv("TZ", g_orig_tz); } void test_refs_revparse__nonexistant_object(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist^1")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist~2")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist^1")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist~2")); } void test_refs_revparse__shas(void) { - test_object("c47800c7266a2be04c571c04d5a6614691ea99bd", "c47800c7266a2be04c571c04d5a6614691ea99bd"); - test_object("c47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object("c47800c7266a2be04c571c04d5a6614691ea99bd", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object("c47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); } void test_refs_revparse__head(void) { - test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("HEAD", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__full_refs(void) { - test_object("refs/heads/master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("refs/heads/test", "e90810b8df3e80c413d903f631643c716887138d"); - test_object("refs/tags/test", "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); + test_object("refs/heads/master", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("refs/heads/test", "e90810b8df3e80c413d903f631643c716887138d"); + test_object("refs/tags/test", "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); } void test_refs_revparse__partial_refs(void) { - test_object("point_to_blob", "1385f264afb75a56a5bec74243be9b367ba4ca08"); - test_object("packed-test", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); - test_object("br2", "a4a7dce85cf63874e984719f4fdd239f5145052f"); + test_object("point_to_blob", "1385f264afb75a56a5bec74243be9b367ba4ca08"); + test_object("packed-test", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); + test_object("br2", "a4a7dce85cf63874e984719f4fdd239f5145052f"); } void test_refs_revparse__describe_output(void) { - test_object("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); - test_object("not-good", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("blah-7-gc47800c", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object("not-good", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__nth_parent(void) { - test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); - test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); - test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); - test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); - test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); - test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("be3563a^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("be3563a^", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("be3563a^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); + test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__not_tag(void) { - test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); - test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("point_to_blob^{}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); + test_object("wrapped_tag^{}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); } void test_refs_revparse__to_type(void) { - test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); - test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); + test_object("wrapped_tag^{commit}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("wrapped_tag^{tree}", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); + test_object("point_to_blob^{blob}", "1385f264afb75a56a5bec74243be9b367ba4ca08"); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "wrapped_tag^{blob}")); } void test_refs_revparse__linear_history(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "foo~bar")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~bar")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "foo~bar")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master~bar")); - test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a"); - test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("master~0", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master~1", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master~2", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("master~1~1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); } void test_refs_revparse__chaining(void) { - test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); - test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); - test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); - test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479"); + test_object("master~1^1", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("master~1^2", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object("master^1^2~1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479"); } void test_refs_revparse__reflog(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); - test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); - test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); + test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__revwalk(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/not found in any commit}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/merge}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/((}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/not found in any commit}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/merge}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/((}")); - test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); - test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("br2^{/Merge}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); - test_object("master^{/fo.rth}", "9fd738e8f7967c078dceed8190330fc8648ee56a"); + test_object("master^{/anoth}", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + test_object("master^{/Merge}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("br2^{/Merge}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); + test_object("master^{/fo.rth}", "9fd738e8f7967c078dceed8190330fc8648ee56a"); } void test_refs_revparse__date(void) { - test_object("HEAD@{10 years ago}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{2012-4-30 10:23:20 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{2012-4-30 18:24 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{2012-4-30 23:24 -0300}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("HEAD@{10 years ago}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master@{2012-4-30 10:23:20 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master@{2012-4-30 18:24 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master@{2012-4-30 23:24 -0300}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - /* Core git gives a65fedf, because they don't take time zones into account. */ - test_object("master@{1335806640}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + /* Core git gives a65fedf, because they don't take time zones into account. */ + test_object("master@{1335806640}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__colon(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master:")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master:")); - test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f"); - test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b"); - test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); - test_object("master:new.txt", "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"); - test_object(":/Merge", "a4a7dce85cf63874e984719f4fdd239f5145052f"); - test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd"); - test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); + test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f"); + test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b"); + test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); + test_object("master:new.txt", "a71586c1dfe8a71c6cbf6c129f404c5642ff31bd"); + test_object(":/Merge", "a4a7dce85cf63874e984719f4fdd239f5145052f"); + test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd"); + test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); } From faaa7c517c71b1937da6888e173c9aa763b5286a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 27 Jun 2012 16:51:19 +0200 Subject: [PATCH 050/123] revparse: return trees through the "colon" syntax --- src/revparse.c | 16 ++++++++++++---- tests-clar/refs/revparse.c | 7 ++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index bc750f441..4bc6849a1 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -533,16 +533,24 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m static int oid_for_tree_path(git_oid *out, git_tree *tree, git_repository *repo, const char *path) { - char *str = git__strdup(path); - char *tok; - void *alloc = str; + char *str, *tok; + void *alloc; git_tree *tree2 = tree; const git_tree_entry *entry = NULL; + if (*path == '\0') { + git_oid_cpy(out, git_object_id((git_object *)tree)); + return 0; + } + + alloc = str = git__strdup(path); + while ((tok = git__strtok(&str, "/\\")) != NULL) { entry = git_tree_entry_byname(tree2, tok); if (tree2 != tree) git_tree_free(tree2); if (git_tree_entry__is_tree(entry)) { + if (str == '\0') + break; if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) { git__free(alloc); return GIT_ERROR; @@ -576,7 +584,7 @@ static int handle_colon_syntax(git_object **out, } tree = (git_tree*)obj; - /* Find the blob at the given path. */ + /* Find the blob or tree at the given path. */ error = oid_for_tree_path(&oid, tree, repo, path); git_tree_free(tree); diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index a468a4cac..b8b1ed955 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -166,8 +166,13 @@ void test_refs_revparse__colon(void) cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/")); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "master:")); + /* Trees */ + test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); + test_object("subtrees:", "ae90f12eea699729ed24555e40b9fd669da12a12"); + test_object("subtrees:ab", "f1425cef211cc08caa31e7b545ffb232acb098c3"); + + /* Blobs */ test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f"); test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b"); test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); From 5b68ba7e158367c9dc613754c50cad640a63fd52 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 27 Jun 2012 17:27:38 +0200 Subject: [PATCH 051/123] revparse: unfound treepath returns ENOTFOUND --- src/revparse.c | 28 +++++++++++++++++++++++++--- tests-clar/refs/revparse.c | 6 +++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 4bc6849a1..1b466cde0 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -537,6 +537,7 @@ static int oid_for_tree_path(git_oid *out, git_tree *tree, git_repository *repo, void *alloc; git_tree *tree2 = tree; const git_tree_entry *entry = NULL; + git_otype type; if (*path == '\0') { git_oid_cpy(out, git_object_id((git_object *)tree)); @@ -548,20 +549,40 @@ static int oid_for_tree_path(git_oid *out, git_tree *tree, git_repository *repo, while ((tok = git__strtok(&str, "/\\")) != NULL) { entry = git_tree_entry_byname(tree2, tok); if (tree2 != tree) git_tree_free(tree2); - if (git_tree_entry__is_tree(entry)) { - if (str == '\0') + + if (entry == NULL) + break; + + type = git_tree_entry_type(entry); + + switch (type) { + case GIT_OBJ_TREE: + if (*str == '\0') break; if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) { git__free(alloc); return GIT_ERROR; } + break; + case GIT_OBJ_BLOB: + if (*str != '\0') { + entry = NULL; + goto out; + } + break; + default: + /* TODO: support submodules? */ + giterr_set(GITERR_INVALID, "Unimplemented"); + git__free(alloc); + return GIT_ERROR; } } +out: if (!entry) { giterr_set(GITERR_INVALID, "Invalid tree path '%s'", path); git__free(alloc); - return GIT_ERROR; + return GIT_ENOTFOUND; } git_oid_cpy(out, git_tree_entry_id(entry)); @@ -631,6 +652,7 @@ static int revparse_global_grep(git_object **out, git_repository *repo, const ch } if (!resultobj) { giterr_set(GITERR_REFERENCE, "Couldn't find a match for %s", pattern); + retcode = GIT_ENOTFOUND; git_object_free(walkobj); } else { *out = resultobj; diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index b8b1ed955..aaef90b1c 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -164,9 +164,13 @@ void test_refs_revparse__date(void) void test_refs_revparse__colon(void) { cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/42.txt")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/4.txt/nope")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:nope")); + /* Trees */ test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("subtrees:", "ae90f12eea699729ed24555e40b9fd669da12a12"); From 0d23c62c480d155b8ba446ca2ec536758a567bcc Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 28 Jun 2012 11:09:16 +0200 Subject: [PATCH 052/123] revparse: handle specs with caret and colon --- src/revparse.c | 4 ++++ tests-clar/refs/revparse.c | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/revparse.c b/src/revparse.c index 1b466cde0..dd3886e2d 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -732,6 +732,10 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec if (retcode < 0) { next_state = REVPARSE_STATE_DONE; } + } else if (*spec_cur == ':') { + retcode = handle_caret_syntax(&next_obj, repo, cur_obj, git_buf_cstr(&stepbuffer)); + git_buf_clear(&stepbuffer); + next_state = !retcode ? REVPARSE_STATE_COLON : REVPARSE_STATE_DONE; } else { git_buf_putc(&stepbuffer, *spec_cur); } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index aaef90b1c..e2e82cf82 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -170,6 +170,7 @@ void test_refs_revparse__colon(void) cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/42.txt")); cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/4.txt/nope")); cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:nope")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "test/master^1:branch_file.txt")); /* Trees */ test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); @@ -184,4 +185,5 @@ void test_refs_revparse__colon(void) test_object(":/Merge", "a4a7dce85cf63874e984719f4fdd239f5145052f"); test_object(":/one", "c47800c7266a2be04c571c04d5a6614691ea99bd"); test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); + test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); } From 0e7af9e758f5fcb3ddc8a1130181ddf3ef9c6b20 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 28 Jun 2012 18:04:01 +0200 Subject: [PATCH 053/123] revparse: unfound nth parent returns ENOTFOUND --- src/revparse.c | 2 +- tests-clar/refs/revparse.c | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/revparse.c b/src/revparse.c index dd3886e2d..5050bdf1b 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -485,7 +485,7 @@ static int handle_caret_syntax(git_object **out, git_repository *repo, git_objec } if (git_commit_parent(&commit, commit, n-1) < 0) { - return GIT_ERROR; + return GIT_ENOTFOUND; } *out = (git_object*)commit; diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index e2e82cf82..c71e6d844 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -85,6 +85,8 @@ void test_refs_revparse__nth_parent(void) test_object("be3563a^1^1", "4a202b346bb0fb0db7eff3cffeb3c70babbd2045"); test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "be3563a^42")); } void test_refs_revparse__not_tag(void) From 0e2fcca850e3021da4a08bc6487a10b35a75d05b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 29 Jun 2012 02:21:12 +0200 Subject: [PATCH 054/123] tree: Bring back `entry_bypath` Smaller, simpler, faster. --- include/git2/tree.h | 67 ++++++-- src/index.c | 2 +- src/notes.c | 2 +- src/tree.c | 247 +++++++++++++++++------------- src/tree.h | 6 +- tests-clar/object/tree/frompath.c | 75 ++++----- 6 files changed, 229 insertions(+), 170 deletions(-) diff --git a/include/git2/tree.h b/include/git2/tree.h index 8f62e752a..107c771c4 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -46,7 +46,11 @@ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git * @param len the length of the short identifier * @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) +GIT_INLINE(int) git_tree_lookup_prefix( + git_tree **tree, + git_repository *repo, + const git_oid *id, + unsigned int len) { return git_object_lookup_prefix((git_object **)tree, repo, id, len, GIT_OBJ_TREE); } @@ -62,12 +66,33 @@ GIT_INLINE(int) git_tree_lookup_prefix(git_tree **tree, git_repository *repo, co * * @param tree the tree to close */ - GIT_INLINE(void) git_tree_free(git_tree *tree) { git_object_free((git_object *) tree); } +/** + * Free a tree entry + * + * IMPORTANT: This function is only needed for tree + * entries owned by the user, such as the ones returned + * by `git_tree_entry_copy`. + * + * @param entry The entry to free + */ +GIT_EXTERN(void) git_tree_entry_free(git_tree_entry *entry); + +/** + * Duplicate a tree entry + * + * Create a copy of a tree entry. The returned copy is owned + * by the user, and must be freed manually with + * `git_tree_entry_free`. + * + * @param entry A tree entry to duplicate + * @return a copy of the original entry + */ +GIT_EXTERN(git_tree_entry *) git_tree_entry_copy(const git_tree_entry *entry); /** * Get the id of a tree. @@ -143,7 +168,10 @@ GIT_EXTERN(git_otype) git_tree_entry_type(const git_tree_entry *entry); * @param entry a tree entry * @return 0 or an error code */ -GIT_EXTERN(int) git_tree_entry_to_object(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 @@ -231,7 +259,12 @@ GIT_EXTERN(const git_tree_entry *) git_treebuilder_get(git_treebuilder *bld, con * @param attributes Folder attributes of the entry * @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); +GIT_EXTERN(int) git_treebuilder_insert( + const git_tree_entry **entry_out, + git_treebuilder *bld, + const char *filename, + const git_oid *id, + unsigned int attributes); /** * Remove an entry from the builder by its filename @@ -252,7 +285,10 @@ GIT_EXTERN(int) git_treebuilder_remove(git_treebuilder *bld, const char *filenam * @param bld Tree builder * @param filter Callback to filter entries */ -GIT_EXTERN(void) git_treebuilder_filter(git_treebuilder *bld, int (*filter)(const git_tree_entry *, void *), void *payload); +GIT_EXTERN(void) git_treebuilder_filter( + git_treebuilder *bld, + int (*filter)(const git_tree_entry *, void *), + void *payload); /** * Write the contents of the tree builder as a tree object @@ -269,21 +305,24 @@ GIT_EXTERN(void) git_treebuilder_filter(git_treebuilder *bld, int (*filter)(cons GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld); /** - * Retrieve a subtree contained in a tree, given its - * relative path. + * Retrieve a tree entry contained in a tree or in any + * of its subtrees, given its relative path. * - * The returned tree is owned by the repository and - * should be closed with the `git_object_free` method. + * The returned tree entry is owned by the user and must + * be freed manually with `git_tree_entry_free`. * - * @param subtree Pointer where to store the subtree + * @param entry Pointer where to store the tree entry * @param root A previously loaded tree which will be the root of the relative path - * @param subtree_path Path to the contained subtree - * @return 0 on success; GIT_ENOTFOUND if the path does not lead to a subtree + * @param subtree_path Path to the contained entry + * @return 0 on success; GIT_ENOTFOUND if the path does not exist */ -GIT_EXTERN(int) git_tree_get_subtree(git_tree **subtree, git_tree *root, const char *subtree_path); +GIT_EXTERN(int) git_tree_entry_bypath( + git_tree_entry **entry, + git_tree *root, + const char *path); /** Callback for the tree traversal method */ -typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry, void *payload); +typedef int (*git_treewalk_cb)(const char *root, const git_tree_entry *entry, void *payload); /** Tree traversal modes */ enum git_treewalk_mode { diff --git a/src/index.c b/src/index.c index 3fedcd27a..89d479870 100644 --- a/src/index.c +++ b/src/index.c @@ -985,7 +985,7 @@ int git_index_entry_stage(const git_index_entry *entry) return (entry->flags & GIT_IDXENTRY_STAGEMASK) >> GIT_IDXENTRY_STAGESHIFT; } -static int read_tree_cb(const char *root, git_tree_entry *tentry, void *data) +static int read_tree_cb(const char *root, const git_tree_entry *tentry, void *data) { git_index *index = data; git_index_entry *entry = NULL; diff --git a/src/notes.c b/src/notes.c index 0dfd3f891..7813e9985 100644 --- a/src/notes.c +++ b/src/notes.c @@ -97,7 +97,7 @@ static int tree_write( { int error; git_treebuilder *tb = NULL; - git_tree_entry *entry; + const git_tree_entry *entry; git_oid tree_oid; if ((error = git_treebuilder_create(&tb, source_tree)) < 0) diff --git a/src/tree.c b/src/tree.c index 9bdc2180c..8e97f442f 100644 --- a/src/tree.c +++ b/src/tree.c @@ -35,6 +35,22 @@ static int entry_sort_cmp(const void *a, const void *b) entry_b->filename, entry_b->filename_len, git_tree_entry__is_tree(entry_b)); } +static git_tree_entry *alloc_entry(const char *filename) +{ + git_tree_entry *entry = NULL; + size_t filename_len = strlen(filename); + + entry = git__malloc(sizeof(git_tree_entry) + filename_len + 1); + if (!entry) + return NULL; + + memset(entry, 0x0, sizeof(git_tree_entry)); + memcpy(entry->filename, filename, filename_len); + entry->filename[filename_len] = 0; + entry->filename_len = filename_len; + + return entry; +} struct tree_key_search { const char *filename; @@ -76,7 +92,7 @@ static int homing_search_cmp(const void *key, const void *array_member) * ambiguous because of folder vs file sorting, we look linearly * around the area for our target file. */ -static int tree_key_search(git_vector *entries, const char *filename) +static int tree_key_search(git_vector *entries, const char *filename, size_t filename_len) { struct tree_key_search ksearch; const git_tree_entry *entry; @@ -84,7 +100,7 @@ static int tree_key_search(git_vector *entries, const char *filename) int homing, i; ksearch.filename = filename; - ksearch.filename_len = strlen(filename); + ksearch.filename_len = filename_len; /* Initial homing search; find an entry on the tree with * the same prefix as the filename we're looking for */ @@ -100,7 +116,8 @@ static int tree_key_search(git_vector *entries, const char *filename) if (homing_search_cmp(&ksearch, entry) < 0) break; - if (strcmp(filename, entry->filename) == 0) + if (entry->filename_len == filename_len && + memcmp(filename, entry->filename, filename_len) == 0) return i; } @@ -112,7 +129,8 @@ static int tree_key_search(git_vector *entries, const char *filename) if (homing_search_cmp(&ksearch, entry) > 0) break; - if (strcmp(filename, entry->filename) == 0) + if (entry->filename_len == filename_len && + memcmp(filename, entry->filename, filename_len) == 0) return i; } @@ -120,16 +138,35 @@ static int tree_key_search(git_vector *entries, const char *filename) return GIT_ENOTFOUND; } +void git_tree_entry_free(git_tree_entry *entry) +{ + git__free(entry); +} + +git_tree_entry *git_tree_entry_copy(const git_tree_entry *entry) +{ + size_t total_size; + git_tree_entry *copy; + + assert(entry); + + total_size = sizeof(git_tree_entry) + entry->filename_len + 1; + + copy = git__malloc(total_size); + if (!copy) + return NULL; + + memcpy(copy, entry, total_size); + return copy; +} + void git_tree__free(git_tree *tree) { unsigned int i; for (i = 0; i < tree->entries.length; ++i) { - git_tree_entry *e; - e = git_vector_get(&tree->entries, i); - - git__free(e->filename); - git__free(e); + git_tree_entry *e = git_vector_get(&tree->entries, i); + git_tree_entry_free(e); } git_vector_free(&tree->entries); @@ -179,19 +216,21 @@ int git_tree_entry_to_object( return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY); } -const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) +static git_tree_entry *entry_fromname(git_tree *tree, const char *name, size_t name_len) { - int idx; - - assert(tree && filename); - - idx = tree_key_search(&tree->entries, filename); - if (idx == GIT_ENOTFOUND) + int idx = tree_key_search(&tree->entries, name, name_len); + if (idx < 0) return NULL; return git_vector_get(&tree->entries, idx); } +const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) +{ + assert(tree && filename); + return entry_fromname(tree, filename, strlen(filename)); +} + const git_tree_entry *git_tree_entry_byindex(git_tree *tree, unsigned int idx) { assert(tree); @@ -244,28 +283,28 @@ static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buf while (buffer < buffer_end) { git_tree_entry *entry; - int tmp; + int attr; - entry = git__calloc(1, sizeof(git_tree_entry)); - GITERR_CHECK_ALLOC(entry); - - if (git_vector_insert(&tree->entries, entry) < 0) - return -1; - - if (git__strtol32(&tmp, buffer, &buffer, 8) < 0 || - !buffer || !valid_attributes(tmp)) + if (git__strtol32(&attr, buffer, &buffer, 8) < 0 || + !buffer || !valid_attributes(attr)) return tree_error("Failed to parse tree. Can't parse attributes"); - entry->attr = tmp; - if (*buffer++ != ' ') return tree_error("Failed to parse tree. Object is corrupted"); if (memchr(buffer, 0, buffer_end - buffer) == NULL) return tree_error("Failed to parse tree. Object is corrupted"); - entry->filename = git__strdup(buffer); - entry->filename_len = strlen(buffer); + /** Allocate the entry and store it in the entries vector */ + { + entry = alloc_entry(buffer); + GITERR_CHECK_ALLOC(entry); + + if (git_vector_insert(&tree->entries, entry) < 0) + return -1; + + entry->attr = attr; + } while (buffer < buffer_end && *buffer != 0) buffer++; @@ -303,16 +342,17 @@ static unsigned int find_next_dir(const char *dirname, git_index *index, unsigne return i; } -static int append_entry(git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) +static int append_entry( + git_treebuilder *bld, + const char *filename, + const git_oid *id, + unsigned int attributes) { git_tree_entry *entry; - entry = git__calloc(1, sizeof(git_tree_entry)); + entry = alloc_entry(filename); GITERR_CHECK_ALLOC(entry); - entry->filename = git__strdup(filename); - entry->filename_len = strlen(entry->filename); - git_oid_cpy(&entry->oid, id); entry->attr = attributes; @@ -488,7 +528,12 @@ on_error: return -1; } -int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) +int git_treebuilder_insert( + const git_tree_entry **entry_out, + git_treebuilder *bld, + const char *filename, + const git_oid *id, + unsigned int attributes) { git_tree_entry *entry; int pos; @@ -501,30 +546,28 @@ int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, con if (!valid_entry_name(filename)) return tree_error("Failed to insert entry. Invalid name for a tree entry"); - pos = tree_key_search(&bld->entries, filename); + pos = tree_key_search(&bld->entries, filename, strlen(filename)); if (pos >= 0) { entry = git_vector_get(&bld->entries, pos); if (entry->removed) entry->removed = 0; } else { - entry = git__calloc(1, sizeof(git_tree_entry)); + entry = alloc_entry(filename); GITERR_CHECK_ALLOC(entry); - - entry->filename = git__strdup(filename); - entry->filename_len = strlen(entry->filename); } git_oid_cpy(&entry->oid, id); entry->attr = attributes; - if (pos == GIT_ENOTFOUND) { + if (pos < 0) { if (git_vector_insert(&bld->entries, entry) < 0) return -1; } - if (entry_out != NULL) + if (entry_out != NULL) { *entry_out = entry; + } return 0; } @@ -536,7 +579,7 @@ static git_tree_entry *treebuilder_get(git_treebuilder *bld, const char *filenam assert(bld && filename); - idx = tree_key_search(&bld->entries, filename); + idx = tree_key_search(&bld->entries, filename, strlen(filename)); if (idx < 0) return NULL; @@ -625,8 +668,7 @@ void git_treebuilder_clear(git_treebuilder *bld) for (i = 0; i < bld->entries.length; ++i) { git_tree_entry *e = bld->entries.contents[i]; - git__free(e->filename); - git__free(e); + git_tree_entry_free(e); } git_vector_clear(&bld->entries); @@ -642,85 +684,78 @@ void git_treebuilder_free(git_treebuilder *bld) git__free(bld); } -static int tree_frompath( - git_tree **parent_out, - git_tree *root, - git_buf *treeentry_path, - size_t offset) +static size_t subpath_len(const char *path) +{ + const char *slash_pos = strchr(path, '/'); + if (slash_pos == NULL) + return strlen(path); + + return slash_pos - path; +} + +int git_tree_entry_bypath( + git_tree_entry **entry_out, + git_tree *root, + const char *path) { - char *slash_pos = NULL; - const git_tree_entry* entry; int error = 0; git_tree *subtree; + const git_tree_entry *entry; + size_t filename_len; - if (!*(treeentry_path->ptr + offset)) { - giterr_set(GITERR_INVALID, - "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr); - return -1; - } + /* Find how long is the current path component (i.e. + * the filename between two slashes */ + filename_len = subpath_len(path); - slash_pos = (char *)strchr(treeentry_path->ptr + offset, '/'); - - if (slash_pos == NULL) - return git_tree_lookup( - parent_out, - root->object.repo, - git_object_id((const git_object *)root) - ); - - if (slash_pos == treeentry_path->ptr + offset) { - giterr_set(GITERR_INVALID, - "Invalid relative path to a tree entry '%s'.", treeentry_path->ptr); - return -1; - } - - *slash_pos = '\0'; - - entry = git_tree_entry_byname(root, treeentry_path->ptr + offset); - - if (slash_pos != NULL) - *slash_pos = '/'; - - if (entry == NULL) { - giterr_set(GITERR_TREE, - "No tree entry can be found from " - "the given tree and relative path '%s'.", treeentry_path->ptr); + if (filename_len == 0) { + giterr_set(GITERR_TREE, "Invalid tree path given"); return GIT_ENOTFOUND; } + entry = entry_fromname(root, path, filename_len); + + if (entry == NULL) { + giterr_set(GITERR_TREE, + "The path '%s' does not exist in the given tree", path); + return GIT_ENOTFOUND; + } + + switch (path[filename_len]) { + case '/': + /* If there are more components in the path... + * then this entry *must* be a tree */ + if (!git_tree_entry__is_tree(entry)) { + giterr_set(GITERR_TREE, + "The path '%s' does not exist in the given tree", path); + return -1; + } + + /* If there's only a slash left in the path, we + * return the current entry; otherwise, we keep + * walking down the path */ + if (path[filename_len + 1] != '\0') + break; + + case '\0': + /* If there are no more components in the path, return + * this entry */ + *entry_out = git_tree_entry_copy(entry); + return 0; + } if (git_tree_lookup(&subtree, root->object.repo, &entry->oid) < 0) - return error; + return -1; - error = tree_frompath( - parent_out, + error = git_tree_entry_bypath( + entry_out, subtree, - treeentry_path, - (slash_pos - treeentry_path->ptr) + 1 + path + filename_len + 1 ); git_tree_free(subtree); return error; } -int git_tree_get_subtree( - git_tree **subtree, - git_tree *root, - const char *subtree_path) -{ - int error; - git_buf buffer = GIT_BUF_INIT; - - assert(subtree && root && subtree_path); - - if ((error = git_buf_sets(&buffer, subtree_path)) == 0) - error = tree_frompath(subtree, root, &buffer, 0); - - git_buf_free(&buffer); - - return error; -} - static int tree_walk_post( git_tree *tree, git_treewalk_cb callback, diff --git a/src/tree.h b/src/tree.h index 498a90d66..c49309cbc 100644 --- a/src/tree.h +++ b/src/tree.h @@ -13,11 +13,11 @@ #include "vector.h" struct git_tree_entry { - unsigned int attr; - char *filename; + uint16_t removed; + uint16_t attr; git_oid oid; size_t filename_len; - int removed; + char filename[1]; }; struct git_tree { diff --git a/tests-clar/object/tree/frompath.c b/tests-clar/object/tree/frompath.c index 06c69ac08..853af4306 100644 --- a/tests-clar/object/tree/frompath.c +++ b/tests-clar/object/tree/frompath.c @@ -1,15 +1,14 @@ #include "clar_libgit2.h" static git_repository *repo; -const char *tree_with_subtrees_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; static git_tree *tree; void test_object_tree_frompath__initialize(void) { git_oid id; + const char *tree_with_subtrees_oid = "ae90f12eea699729ed24555e40b9fd669da12a12"; - cl_fixture_sandbox("testrepo.git"); - cl_git_pass(git_repository_open(&repo, "testrepo.git")); + cl_git_pass(git_repository_open(&repo, cl_fixture("testrepo.git"))); cl_assert(repo != NULL); cl_git_pass(git_oid_fromstr(&id, tree_with_subtrees_oid)); @@ -24,58 +23,44 @@ void test_object_tree_frompath__cleanup(void) cl_fixture_cleanup("testrepo.git"); } -static void assert_tree_from_path(git_tree *root, const char *path, int expected_result, const char *expected_raw_oid) +static void assert_tree_from_path( + git_tree *root, + const char *path, + const char *expected_entry_name) { - git_tree *containing_tree = NULL; + git_tree_entry *entry; - cl_assert(git_tree_get_subtree(&containing_tree, root, path) == expected_result); - - if (containing_tree == NULL && expected_result != 0) - return; - - 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)); - - git_tree_free(containing_tree); -} - -static void assert_tree_from_path_klass(git_tree *root, const char *path, int expected_result, const char *expected_raw_oid) -{ - assert_tree_from_path(root, path, GIT_ERROR, expected_raw_oid); - cl_assert(giterr_last()->klass == expected_result); + cl_git_pass(git_tree_entry_bypath(&entry, root, path)); + cl_assert_equal_s(git_tree_entry_name(entry), expected_entry_name); + git_tree_entry_free(entry); } 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", 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", 0, tree_with_subtrees_oid); - - /* Will return fgh tree oid given this following path... */ - 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", 0, "f1425cef211cc08caa31e7b545ffb232acb098c3"); + git_tree_entry *e; - /* 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", 0, "3259a6bd5b57fb9c1281bb7ed3167b50f224cb54"); -} + assert_tree_from_path(tree, "README", "README"); + assert_tree_from_path(tree, "ab/de/fgh/1.txt", "1.txt"); + assert_tree_from_path(tree, "ab/de/fgh", "fgh"); + assert_tree_from_path(tree, "ab/de/fgh/", "fgh"); + assert_tree_from_path(tree, "ab/de", "de"); + assert_tree_from_path(tree, "ab/", "ab"); + assert_tree_from_path(tree, "ab/de/", "de"); -void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void) -{ - assert_tree_from_path(tree, "nope/de/fgh/1.txt", GIT_ENOTFOUND, NULL); - assert_tree_from_path(tree, "ab/me-neither/fgh/2.txt", GIT_ENOTFOUND, NULL); + cl_must_fail(git_tree_entry_bypath(&e, tree, "i-do-not-exist.txt")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "README/")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/de/fgh/i-do-not-exist.txt")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "nope/de/fgh/1.txt")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt/")); } void test_object_tree_frompath__fail_when_processing_an_invalid_path(void) { - assert_tree_from_path_klass(tree, "/", GITERR_INVALID, NULL); - assert_tree_from_path_klass(tree, "/ab", GITERR_INVALID, NULL); - assert_tree_from_path_klass(tree, "/ab/de", GITERR_INVALID, NULL); - assert_tree_from_path_klass(tree, "ab/", GITERR_INVALID, NULL); - assert_tree_from_path_klass(tree, "ab//de", GITERR_INVALID, NULL); - assert_tree_from_path_klass(tree, "ab/de/", GITERR_INVALID, NULL); + git_tree_entry *e; + + cl_must_fail(git_tree_entry_bypath(&e, tree, "/")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "/ab/de")); + cl_must_fail(git_tree_entry_bypath(&e, tree, "ab//de")); } From 7e8c146c6b78fe5b9d26f059e381b978260984f4 Mon Sep 17 00:00:00 2001 From: "Scott J. Goldman" Date: Fri, 29 Jun 2012 00:47:46 -0700 Subject: [PATCH 055/123] Don't rmdir() nonexistent dirs in object::tree::frompath tests It causes the clar testsuite to abort on Windows, and isn't necessary. --- tests-clar/object/tree/frompath.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tests-clar/object/tree/frompath.c b/tests-clar/object/tree/frompath.c index 853af4306..ef092d1db 100644 --- a/tests-clar/object/tree/frompath.c +++ b/tests-clar/object/tree/frompath.c @@ -20,7 +20,6 @@ void test_object_tree_frompath__cleanup(void) { git_tree_free(tree); git_repository_free(repo); - cl_fixture_cleanup("testrepo.git"); } static void assert_tree_from_path( From 46ea40d9955a171187d252872f5c9bac1da7e286 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Fri, 29 Jun 2012 17:08:36 +0200 Subject: [PATCH 056/123] tree: Rename `entry_copy` to `entry_dup` --- include/git2/tree.h | 4 ++-- src/tree.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/git2/tree.h b/include/git2/tree.h index 107c771c4..f12b15e2e 100644 --- a/include/git2/tree.h +++ b/include/git2/tree.h @@ -76,7 +76,7 @@ GIT_INLINE(void) git_tree_free(git_tree *tree) * * IMPORTANT: This function is only needed for tree * entries owned by the user, such as the ones returned - * by `git_tree_entry_copy`. + * by `git_tree_entry_dup`. * * @param entry The entry to free */ @@ -92,7 +92,7 @@ GIT_EXTERN(void) git_tree_entry_free(git_tree_entry *entry); * @param entry A tree entry to duplicate * @return a copy of the original entry */ -GIT_EXTERN(git_tree_entry *) git_tree_entry_copy(const git_tree_entry *entry); +GIT_EXTERN(git_tree_entry *) git_tree_entry_dup(const git_tree_entry *entry); /** * Get the id of a tree. diff --git a/src/tree.c b/src/tree.c index 8e97f442f..b609eea33 100644 --- a/src/tree.c +++ b/src/tree.c @@ -143,7 +143,7 @@ void git_tree_entry_free(git_tree_entry *entry) git__free(entry); } -git_tree_entry *git_tree_entry_copy(const git_tree_entry *entry) +git_tree_entry *git_tree_entry_dup(const git_tree_entry *entry) { size_t total_size; git_tree_entry *copy; @@ -739,7 +739,7 @@ int git_tree_entry_bypath( case '\0': /* If there are no more components in the path, return * this entry */ - *entry_out = git_tree_entry_copy(entry); + *entry_out = git_tree_entry_dup(entry); return 0; } From 4de89ce72aa66fe2141f973960c3baf1e373a827 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 29 Jun 2012 16:51:46 +0200 Subject: [PATCH 057/123] revparse: unfound partially-named ref returns ENOTFOUND --- src/revparse.c | 2 +- tests-clar/refs/revparse.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 5050bdf1b..b895b9067 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -107,7 +107,7 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const git_buf_free(&refnamebuf); giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); - return GIT_ERROR; + return GIT_ENOTFOUND; } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index c71e6d844..7c5c917de 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -38,10 +38,9 @@ void test_refs_revparse__cleanup(void) cl_setenv("TZ", g_orig_tz); } - void test_refs_revparse__nonexistant_object(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "this doesn't exist")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist^1")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist~2")); } From 08ac23a5fd3f237f3e028dbdfc4e49133bb53a2e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 29 Jun 2012 17:02:29 +0200 Subject: [PATCH 058/123] revparse: unfound reflog ref returns ENOTFOUND --- src/revparse.c | 5 +++-- tests-clar/refs/revparse.c | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index b895b9067..dab74d66a 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -29,9 +29,10 @@ static void set_invalid_syntax_err(const char *spec) static int revparse_lookup_fully_qualifed_ref(git_object **out, git_repository *repo, const char*spec) { git_oid resolved; + int error; - if (git_reference_name_to_oid(&resolved, repo, spec) < 0) - return GIT_ERROR; + if ((error = git_reference_name_to_oid(&resolved, repo, spec)) < 0) + return error; return git_object_lookup(out, repo, &resolved, GIT_OBJ_ANY); } diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 7c5c917de..68479962d 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -128,6 +128,8 @@ void test_refs_revparse__reflog(void) cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "nope@{0}")); + test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); From 52b938d55a0619abb3b8f8b7b450a140f560a6d4 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 29 Jun 2012 17:06:38 +0200 Subject: [PATCH 059/123] revparse: unfound reflog entry returns ENOTFOUND --- src/revparse.c | 2 +- tests-clar/refs/revparse.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/revparse.c b/src/revparse.c index dab74d66a..774beef63 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -245,7 +245,7 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * if (numentries < n) { giterr_set(GITERR_REFERENCE, "Reflog for '%s' has only %d entries, asked for %d", git_buf_cstr(&buf), numentries, n); - retcode = GIT_ERROR; + retcode = GIT_ENOTFOUND; } else { const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, n); const git_oid *oid = git_reflog_entry_oidold(entry); diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 68479962d..d28dfa5fd 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -129,6 +129,7 @@ void test_refs_revparse__reflog(void) cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "nope@{0}")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{31415}")); test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); From 29f9186d1b772994f65bb87ac88180d7d9d4141b Mon Sep 17 00:00:00 2001 From: yorah Date: Mon, 2 Jul 2012 11:18:01 +0200 Subject: [PATCH 060/123] diff: make inter-hunk-context default value git-compliant Default in git core is 0, not 3 --- include/git2/diff.h | 2 +- src/diff_output.c | 2 +- tests-clar/diff/blob.c | 70 ++++++++++++++++-- tests-clar/diff/iterator.c | 4 +- tests-clar/resources/attr/.gitted/index | Bin 1856 -> 1856 bytes tests-clar/resources/attr/.gitted/logs/HEAD | 1 + .../attr/.gitted/logs/refs/heads/master | 1 + .../16/983da6643656bb44c43965ecb6855c6d574512 | Bin 0 -> 446 bytes .../8d/0b9df9bd30be7910ddda60548d485bc302b911 | 1 + .../a0/f7217ae99f5ac3e88534f5cea267febc5fa85b | 1 + .../resources/attr/.gitted/refs/heads/master | 2 +- tests-clar/resources/attr/root_test4.txt | 4 +- 12 files changed, 76 insertions(+), 12 deletions(-) create mode 100644 tests-clar/resources/attr/.gitted/objects/16/983da6643656bb44c43965ecb6855c6d574512 create mode 100644 tests-clar/resources/attr/.gitted/objects/8d/0b9df9bd30be7910ddda60548d485bc302b911 create mode 100644 tests-clar/resources/attr/.gitted/objects/a0/f7217ae99f5ac3e88534f5cea267febc5fa85b diff --git a/include/git2/diff.h b/include/git2/diff.h index d4d0eac47..edec9957b 100644 --- a/include/git2/diff.h +++ b/include/git2/diff.h @@ -60,7 +60,7 @@ enum { typedef struct { uint32_t flags; /**< defaults to GIT_DIFF_NORMAL */ uint16_t context_lines; /**< defaults to 3 */ - uint16_t interhunk_lines; /**< defaults to 3 */ + uint16_t interhunk_lines; /**< defaults to 0 */ char *old_prefix; /**< defaults to "a" */ char *new_prefix; /**< defaults to "b" */ git_strarray pathspec; /**< defaults to show all paths */ diff --git a/src/diff_output.c b/src/diff_output.c index 92f7f8f2f..f6650b345 100644 --- a/src/diff_output.c +++ b/src/diff_output.c @@ -212,7 +212,7 @@ static void setup_xdiff_options( cfg->ctxlen = (!opts || !opts->context_lines) ? 3 : opts->context_lines; cfg->interhunkctxlen = - (!opts || !opts->interhunk_lines) ? 3 : opts->interhunk_lines; + (!opts) ? 0 : opts->interhunk_lines; if (!opts) return; diff --git a/tests-clar/diff/blob.c b/tests-clar/diff/blob.c index 6d7ad41d6..5d3ab8d56 100644 --- a/tests-clar/diff/blob.c +++ b/tests-clar/diff/blob.c @@ -14,13 +14,13 @@ void test_diff_blob__initialize(void) memset(&opts, 0, sizeof(opts)); opts.context_lines = 1; - opts.interhunk_lines = 1; + opts.interhunk_lines = 0; memset(&expected, 0, sizeof(expected)); /* tests/resources/attr/root_test4.txt */ - cl_git_pass(git_oid_fromstrn(&oid, "fe773770c5a6", 12)); - cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 6)); + cl_git_pass(git_oid_fromstrn(&oid, "a0f7217a", 8)); + cl_git_pass(git_blob_lookup_prefix(&d, g_repo, &oid, 4)); /* alien.png */ cl_git_pass(git_oid_fromstrn(&oid, "edf3dcee", 8)); @@ -54,6 +54,7 @@ void test_diff_blob__can_compare_text_blobs(void) /* Doing the equivalent of a `git diff -U1` on these files */ + /* diff on tests/resources/attr/root_test1 */ cl_git_pass(git_diff_blobs( a, b, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); @@ -67,6 +68,7 @@ void test_diff_blob__can_compare_text_blobs(void) cl_assert(expected.line_adds == 5); cl_assert(expected.line_dels == 0); + /* diff on tests/resources/attr/root_test2 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( b, c, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); @@ -81,6 +83,7 @@ void test_diff_blob__can_compare_text_blobs(void) cl_assert(expected.line_adds == 9); cl_assert(expected.line_dels == 3); + /* diff on tests/resources/attr/root_test3 */ memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( a, c, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); @@ -95,8 +98,6 @@ void test_diff_blob__can_compare_text_blobs(void) cl_assert(expected.line_adds == 12); cl_assert(expected.line_dels == 1); - opts.context_lines = 1; - memset(&expected, 0, sizeof(expected)); cl_git_pass(git_diff_blobs( c, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); @@ -252,3 +253,62 @@ void test_diff_blob__can_compare_a_binary_blob_and_a_text_blob(void) assert_binary_blobs_comparison(expected); } + +/* + * $ git diff fe773770 a0f7217 + * diff --git a/fe773770 b/a0f7217 + * index fe77377..a0f7217 100644 + * --- a/fe773770 + * +++ b/a0f7217 + * @@ -1,6 +1,6 @@ + * Here is some stuff at the start + * + * -This should go in one hunk + * +This should go in one hunk (first) + * + * Some additional lines + * + * @@ -8,7 +8,7 @@ Down here below the other lines + * + * With even more at the end + * + * -Followed by a second hunk of stuff + * +Followed by a second hunk of stuff (second) + * + * That happens down here + */ +void test_diff_blob__comparing_two_text_blobs_honors_interhunkcontext(void) +{ + git_blob *old_d; + git_oid old_d_oid; + + opts.context_lines = 3; + + /* tests/resources/attr/root_test1 from commit f5b0af1 */ + cl_git_pass(git_oid_fromstrn(&old_d_oid, "fe773770", 8)); + cl_git_pass(git_blob_lookup_prefix(&old_d, g_repo, &old_d_oid, 4)); + + /* Test with default inter-hunk-context (not set) => default is 0 */ + cl_git_pass(git_diff_blobs( + old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); + + cl_assert(expected.hunks == 2); + + /* Test with inter-hunk-context explicitly set to 0 */ + opts.interhunk_lines = 0; + memset(&expected, 0, sizeof(expected)); + cl_git_pass(git_diff_blobs( + old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); + + cl_assert(expected.hunks == 2); + + /* Test with inter-hunk-context explicitly set to 1 */ + opts.interhunk_lines = 1; + memset(&expected, 0, sizeof(expected)); + cl_git_pass(git_diff_blobs( + old_d, d, &opts, &expected, diff_file_fn, diff_hunk_fn, diff_line_fn)); + + cl_assert(expected.hunks == 1); + + git_blob_free(old_d); +} diff --git a/tests-clar/diff/iterator.c b/tests-clar/diff/iterator.c index eee84810a..c27d3fa6c 100644 --- a/tests-clar/diff/iterator.c +++ b/tests-clar/diff/iterator.c @@ -312,7 +312,7 @@ static const char *expected_index_oids_0[] = { "45141a79a77842c59a63229403220a4e4be74e3d", "4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d", "108bb4e7fd7b16490dc33ff7d972151e73d7166e", - "fe773770c5a6cc7185580c9204b1ff18a33ff3fc", + "a0f7217ae99f5ac3e88534f5cea267febc5fa85b", "3e42ffc54a663f9401cc25843d6c0e71a33e4249", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057", @@ -343,7 +343,7 @@ static const char *expected_index_oids_range[] = { "45141a79a77842c59a63229403220a4e4be74e3d", "4d713dc48e6b1bd75b0d61ad078ba9ca3a56745d", "108bb4e7fd7b16490dc33ff7d972151e73d7166e", - "fe773770c5a6cc7185580c9204b1ff18a33ff3fc", + "a0f7217ae99f5ac3e88534f5cea267febc5fa85b", }; void test_diff_iterator__index_range(void) diff --git a/tests-clar/resources/attr/.gitted/index b/tests-clar/resources/attr/.gitted/index index 1d60eab8fae80006d0f7b493ab1c815fadcd417d..943e2243e2fa9414886669bdb45e54ba4d7808ea 100644 GIT binary patch delta 784 zcmX@WcYx2p#WTp6fq{Vuh{gR^w;u-53@{qRhJeN;FxEr^Rb^t7RS>7_08z>&b1)L8 zE`YI=7}rgHL8N&GOu9sw*FdDY3q-0@VAidNh4RNfc39w}M+T68cfohXs+aSl4!>wM z`Fd_q`oBH#E20_rit_VI;!9GCOHA}iDoQ~5V37)=A!dO{MC39su-vtC`hV0b&3?+{ zGt81i`8|L|QlF!^G)X@#GbfcednO045ErfsSWJm>!w+K3W0TyR$aFsG1{lr9z`()~?5@nf(71$wf$=L)N@Svesxo$E zDk#b-a4AzoQFZ{AGN3~cmQLni#HCIhMO^@6DGt}^p{RR-(>#3?bp}kjILtFZQP+S| zogs?43pmvop{P?})=kGA%Erj*fDv-$U%7d~(Pd`}TO)WTv26S=vDp6e9|pdn{QQ#m zlGNf76TOm(668oli(IqGZ&+0)-(=>&;ZI9s`z8mlNa}MGmnP|_W#*(J5(=7`c4&HV zg`qu)x&@~ diff --git a/tests-clar/resources/attr/.gitted/logs/HEAD b/tests-clar/resources/attr/.gitted/logs/HEAD index 73f00f345..8ece39f37 100644 --- a/tests-clar/resources/attr/.gitted/logs/HEAD +++ b/tests-clar/resources/attr/.gitted/logs/HEAD @@ -6,3 +6,4 @@ a5d76cad53f66f1312bd995909a5bab3c0820770 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6 f5b0af1fb4f5c0cd7aad880711d368a07333c307 a97cc019851d401a4f1d091cb91a15890a0dd1ba Russell Belfer 1328653313 -0800 commit: Some whitespace only changes for testing purposes a97cc019851d401a4f1d091cb91a15890a0dd1ba 217878ab49e1314388ea2e32dc6fdb58a1b969e0 Russell Belfer 1332734901 -0700 commit: added files in sub/sub 217878ab49e1314388ea2e32dc6fdb58a1b969e0 24fa9a9fc4e202313e24b648087495441dab432b Russell Belfer 1332735555 -0700 commit: adding more files in sub for tree status +24fa9a9fc4e202313e24b648087495441dab432b 8d0b9df9bd30be7910ddda60548d485bc302b911 yorah 1341230701 +0200 commit: Updating test data so we can test inter-hunk-context diff --git a/tests-clar/resources/attr/.gitted/logs/refs/heads/master b/tests-clar/resources/attr/.gitted/logs/refs/heads/master index 73f00f345..8ece39f37 100644 --- a/tests-clar/resources/attr/.gitted/logs/refs/heads/master +++ b/tests-clar/resources/attr/.gitted/logs/refs/heads/master @@ -6,3 +6,4 @@ a5d76cad53f66f1312bd995909a5bab3c0820770 370fe9ec224ce33e71f9e5ec2bd1142ce9937a6 f5b0af1fb4f5c0cd7aad880711d368a07333c307 a97cc019851d401a4f1d091cb91a15890a0dd1ba Russell Belfer 1328653313 -0800 commit: Some whitespace only changes for testing purposes a97cc019851d401a4f1d091cb91a15890a0dd1ba 217878ab49e1314388ea2e32dc6fdb58a1b969e0 Russell Belfer 1332734901 -0700 commit: added files in sub/sub 217878ab49e1314388ea2e32dc6fdb58a1b969e0 24fa9a9fc4e202313e24b648087495441dab432b Russell Belfer 1332735555 -0700 commit: adding more files in sub for tree status +24fa9a9fc4e202313e24b648087495441dab432b 8d0b9df9bd30be7910ddda60548d485bc302b911 yorah 1341230701 +0200 commit: Updating test data so we can test inter-hunk-context diff --git a/tests-clar/resources/attr/.gitted/objects/16/983da6643656bb44c43965ecb6855c6d574512 b/tests-clar/resources/attr/.gitted/objects/16/983da6643656bb44c43965ecb6855c6d574512 new file mode 100644 index 0000000000000000000000000000000000000000..e49c94acdaa60287fbaeb2e98bcfab43710b327d GIT binary patch literal 446 zcmV;v0YUzF0V^p=O;s>8He)a}FfcPQQAjK)DKcOP&F^Wd?(mk!9N4*WOR^9COxTOtMRg|A! z5)V>j$lxj>Rk^&v>FBIvr76rxTz=lq{cO=y88P@4+8*i4mcAa%o4A&}d*vysu##AG zRmKbg-CLgjtrqj-J#7E|W|62|@pZ90bX6vLB^4zM3%)B>y__F)_(iM9*K>=~|Luui z5p7}s1PaBaNepjx)_z)8GNYt)O=F&g`=7q~Ig#0L*_6y8hWT5#(@O6?;|`m?{@l8W o+j1xLFx^B}V8o!Qc~3*<<;<6X&FgL*bCor237z8&0JNyxfdtg*5dZ)H literal 0 HcmV?d00001 diff --git a/tests-clar/resources/attr/.gitted/objects/8d/0b9df9bd30be7910ddda60548d485bc302b911 b/tests-clar/resources/attr/.gitted/objects/8d/0b9df9bd30be7910ddda60548d485bc302b911 new file mode 100644 index 000000000..3dcf088e4 --- /dev/null +++ b/tests-clar/resources/attr/.gitted/objects/8d/0b9df9bd30be7910ddda60548d485bc302b911 @@ -0,0 +1 @@ +xŽKj1D³Ö)zolôiõŒ _"hiÚK2²L’ÛG!7Ȫ¯¨ÔJÉ,ù—ÑEÀPXÝÆDèÈSŒˆ ] /)Òê}¢Í/èUwîR§ˆ. Åj댋‘pÕë‚Á#š#:?ÇÞ:|·Î;¼þF9íÜ‹Ür=_ çÛ)µòÆ¡±N/ÚÀA[­ÕlçÃ!ÿqÕû}ã‘ë†<Lfx4øH\ÿº\çôqÖcj“¿†úƒTè \ No newline at end of file diff --git a/tests-clar/resources/attr/.gitted/objects/a0/f7217ae99f5ac3e88534f5cea267febc5fa85b b/tests-clar/resources/attr/.gitted/objects/a0/f7217ae99f5ac3e88534f5cea267febc5fa85b new file mode 100644 index 000000000..985c2e281 --- /dev/null +++ b/tests-clar/resources/attr/.gitted/objects/a0/f7217ae99f5ac3e88534f5cea267febc5fa85b @@ -0,0 +1 @@ +x5Ž1Â0 E™}Š?–΀;•˜SâˆÔ®’”ŠÛ“Ðv´ýߢ8ŸO‡'FÈÈ:2r™ƒ)(¾ &¢Þ·«×9Z¼A Âð³¼Ñ¹r9Ýl¬ %¨˜ˆ„3ÑEo‚£.ÿV­Õi Date: Mon, 2 Jul 2012 17:51:02 +0200 Subject: [PATCH 061/123] revparse: fix parsing of date specifiers --- src/revparse.c | 23 +++--------- src/util.h | 7 ---- tests-clar/refs/revparse.c | 73 ++++++++++++++++++++++++++++++++++---- 3 files changed, 71 insertions(+), 32 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 774beef63..8c15f46c6 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -267,31 +267,18 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * int numentries = git_reflog_entrycount(reflog); int i; - /* TODO: clunky. Factor "now" into a utility */ - git_signature *sig; - git_time as_of; - - git_signature_now(&sig, "blah", "blah"); - as_of = sig->when; - git_signature_free(sig); - - as_of.time = (timestamp > 0) - ? timestamp - : sig->when.time + timestamp; - - for (i=numentries-1; i>0; i--) { + for (i = numentries - 1; i >= 0; i--) { const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); git_time commit_time = git_reflog_entry_committer(entry)->when; - if (git__time_cmp(&commit_time, &as_of) <= 0 ) { + if (commit_time.time - timestamp <= 0) { retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); break; } } - if (!i) { - /* Didn't find a match. Use the oldest revision in the reflog. */ - const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, 0); - retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); + if (i == -1) { + /* Didn't find a match */ + retcode = GIT_ENOTFOUND; } git_reflog_free(reflog); diff --git a/src/util.h b/src/util.h index eed2bc80c..adc665027 100644 --- a/src/util.h +++ b/src/util.h @@ -209,13 +209,6 @@ GIT_INLINE(bool) git__isspace(int c) return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); } -GIT_INLINE(int) git__time_cmp(const git_time *a, const git_time *b) -{ - /* Adjust for time zones. Times are in seconds, offsets are in minutes. */ - git_time_t adjusted_a = a->time + ((b->offset - a->offset) * 60); - return (int)(adjusted_a - b->time); -} - GIT_INLINE(bool) git__iswildcard(int c) { return (c == '*' || c == '?' || c == '['); diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index d28dfa5fd..e282cd710 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -155,14 +155,73 @@ void test_refs_revparse__revwalk(void) void test_refs_revparse__date(void) { - test_object("HEAD@{10 years ago}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{2012-4-30 10:23:20 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{2012-4-30 18:24 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{2012-4-30 23:24 -0300}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + /* + * $ git reflog HEAD --date=iso + * a65fedf HEAD@{2012-04-30 08:23:41 -0900}: checkout: moving from br2 to master + * a4a7dce HEAD@{2012-04-30 08:23:37 -0900}: commit: checking in + * c47800c HEAD@{2012-04-30 08:23:28 -0900}: checkout: moving from master to br2 + * a65fedf HEAD@{2012-04-30 08:23:23 -0900}: commit: + * be3563a HEAD@{2012-04-30 10:22:43 -0700}: clone: from /Users/ben/src/libgit2/tes + * + * $ git reflog HEAD --date=raw + * a65fedf HEAD@{1335806621 -0900}: checkout: moving from br2 to master + * a4a7dce HEAD@{1335806617 -0900}: commit: checking in + * c47800c HEAD@{1335806608 -0900}: checkout: moving from master to br2 + * a65fedf HEAD@{1335806603 -0900}: commit: + * be3563a HEAD@{1335806563 -0700}: clone: from /Users/ben/src/libgit2/tests/resour + */ + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "HEAD@{10 years ago}")); - /* Core git gives a65fedf, because they don't take time zones into account. */ - test_object("master@{1335806640}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("HEAD@{1 second ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("HEAD@{2 days ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + + /* + * $ git reflog master --date=iso + * a65fedf master@{2012-04-30 09:23:23 -0800}: commit: checking in + * be3563a master@{2012-04-30 09:22:43 -0800}: clone: from /Users/ben/src... + * + * $ git reflog master --date=raw + * a65fedf master@{1335806603 -0800}: commit: checking in + * be3563a master@{1335806563 -0800}: clone: from /Users/ben/src/libgit2/tests/reso + */ + + + /* + * $ git reflog -1 "master@{2012-04-30 17:22:42 +0000}" + * warning: Log for 'master' only goes back to Mon, 30 Apr 2012 09:22:43 -0800. + */ + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{2012-04-30 17:22:42 +0000}")); + cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{2012-04-30 09:22:42 -0800}")); + + /* + * $ git reflog -1 "master@{2012-04-30 17:22:43 +0000}" + * be3563a master@{Mon Apr 30 09:22:43 2012 -0800}: clone: from /Users/ben/src/libg + */ + test_object("master@{2012-04-30 17:22:43 +0000}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master@{2012-04-30 09:22:43 -0800}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + + /* + * $ git reflog -1 "master@{2012-4-30 09:23:27 -0800}" + * a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in + */ + test_object("master@{2012-4-30 09:23:27 -0800}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + + /* + * $ git reflog -1 master@{2012-05-03} + * a65fedf master@{Mon Apr 30 09:23:23 2012 -0800}: commit: checking in + */ + test_object("master@{2012-05-03}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + + /* + * $ git reflog -1 "master@{1335806603}" + * a65fedf + * + * $ git reflog -1 "master@{1335806602}" + * be3563a + */ + test_object("master@{1335806603}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master@{1335806602}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } void test_refs_revparse__colon(void) From 973ed4c9f02a036a7eb706a8eab9ba32d0cdf4a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 3 Jul 2012 12:11:19 +0200 Subject: [PATCH 062/123] repo tests: do cleanup reinit tests --- tests-clar/repo/init.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests-clar/repo/init.c b/tests-clar/repo/init.c index 556a22b6f..3d37c3754 100644 --- a/tests-clar/repo/init.c +++ b/tests-clar/repo/init.c @@ -234,6 +234,7 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) int current_value; /* Init a new repo */ + cl_set_cleanup(&cleanup_repository, "not.overwrite.git"); cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); /* Change the "core.ignorecase" config value to something unlikely */ @@ -241,6 +242,7 @@ void test_repo_init__reinit_doesnot_overwrite_ignorecase(void) git_config_set_int32(config, "core.ignorecase", 42); git_config_free(config); git_repository_free(_repo); + _repo = NULL; /* Reinit the repository */ cl_git_pass(git_repository_init(&_repo, "not.overwrite.git", 1)); @@ -265,13 +267,16 @@ void test_repo_init__reinit_overwrites_filemode(void) #endif /* Init a new repo */ + cl_set_cleanup(&cleanup_repository, "overwrite.git"); cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); + /* Change the "core.filemode" config value to something unlikely */ git_repository_config(&config, _repo); git_config_set_bool(config, "core.filemode", !expected); git_config_free(config); git_repository_free(_repo); + _repo = NULL; /* Reinit the repository */ cl_git_pass(git_repository_init(&_repo, "overwrite.git", 1)); From 521aedad307c6f72d6f6d660943508b2b015f6dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 5 Jun 2012 14:48:51 +0200 Subject: [PATCH 063/123] odb: add git_odb_foreach() Go through each backend and list every objects that exists in them. This allows fsck-like uses. --- include/git2/odb.h | 14 +++++++ include/git2/odb_backend.h | 6 +++ src/odb.c | 12 ++++++ src/odb_loose.c | 84 ++++++++++++++++++++++++++++++++++++++ src/odb_pack.c | 20 +++++++++ src/pack.c | 43 +++++++++++++++++++ src/pack.h | 4 ++ tests-clar/odb/foreach.c | 36 ++++++++++++++++ 8 files changed, 219 insertions(+) create mode 100644 tests-clar/odb/foreach.c diff --git a/include/git2/odb.h b/include/git2/odb.h index e2443178c..dac9e06a9 100644 --- a/include/git2/odb.h +++ b/include/git2/odb.h @@ -172,6 +172,20 @@ GIT_EXTERN(int) git_odb_read_header(size_t *len_p, git_otype *type_p, git_odb *d */ GIT_EXTERN(int) git_odb_exists(git_odb *db, const git_oid *id); +/** + * List all objects available in the database + * + * The callback will be called for each object available in the + * database. Note that the objects are likely to be returned in the + * index order, which would make accessing the objects in that order + * inefficient. + * + * @param db database to use + * @param cb the callback to call for each object + * @param data data to pass to the callback + */ +GIT_EXTERN(int) git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data); + /** * Write an object directly into the ODB * diff --git a/include/git2/odb_backend.h b/include/git2/odb_backend.h index f4620f5f4..3f67202d1 100644 --- a/include/git2/odb_backend.h +++ b/include/git2/odb_backend.h @@ -71,6 +71,12 @@ struct git_odb_backend { struct git_odb_backend *, const git_oid *); + int (*foreach)( + struct git_odb_backend *, + int (*cb)(git_oid *oid, void *data), + void *data + ); + void (* free)(struct git_odb_backend *); }; diff --git a/src/odb.c b/src/odb.c index e0c8fa262..493c8292a 100644 --- a/src/odb.c +++ b/src/odb.c @@ -605,6 +605,18 @@ int git_odb_read_prefix( return 0; } +int git_odb_foreach(git_odb *db, int (*cb)(git_oid *oid, void *data), void *data) +{ + unsigned int i; + backend_internal *internal; + git_vector_foreach(&db->backends, i, internal) { + git_odb_backend *b = internal->backend; + b->foreach(b, cb, data); + } + + return 0; +} + int git_odb_write( git_oid *oid, git_odb *db, const void *data, size_t len, git_otype type) { diff --git a/src/odb_loose.c b/src/odb_loose.c index 989b03ab2..ea51c4d14 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -676,6 +676,89 @@ static int loose_backend__exists(git_odb_backend *backend, const git_oid *oid) return !error; } +struct foreach_state { + size_t dir_len; + int (*cb)(git_oid *oid, void *data); + void *data; +}; + +static inline int filename_to_oid(git_oid *oid, const char *ptr) +{ + int v, i = 0; + if (strlen(ptr) != 41) + return -1; + + if (ptr[2] != '/') { + return -1; + } + + v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i+1]); + if (v < 0) + return -1; + + oid->id[0] = (unsigned char) v; + + ptr += 3; + for (i = 0; i < 38; i += 2) { + v = (git__fromhex(ptr[i]) << 4) | git__fromhex(ptr[i + 1]); + if (v < 0) + return -1; + + oid->id[1 + i/2] = (unsigned char) v; + } + + return 0; +} + +static int foreach_object_dir_cb(void *_state, git_buf *path) +{ + git_oid oid; + struct foreach_state *state = (struct foreach_state *) _state; + + if (filename_to_oid(&oid, path->ptr + state->dir_len) < 0) + return 0; + + if (state->cb(&oid, state->data) < 0) + return -1; + + return 0; +} + +static int foreach_cb(void *_state, git_buf *path) +{ + struct foreach_state *state = (struct foreach_state *) _state; + + if (git_path_direach(path, foreach_object_dir_cb, state) < 0) + return -1; + + return 0; +} + +static int loose_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data) +{ + char *objects_dir; + int error; + git_buf buf = GIT_BUF_INIT; + struct foreach_state state; + loose_backend *backend = (loose_backend *) _backend; + + assert(backend && cb); + + objects_dir = backend->objects_dir; + + git_buf_sets(&buf, objects_dir); + git_path_to_dir(&buf); + + state.cb = cb; + state.data = data; + state.dir_len = git_buf_len(&buf); + + error = git_path_direach(&buf, foreach_cb, &state); + git_buf_free(&buf); + + return error; +} + static int loose_backend__stream_fwrite(git_oid *oid, git_odb_stream *_stream) { loose_writestream *stream = (loose_writestream *)_stream; @@ -845,6 +928,7 @@ int git_odb_backend_loose( backend->parent.read_header = &loose_backend__read_header; backend->parent.writestream = &loose_backend__stream; backend->parent.exists = &loose_backend__exists; + backend->parent.foreach = &loose_backend__foreach; backend->parent.free = &loose_backend__free; *backend_out = (git_odb_backend *)backend; diff --git a/src/odb_pack.c b/src/odb_pack.c index 458f288d9..4b860e864 100644 --- a/src/odb_pack.c +++ b/src/odb_pack.c @@ -420,6 +420,25 @@ static int pack_backend__exists(git_odb_backend *backend, const git_oid *oid) return pack_entry_find(&e, (struct pack_backend *)backend, oid) == 0; } +static int pack_backend__foreach(git_odb_backend *_backend, int (*cb)(git_oid *oid, void *data), void *data) +{ + struct git_pack_file *p; + struct pack_backend *backend; + unsigned int i; + + assert(_backend && cb); + backend = (struct pack_backend *)_backend; + + /* Make sure we know about the packfiles */ + if (packfile_refresh_all(backend) < 0) + return -1; + + git_vector_foreach(&backend->packs, i, p) { + git_pack_foreach_entry(p, cb, &data); + } + return 0; +} + static void pack_backend__free(git_odb_backend *_backend) { struct pack_backend *backend; @@ -463,6 +482,7 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->parent.read_prefix = &pack_backend__read_prefix; backend->parent.read_header = NULL; backend->parent.exists = &pack_backend__exists; + backend->parent.foreach = &pack_backend__foreach; backend->parent.free = &pack_backend__free; *backend_out = (git_odb_backend *)backend; diff --git a/src/pack.c b/src/pack.c index 808ceb70c..1d88eaa7d 100644 --- a/src/pack.c +++ b/src/pack.c @@ -686,6 +686,49 @@ static git_off_t nth_packed_object_offset(const struct git_pack_file *p, uint32_ } } +int git_pack_foreach_entry( + struct git_pack_file *p, + int (*cb)(git_oid *oid, void *data), + void *data) + +{ + const unsigned char *index = p->index_map.data, *current; + unsigned stride; + uint32_t i; + + if (index == NULL) { + int error; + + if ((error = pack_index_open(p)) < 0) + return error; + + assert(p->index_map.data); + + index = p->index_map.data; + } + + if (p->index_version > 1) { + index += 8; + } + + index += 4 * 256; + + if (p->index_version > 1) { + stride = 20; + } else { + stride = 24; + index += 4; + } + + current = index; + for (i = 0; i < p->num_objects; i++) { + cb((git_oid *)current, data); + current += stride; + } + + return 0; +} + static int pack_entry_find_offset( git_off_t *offset_out, git_oid *found_oid, diff --git a/src/pack.h b/src/pack.h index cd7a4d2e1..7e1f978b0 100644 --- a/src/pack.h +++ b/src/pack.h @@ -102,5 +102,9 @@ int git_pack_entry_find( struct git_pack_file *p, const git_oid *short_oid, unsigned int len); +int git_pack_foreach_entry( + struct git_pack_file *p, + int (*cb)(git_oid *oid, void *data), + void *data); #endif diff --git a/tests-clar/odb/foreach.c b/tests-clar/odb/foreach.c new file mode 100644 index 000000000..6cb4faad2 --- /dev/null +++ b/tests-clar/odb/foreach.c @@ -0,0 +1,36 @@ +#include "clar_libgit2.h" +#include "odb.h" +#include "git2/odb_backend.h" +#include "pack.h" + +static git_odb *_odb; +static git_repository *_repo; +static int nobj; + +void test_odb_foreach__initialize(void) +{ + cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); + git_repository_odb(&_odb, _repo); +} + +void test_odb_foreach__cleanup(void) +{ + git_odb_free(_odb); + git_repository_free(_repo); +} + +static int foreach_cb(git_oid *oid, void *data) +{ + GIT_UNUSED(data); + GIT_UNUSED(oid); + + nobj++; + + return 0; +} + +void test_odb_foreach__foreach(void) +{ + cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); + cl_assert(nobj == 1681); +} From 4ea7c8c6660a33d27190133d0aed8437da432478 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Tue, 3 Jul 2012 12:35:33 -0700 Subject: [PATCH 064/123] Replace incorrect 'it' with 'if' in documentation --- include/git2/revwalk.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/git2/revwalk.h b/include/git2/revwalk.h index 2e9dc421a..d86bb28eb 100644 --- a/include/git2/revwalk.h +++ b/include/git2/revwalk.h @@ -107,7 +107,7 @@ GIT_EXTERN(int) git_revwalk_push(git_revwalk *walk, const git_oid *oid); * 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 + * A leading 'refs/' is implied if not present as well as a trailing * '/ *' if the glob lacks '?', '*' or '['. * * @param walk the walker being used for the traversal @@ -146,7 +146,7 @@ GIT_EXTERN(int) git_revwalk_hide(git_revwalk *walk, const git_oid *oid); * pattern and their ancestors will be hidden from the output on the * revision walk. * - * A leading 'refs/' is implied it not present as well as a trailing + * A leading 'refs/' is implied if not present as well as a trailing * '/ *' if the glob lacks '?', '*' or '['. * * @param walk the walker being used for the traversal From 296f60f56da4854d746984415e7e9887796d4e64 Mon Sep 17 00:00:00 2001 From: Cyril Roelandt Date: Fri, 6 Jul 2012 00:54:07 +0200 Subject: [PATCH 065/123] Fix libgit2 on GNU/Hurd. On GNU, the d_name field of the dirent structure is defined as "char d_name[1]", so we must allocate more than sizeof(struct dirent) bytes, just like on Sun. --- src/path.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/path.c b/src/path.c index a6574b3de..9c88240e0 100644 --- a/src/path.c +++ b/src/path.c @@ -515,7 +515,7 @@ int git_path_direach( return -1; } -#ifdef __sun +#if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); @@ -569,7 +569,7 @@ int git_path_dirload( return -1; } -#ifdef __sun +#if defined(__sun) || defined(__GNU__) de_buf = git__malloc(sizeof(struct dirent) + FILENAME_MAX + 1); #else de_buf = git__malloc(sizeof(struct dirent)); From b6bfd96fdd0cffc37c843cbf0f7c43efdbe96ef9 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 Jul 2012 12:07:33 +0200 Subject: [PATCH 066/123] refs: fix moving of the reflog when renaming a ref --- src/reflog.c | 48 +++++++++++++++++++++++++++++++++------- src/refs.c | 1 + tests-clar/refs/reflog.c | 28 +++++++++++++++++++++-- 3 files changed, 67 insertions(+), 10 deletions(-) diff --git a/src/reflog.c b/src/reflog.c index 3ea073e65..004ba936d 100644 --- a/src/reflog.c +++ b/src/reflog.c @@ -269,18 +269,50 @@ cleanup: int git_reflog_rename(git_reference *ref, const char *new_name) { - int error; + int error = -1, fd; git_buf old_path = GIT_BUF_INIT; git_buf new_path = GIT_BUF_INIT; + git_buf temp_path = GIT_BUF_INIT; - if (!git_buf_join_n(&old_path, '/', 3, ref->owner->path_repository, - GIT_REFLOG_DIR, ref->name) && - !git_buf_join_n(&new_path, '/', 3, ref->owner->path_repository, - GIT_REFLOG_DIR, new_name)) - error = p_rename(git_buf_cstr(&old_path), git_buf_cstr(&new_path)); - else - error = -1; + assert(ref && new_name); + if (git_buf_joinpath(&temp_path, ref->owner->path_repository, GIT_REFLOG_DIR) < 0) + return -1; + + if (git_buf_joinpath(&old_path, git_buf_cstr(&temp_path), ref->name) < 0) + goto cleanup; + + if (git_buf_joinpath(&new_path, git_buf_cstr(&temp_path), new_name) < 0) + goto cleanup; + + /* + * Move the reflog to a temporary place. This two-phase renaming is required + * in order to cope with funny renaming use cases when one tries to move a reference + * to a partially colliding namespace: + * - a/b -> a/b/c + * - a/b/c/d -> a/b/c + */ + if (git_buf_joinpath(&temp_path, git_buf_cstr(&temp_path), "temp_reflog") < 0) + goto cleanup; + + if ((fd = git_futils_mktmp(&temp_path, git_buf_cstr(&temp_path))) < 0) + goto cleanup; + p_close(fd); + + if (p_rename(git_buf_cstr(&old_path), git_buf_cstr(&temp_path)) < 0) + goto cleanup; + + if (git_path_isdir(git_buf_cstr(&new_path)) && + (git_futils_rmdir_r(git_buf_cstr(&new_path), GIT_DIRREMOVAL_ONLY_EMPTY_DIRS) < 0)) + goto cleanup; + + if (git_futils_mkpath2file(git_buf_cstr(&new_path), GIT_REFLOG_DIR_MODE) < 0) + goto cleanup; + + error = p_rename(git_buf_cstr(&temp_path), git_buf_cstr(&new_path)); + +cleanup: + git_buf_free(&temp_path); git_buf_free(&old_path); git_buf_free(&new_path); diff --git a/src/refs.c b/src/refs.c index ee076b3b8..80349b710 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1406,6 +1406,7 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) /* * Rename the reflog file. */ + git_buf_clear(&aux_path); if (git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0) goto cleanup; diff --git a/tests-clar/refs/reflog.c b/tests-clar/refs/reflog.c index 1bc51b2b8..a945b4789 100644 --- a/tests-clar/refs/reflog.c +++ b/tests-clar/refs/reflog.c @@ -26,7 +26,7 @@ static void assert_signature(git_signature *expected, git_signature *actual) // Fixture setup and teardown void test_refs_reflog__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); + g_repo = cl_git_sandbox_init("testrepo.git"); } void test_refs_reflog__cleanup(void) @@ -61,7 +61,7 @@ void test_refs_reflog__write_then_read(void) cl_git_pass(git_reflog_write(ref, &oid, committer, commit_msg)); /* Reopen a new instance of the repository */ - cl_git_pass(git_repository_open(&repo2, "testrepo")); + cl_git_pass(git_repository_open(&repo2, "testrepo.git")); /* Lookup the preivously created branch */ cl_git_pass(git_reference_lookup(&lookedup_ref, repo2, new_ref)); @@ -121,3 +121,27 @@ void test_refs_reflog__dont_write_bad(void) git_reference_free(ref); } + +void test_refs_reflog__renaming_the_reference_moves_the_reflog(void) +{ + git_reference *master; + git_buf master_log_path = GIT_BUF_INIT, moved_log_path = GIT_BUF_INIT; + + git_buf_joinpath(&master_log_path, git_repository_path(g_repo), GIT_REFLOG_DIR); + git_buf_puts(&moved_log_path, git_buf_cstr(&master_log_path)); + git_buf_joinpath(&master_log_path, git_buf_cstr(&master_log_path), "refs/heads/master"); + git_buf_joinpath(&moved_log_path, git_buf_cstr(&moved_log_path), "refs/moved"); + + cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&master_log_path))); + cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&moved_log_path))); + + cl_git_pass(git_reference_lookup(&master, g_repo, "refs/heads/master")); + cl_git_pass(git_reference_rename(master, "refs/moved", 0)); + + cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&master_log_path))); + cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&moved_log_path))); + + git_reference_free(master); + git_buf_free(&moved_log_path); + git_buf_free(&master_log_path); +} From 75261421ec00b6dc0a72931ed7640743a4998c7d Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 11:58:04 +0200 Subject: [PATCH 067/123] refs: add git_reference_has_log() --- include/git2/refs.h | 10 ++++++++++ src/refs.c | 17 +++++++++++++++++ tests-clar/refs/reflog.c | 17 +++++++++++++++++ 3 files changed, 44 insertions(+) diff --git a/include/git2/refs.h b/include/git2/refs.h index 2aa0ac267..7f6eb0e9b 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -353,6 +353,16 @@ GIT_EXTERN(int) git_reference_foreach_glob( void *payload ); +/** + * Check if a reflog exists for the specified reference. + * + * @param ref A git reference + * + * @return 0 when no reflog can be found, 1 when it exists; + * otherwise an error code. + */ +GIT_EXTERN(int) git_reference_has_log(git_reference *ref); + /** @} */ GIT_END_DECL #endif diff --git a/src/refs.c b/src/refs.c index 80349b710..2aba83ef5 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1802,3 +1802,20 @@ int git_reference_foreach_glob( return git_reference_foreach( repo, list_flags, fromglob_cb, &data); } + +int git_reference_has_log( + git_reference *ref) +{ + git_buf path = GIT_BUF_INIT; + int result; + + assert(ref); + + if (git_buf_join_n(&path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0) + return -1; + + result = git_path_isfile(git_buf_cstr(&path)); + git_buf_free(&path); + + return result; +} diff --git a/tests-clar/refs/reflog.c b/tests-clar/refs/reflog.c index a945b4789..05f3786bb 100644 --- a/tests-clar/refs/reflog.c +++ b/tests-clar/refs/reflog.c @@ -145,3 +145,20 @@ void test_refs_reflog__renaming_the_reference_moves_the_reflog(void) git_buf_free(&moved_log_path); git_buf_free(&master_log_path); } +static void assert_has_reflog(bool expected_result, const char *name) +{ + git_reference *ref; + + cl_git_pass(git_reference_lookup(&ref, g_repo, name)); + + cl_assert_equal_i(expected_result, git_reference_has_log(ref)); + + git_reference_free(ref); +} + +void test_refs_reflog__reference_has_reflog(void) +{ + assert_has_reflog(true, "HEAD"); + assert_has_reflog(true, "refs/heads/master"); + assert_has_reflog(false, "refs/heads/subtrees"); +} From 33c3370700083b9138b167778814d5af06ccf0b4 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 12:20:43 +0200 Subject: [PATCH 068/123] refs: deploy git_reference_has_log() --- include/git2/reflog.h | 2 ++ src/refs.c | 12 +++--------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/include/git2/reflog.h b/include/git2/reflog.h index f490e29de..8acba349b 100644 --- a/include/git2/reflog.h +++ b/include/git2/reflog.h @@ -53,6 +53,8 @@ GIT_EXTERN(int) git_reflog_write(git_reference *ref, const git_oid *oid_old, con /** * Rename the reflog for the given reference * + * The reflog to be renamed is expected to already exist + * * @param ref the reference * @param new_name the new name of the reference * @return 0 or an error code diff --git a/src/refs.c b/src/refs.c index 2aba83ef5..fbbb86689 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1404,18 +1404,12 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) } /* - * Rename the reflog file. + * Rename the reflog file, if it exists. */ - git_buf_clear(&aux_path); - if (git_buf_join_n(&aux_path, '/', 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name) < 0) + if ((git_reference_has_log(ref)) && (git_reflog_rename(ref, new_name) < 0)) goto cleanup; - if (git_path_exists(aux_path.ptr) == true) { - if (git_reflog_rename(ref, new_name) < 0) - goto cleanup; - } else { - giterr_clear(); - } + giterr_clear(); /* * Change the name of the reference given by the user. From 5ffd510dd2f39f674d502853cee38c80ad959756 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 12:23:03 +0200 Subject: [PATCH 069/123] refs: remove seemingly useless giterr_clear() call --- src/refs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/refs.c b/src/refs.c index fbbb86689..e8f9fc8dc 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1409,8 +1409,6 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) if ((git_reference_has_log(ref)) && (git_reflog_rename(ref, new_name) < 0)) goto cleanup; - giterr_clear(); - /* * Change the name of the reference given by the user. */ From d0a920a6fd70aaad9a3cee10ba6465f3b04a7bc5 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 7 Jul 2012 10:36:35 +0200 Subject: [PATCH 070/123] refs: deep unfound ref returns ENOTFOUND --- src/fileops.c | 2 +- tests-clar/refs/read.c | 10 ++++++++++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/fileops.c b/src/fileops.c index 95a65893c..5849b79b2 100644 --- a/src/fileops.c +++ b/src/fileops.c @@ -94,7 +94,7 @@ int git_futils_open_ro(const char *path) { int fd = p_open(path, O_RDONLY); if (fd < 0) { - if (errno == ENOENT) + if (errno == ENOENT || errno == ENOTDIR) fd = GIT_ENOTFOUND; giterr_set(GITERR_OS, "Failed to open '%s'", path); } diff --git a/tests-clar/refs/read.c b/tests-clar/refs/read.c index d7111b232..6838ead74 100644 --- a/tests-clar/refs/read.c +++ b/tests-clar/refs/read.c @@ -192,3 +192,13 @@ void test_refs_read__loose_first(void) git_reference_free(reference); } + +void test_refs_read__unfound_return_ENOTFOUND(void) +{ + git_reference *reference; + + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "test/master")); + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/test/master")); + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/master")); + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&reference, g_repo, "refs/tags/test/farther/master")); +} From 34922eeeedaf2067a2fb1326bcbc623fb11a3f6a Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 Jul 2012 14:59:14 +0200 Subject: [PATCH 071/123] revparse: readonly tests don't need a sandboxed repo --- tests-clar/refs/revparse.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index e282cd710..235d18f9c 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -28,12 +28,13 @@ void test_refs_revparse__initialize(void) if (tz) strcpy(g_orig_tz, tz); cl_setenv("TZ", "UTC"); - g_repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_refs_revparse__cleanup(void) { - cl_git_sandbox_cleanup(); + git_repository_free(g_repo); g_obj = NULL; cl_setenv("TZ", g_orig_tz); } From 1decf88bc12a55261c42db5d3c086500e642a088 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 Jul 2012 15:34:22 +0200 Subject: [PATCH 072/123] revparse: slightly improve readability of tests --- tests-clar/refs/revparse.c | 42 ++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 235d18f9c..f36809494 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -12,16 +12,21 @@ static char g_orig_tz[16] = {0}; static void test_object(const char *spec, const char *expected_oid) { char objstr[64] = {0}; + git_object *obj = NULL; + int error; - cl_git_pass(git_revparse_single(&g_obj, g_repo, spec)); - git_oid_fmt(objstr, git_object_id(g_obj)); - cl_assert_equal_s(objstr, expected_oid); + error = git_revparse_single(&obj, g_repo, spec); - git_object_free(g_obj); - g_obj = NULL; + if (expected_oid != NULL) { + cl_assert_equal_i(0, error); + git_oid_fmt(objstr, git_object_id(obj)); + cl_assert_equal_s(objstr, expected_oid); + } else + cl_assert_equal_i(GIT_ENOTFOUND, error); + + git_object_free(obj); } - void test_refs_revparse__initialize(void) { char *tz = cl_getenv("TZ"); @@ -41,7 +46,8 @@ void test_refs_revparse__cleanup(void) void test_refs_revparse__nonexistant_object(void) { - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "this doesn't exist")); + test_object("this doesn't exist", NULL); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist^1")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist~2")); } @@ -86,7 +92,7 @@ void test_refs_revparse__nth_parent(void) test_object("be3563a^2^1", "5b5b025afb0b4c913b4c338a42934a3863bf3644"); test_object("be3563a^0", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "be3563a^42")); + test_object("be3563a^42", NULL); } void test_refs_revparse__not_tag(void) @@ -129,8 +135,8 @@ void test_refs_revparse__reflog(void) cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "nope@{0}")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{31415}")); + test_object("nope@{0}", NULL); + test_object("master@{31415}", NULL); test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); @@ -171,7 +177,7 @@ void test_refs_revparse__date(void) * a65fedf HEAD@{1335806603 -0900}: commit: * be3563a HEAD@{1335806563 -0700}: clone: from /Users/ben/src/libgit2/tests/resour */ - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "HEAD@{10 years ago}")); + test_object("HEAD@{10 years ago}", NULL); test_object("HEAD@{1 second}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("HEAD@{1 second ago}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); @@ -192,8 +198,8 @@ void test_refs_revparse__date(void) * $ git reflog -1 "master@{2012-04-30 17:22:42 +0000}" * warning: Log for 'master' only goes back to Mon, 30 Apr 2012 09:22:43 -0800. */ - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{2012-04-30 17:22:42 +0000}")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "master@{2012-04-30 09:22:42 -0800}")); + test_object("master@{2012-04-30 17:22:42 +0000}", NULL); + test_object("master@{2012-04-30 09:22:42 -0800}", NULL); /* * $ git reflog -1 "master@{2012-04-30 17:22:43 +0000}" @@ -230,11 +236,11 @@ void test_refs_revparse__colon(void) cl_git_fail(git_revparse_single(&g_obj, g_repo, ":/")); cl_git_fail(git_revparse_single(&g_obj, g_repo, ":2:README")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, ":/not found in any commit")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/42.txt")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:ab/4.txt/nope")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "subtrees:nope")); - cl_assert_equal_i(GIT_ENOTFOUND, git_revparse_single(&g_obj, g_repo, "test/master^1:branch_file.txt")); + test_object(":/not found in any commit", NULL); + test_object("subtrees:ab/42.txt", NULL); + test_object("subtrees:ab/4.txt/nope", NULL); + test_object("subtrees:nope", NULL); + test_object("test/master^1:branch_file.txt", NULL); /* Trees */ test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); From cab65c2b23e1a01969c4586ef123ab153652aa6e Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 5 Jul 2012 22:26:14 +0200 Subject: [PATCH 073/123] revparse: detect incorrect "refname@{-n}" syntax --- src/revparse.c | 29 +++++++++++++---------------- tests-clar/refs/revparse.c | 1 + 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 8c15f46c6..f5cf93ba2 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -21,9 +21,10 @@ typedef enum { REVPARSE_STATE_DONE, } revparse_state; -static void set_invalid_syntax_err(const char *spec) +static int revspec_error(const char *revspec) { - giterr_set(GITERR_INVALID, "Refspec '%s' is not valid.", spec); + giterr_set(GITERR_INVALID, "Failed to parse revision specifier - Invalid pattern '%s'", revspec); + return -1; } static int revparse_lookup_fully_qualifed_ref(git_object **out, git_repository *repo, const char*spec) @@ -154,21 +155,19 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * size_t reflogspeclen = strlen(reflogspec); if (git__prefixcmp(reflogspec, "@{") != 0 || - git__suffixcmp(reflogspec, "}") != 0) { - giterr_set(GITERR_INVALID, "Bad reflogspec '%s'", reflogspec); - return GIT_ERROR; - } + git__suffixcmp(reflogspec, "}") != 0) + return revspec_error(reflogspec); /* "@{-N}" form means walk back N checkouts. That means the HEAD log. */ - if (refspeclen == 0 && !git__prefixcmp(reflogspec, "@{-")) { + if (!git__prefixcmp(reflogspec, "@{-")) { regex_t regex; int regex_error; - if (git__strtol32(&n, reflogspec+3, NULL, 0) < 0 || - n < 1) { - giterr_set(GITERR_INVALID, "Invalid reflogspec %s", reflogspec); - return GIT_ERROR; - } + if (refspeclen > 0) + return revspec_error(reflogspec); + + if (git__strtol32(&n, reflogspec+3, NULL, 0) < 0 || n < 1) + return revspec_error(reflogspec); if (!git_reference_lookup(&ref, repo, "HEAD")) { if (!git_reflog_read(&reflog, ref)) { @@ -373,10 +372,8 @@ static int handle_caret_syntax(git_object **out, git_repository *repo, git_objec int n; if (*movement == '{') { - if (movement[movementlen-1] != '}') { - set_invalid_syntax_err(movement); - return GIT_ERROR; - } + if (movement[movementlen-1] != '}') + return revspec_error(movement); /* {} -> Dereference until we reach an object that isn't a tag. */ if (movementlen == 2) { diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index f36809494..892cb760a 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -133,6 +133,7 @@ void test_refs_revparse__reflog(void) { cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{-2}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); test_object("nope@{0}", NULL); From 98d6a1fdda5fa0605dee933930b5b7ddff4feb37 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 16:24:09 +0200 Subject: [PATCH 074/123] util: add git__isdigit() --- src/util.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/util.h b/src/util.h index adc665027..abdd543cc 100644 --- a/src/util.h +++ b/src/util.h @@ -204,6 +204,11 @@ GIT_INLINE(bool) git__isalpha(int c) return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')); } +GIT_INLINE(bool) git__isdigit(int c) +{ + return (c >= '0' && c <= '9'); +} + GIT_INLINE(bool) git__isspace(int c) { return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); From 29f72aa63844967cfd56d2edce804af243ef3ddd Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 22:02:54 +0200 Subject: [PATCH 075/123] revparse: leverage git__isdigit() --- src/revparse.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index f5cf93ba2..3b9b2c903 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -115,10 +115,11 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const static int all_chars_are_digits(const char *str, size_t len) { - size_t i=0; - for (i=0; i '9') return 0; - } + size_t i = 0; + + for (i = 0; i < len; i++) + if (!git__isdigit(str[i])) return 0; + return 1; } From 6a5136e5389034b696c9cd0292a760e78e975fd8 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 12:47:14 +0200 Subject: [PATCH 076/123] revparse: only allow decimal reflog ordinal specs passing 0 to git_strol(32|64) let the implementation guess if it's dealing with an octal number or a decimal one. Let's make it safe and ensure that both 'HEAD@{010}' and 'HEAD@{10}' point at the same commit. --- src/revparse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 3b9b2c903..af0b055be 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -167,7 +167,7 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * if (refspeclen > 0) return revspec_error(reflogspec); - if (git__strtol32(&n, reflogspec+3, NULL, 0) < 0 || n < 1) + if (git__strtol32(&n, reflogspec+3, NULL, 10) < 0 || n < 1) return revspec_error(reflogspec); if (!git_reference_lookup(&ref, repo, "HEAD")) { @@ -233,7 +233,7 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * /* @{N} -> Nth prior value for the ref (from reflog) */ else if (all_chars_are_digits(reflogspec+2, reflogspeclen-3) && - !git__strtol32(&n, reflogspec+2, NULL, 0) && + !git__strtol32(&n, reflogspec+2, NULL, 10) && n <= 100000000) { /* Allow integer time */ normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); From 35bed94fd5fec699faca6a6d7dc7d03994373bb7 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 3 Jul 2012 18:01:46 +0200 Subject: [PATCH 077/123] revparse: enhance refs/ coverage --- tests-clar/refs/revparse.c | 59 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 892cb760a..bd50ca3cd 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -1,6 +1,9 @@ #include "clar_libgit2.h" #include "git2/revparse.h" +#include "buffer.h" +#include "refs.h" +#include "path.h" static git_repository *g_repo; static git_object *g_obj; @@ -9,13 +12,13 @@ static char g_orig_tz[16] = {0}; /* Helpers */ -static void test_object(const char *spec, const char *expected_oid) +static void test_object_inrepo(const char *spec, const char *expected_oid, git_repository *repo) { char objstr[64] = {0}; git_object *obj = NULL; int error; - error = git_revparse_single(&obj, g_repo, spec); + error = git_revparse_single(&obj, repo, spec); if (expected_oid != NULL) { cl_assert_equal_i(0, error); @@ -27,6 +30,11 @@ static void test_object(const char *spec, const char *expected_oid) git_object_free(obj); } +static void test_object(const char *spec, const char *expected_oid) +{ + test_object_inrepo(spec, expected_oid, g_repo); +} + void test_refs_revparse__initialize(void) { char *tz = cl_getenv("TZ"); @@ -149,6 +157,53 @@ void test_refs_revparse__reflog(void) test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } +static void create_fake_stash_reference_and_reflog(git_repository *repo) +{ + git_reference *master; + git_buf log_path = GIT_BUF_INIT; + + git_buf_joinpath(&log_path, git_repository_path(repo), "logs/refs/fakestash"); + + cl_assert_equal_i(false, git_path_isfile(git_buf_cstr(&log_path))); + + cl_git_pass(git_reference_lookup(&master, repo, "refs/heads/master")); + cl_git_pass(git_reference_rename(master, "refs/fakestash", 0)); + + cl_assert_equal_i(true, git_path_isfile(git_buf_cstr(&log_path))); + + git_buf_free(&log_path); + git_reference_free(master); +} + +void test_refs_revparse__reflog_of_a_ref_under_refs(void) +{ + git_repository *repo = cl_git_sandbox_init("testrepo.git"); + + test_object_inrepo("refs/fakestash", NULL, repo); + + create_fake_stash_reference_and_reflog(repo); + + /* + * $ git reflog -1 refs/fakestash + * a65fedf refs/fakestash@{0}: commit: checking in + * + * $ git reflog -1 refs/fakestash@{0} + * a65fedf refs/fakestash@{0}: commit: checking in + * + * $ git reflog -1 fakestash + * a65fedf fakestash@{0}: commit: checking in + * + * $ git reflog -1 fakestash@{0} + * a65fedf fakestash@{0}: commit: checking in + */ + test_object_inrepo("refs/fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); + test_object_inrepo("refs/fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); + test_object_inrepo("fakestash", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); + test_object_inrepo("fakestash@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", repo); + + cl_git_sandbox_cleanup(); +} + void test_refs_revparse__revwalk(void) { cl_git_fail(git_revparse_single(&g_obj, g_repo, "master^{/not found in any commit}")); From 3cd90893a0b8737e9536d46bb3813c0a8432fdad Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 17:25:31 +0200 Subject: [PATCH 078/123] revparse: enhance upstream reflog test coverage --- tests-clar/refs/revparse.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index bd50ca3cd..b23ce6788 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -137,6 +137,18 @@ void test_refs_revparse__chaining(void) test_object("master^1^1^1^1^1", "8496071c1b46c854b31185ea97743be6a8774479"); } +void test_refs_revparse__upstream(void) +{ + cl_git_fail(git_revparse_single(&g_obj, g_repo, "e90810b@{u}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "refs/tags/e90810b@{u}")); + + test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("refs/heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); +} + void test_refs_revparse__reflog(void) { cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); @@ -153,8 +165,6 @@ void test_refs_revparse__reflog(void) test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{upstream}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } static void create_fake_stash_reference_and_reflog(git_repository *repo) From 3d78ab64272ab56fc449f50bbd970d64801aa8bd Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 19:48:57 +0200 Subject: [PATCH 079/123] revparse: split reflog test per feature --- tests-clar/refs/revparse.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index b23ce6788..3f4fcd68b 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -149,22 +149,32 @@ void test_refs_revparse__upstream(void) test_object("refs/heads/master@{u}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } -void test_refs_revparse__reflog(void) +void test_refs_revparse__ordinal(void) { - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); cl_git_fail(git_revparse_single(&g_obj, g_repo, "master@{-2}")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{1000}")); test_object("nope@{0}", NULL); test_object("master@{31415}", NULL); + test_object("@{1000}", NULL); + + test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + + test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); + test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + test_object("refs/heads/master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); +} + +void test_refs_revparse__previous_head(void) +{ + cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-xyz}")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "@{-0}")); + + test_object("@{-42}", NULL); test_object("@{-2}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{-1}", "a4a7dce85cf63874e984719f4fdd239f5145052f"); - test_object("master@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("master@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); - test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); - test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); } static void create_fake_stash_reference_and_reflog(git_repository *repo) From 805c81594dad1ad5758e78490f1c9d46b42cd41c Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 20:44:17 +0200 Subject: [PATCH 080/123] revparse: unfound previous head return ENOTFOUND --- src/revparse.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/revparse.c b/src/revparse.c index af0b055be..574392f7c 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -178,6 +178,8 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * } else { regmatch_t regexmatches[2]; + retcode = GIT_ENOTFOUND; + refloglen = git_reflog_entrycount(reflog); for (i=refloglen-1; i >= 0; i--) { const char *msg; From e727938112a45a3ef9b8751aaef96d4ff7da74b2 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 21:25:42 +0200 Subject: [PATCH 081/123] revparse: fix disambiguation of refs --- src/revparse.c | 182 ++++++++++++++++++++++++++----------------------- 1 file changed, 98 insertions(+), 84 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 574392f7c..47437f355 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -54,13 +54,15 @@ static int spec_looks_like_describe_output(const char *spec) return retcode == 0; } -static int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) +static int disambiguate_refname(git_reference **out, git_repository *repo, const char *refname) { - size_t speclen = strlen(spec); - git_object *obj = NULL; - git_oid oid; - git_buf refnamebuf = GIT_BUF_INIT; + int error, i; + bool fallbackmode = true; + git_reference *ref; + git_buf refnamebuf = GIT_BUF_INIT, name = GIT_BUF_INIT; + static const char* formatters[] = { + "%s", "refs/%s", "refs/tags/%s", "refs/heads/%s", @@ -68,7 +70,46 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const "refs/remotes/%s/HEAD", NULL }; - unsigned int i; + + if (*refname) + git_buf_puts(&name, refname); + else { + git_buf_puts(&name, "HEAD"); + fallbackmode = false; + } + + for (i = 0; formatters[i] && (fallbackmode || i == 0); i++) { + + git_buf_clear(&refnamebuf); + + if ((error = git_buf_printf(&refnamebuf, formatters[i], git_buf_cstr(&name))) < 0) + goto cleanup; + + error = git_reference_lookup_resolved(&ref, repo, git_buf_cstr(&refnamebuf), -1); + + if (!error) { + *out = ref; + error = 0; + goto cleanup; + } + + if (error != GIT_ENOTFOUND) + goto cleanup; + } + +cleanup: + git_buf_free(&name); + git_buf_free(&refnamebuf); + return error; +} + +static int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) +{ + size_t speclen = strlen(spec); + git_object *obj = NULL; + git_oid oid; + int error; + git_reference *ref; const char *substr; /* "git describe" output; snip everything before/including "-g" */ @@ -87,32 +128,20 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const } } - /* Fully-named ref */ - if (!revparse_lookup_fully_qualifed_ref(&obj, repo, spec)) { - *out = obj; - return 0; + error = disambiguate_refname(&ref, repo, spec); + if (!error) { + error = git_object_lookup(out, repo, git_reference_oid(ref), GIT_OBJ_ANY); + git_reference_free(ref); + return error; } - /* Partially-named ref; match in this order: */ - for (i=0; formatters[i]; i++) { - git_buf_clear(&refnamebuf); - if (git_buf_printf(&refnamebuf, formatters[i], spec) < 0) { - return GIT_ERROR; - } - - if (!revparse_lookup_fully_qualifed_ref(&obj, repo, git_buf_cstr(&refnamebuf))) { - git_buf_free(&refnamebuf); - *out = obj; - return 0; - } - } - git_buf_free(&refnamebuf); + if (error < 0) + return error; giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); return GIT_ENOTFOUND; } - static int all_chars_are_digits(const char *str, size_t len) { size_t i = 0; @@ -123,30 +152,9 @@ static int all_chars_are_digits(const char *str, size_t len) return 1; } -static void normalize_maybe_empty_refname(git_buf *buf, git_repository *repo, const char *refspec, size_t refspeclen) -{ - git_reference *ref; - - if (!refspeclen) { - /* Empty refspec means current branch (target of HEAD) */ - git_reference_lookup(&ref, repo, "HEAD"); - git_buf_puts(buf, git_reference_target(ref)); - git_reference_free(ref); - } else if (strstr(refspec, "HEAD")) { - /* Explicit head */ - git_buf_puts(buf, refspec); - }else { - if (git__prefixcmp(refspec, "refs/heads/") != 0) { - git_buf_printf(buf, "refs/heads/%s", refspec); - } else { - git_buf_puts(buf, refspec); - } - } -} - static int walk_ref_history(git_object **out, git_repository *repo, const char *refspec, const char *reflogspec) { - git_reference *ref; + git_reference *disambiguated = NULL; git_reflog *reflog = NULL; int n, retcode = GIT_ERROR; int i, refloglen; @@ -170,8 +178,8 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * if (git__strtol32(&n, reflogspec+3, NULL, 10) < 0 || n < 1) return revspec_error(reflogspec); - if (!git_reference_lookup(&ref, repo, "HEAD")) { - if (!git_reflog_read(&reflog, ref)) { + if (!git_reference_lookup(&disambiguated, repo, "HEAD")) { + if (!git_reflog_read(&reflog, disambiguated)) { regex_error = regcomp(®ex, "checkout: moving from (.*) to .*", REG_EXTENDED); if (regex_error != 0) { giterr_set_regex(®ex, regex_error); @@ -198,29 +206,40 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * regfree(®ex); } } - git_reference_free(ref); } } else { - int date_error = 0; + int date_error = 0, result; git_time_t timestamp; git_buf datebuf = GIT_BUF_INIT; + result = disambiguate_refname(&disambiguated, repo, refspec); + + if (result < 0) { + retcode = result; + goto cleanup; + } + git_buf_put(&datebuf, reflogspec+2, reflogspeclen-3); date_error = git__date_parse(×tamp, git_buf_cstr(&datebuf)); /* @{u} or @{upstream} -> upstream branch, for a tracking branch. This is stored in the config. */ - if (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}")) { + if (!git__prefixcmp(git_reference_name(disambiguated), GIT_REFS_HEADS_DIR) && + (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}"))) { git_config *cfg; if (!git_repository_config(&cfg, repo)) { /* Is the ref a tracking branch? */ const char *remote; git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.remote", refspec); + git_buf_printf(&buf, "branch.%s.remote", + git_reference_name(disambiguated) + strlen(GIT_REFS_HEADS_DIR)); + if (!git_config_get_string(&remote, cfg, git_buf_cstr(&buf))) { /* Yes. Find the first merge target name. */ const char *mergetarget; git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.merge", refspec); + git_buf_printf(&buf, "branch.%s.merge", + git_reference_name(disambiguated) + strlen(GIT_REFS_HEADS_DIR)); + if (!git_config_get_string(&mergetarget, cfg, git_buf_cstr(&buf)) && !git__prefixcmp(mergetarget, "refs/heads/")) { /* Success. Look up the target and fetch the object. */ @@ -237,12 +256,12 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * else if (all_chars_are_digits(reflogspec+2, reflogspeclen-3) && !git__strtol32(&n, reflogspec+2, NULL, 10) && n <= 100000000) { /* Allow integer time */ - normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); - if (n == 0) { + git_buf_puts(&buf, git_reference_name(disambiguated)); + + if (n == 0) retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); - } else if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { - if (!git_reflog_read(&reflog, ref)) { + else if (!git_reflog_read(&reflog, disambiguated)) { int numentries = git_reflog_entrycount(reflog); if (numentries < n) { giterr_set(GITERR_REFERENCE, "Reflog for '%s' has only %d entries, asked for %d", @@ -253,48 +272,43 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * const git_oid *oid = git_reflog_entry_oidold(entry); retcode = git_object_lookup(out, repo, oid, GIT_OBJ_ANY); } - } - git_reference_free(ref); } } else if (!date_error) { /* Ref as it was on a certain date */ - normalize_maybe_empty_refname(&buf, repo, refspec, refspeclen); + git_reflog *reflog; + if (!git_reflog_read(&reflog, disambiguated)) { + /* Keep walking until we find an entry older than the given date */ + int numentries = git_reflog_entrycount(reflog); + int i; - if (!git_reference_lookup(&ref, repo, git_buf_cstr(&buf))) { - git_reflog *reflog; - if (!git_reflog_read(&reflog, ref)) { - /* Keep walking until we find an entry older than the given date */ - int numentries = git_reflog_entrycount(reflog); - int i; - - for (i = numentries - 1; i >= 0; i--) { - const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); - git_time commit_time = git_reflog_entry_committer(entry)->when; - if (commit_time.time - timestamp <= 0) { - retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); - break; - } + for (i = numentries - 1; i >= 0; i--) { + const git_reflog_entry *entry = git_reflog_entry_byindex(reflog, i); + git_time commit_time = git_reflog_entry_committer(entry)->when; + if (commit_time.time - timestamp <= 0) { + retcode = git_object_lookup(out, repo, git_reflog_entry_oidnew(entry), GIT_OBJ_ANY); + break; } - - if (i == -1) { - /* Didn't find a match */ - retcode = GIT_ENOTFOUND; - } - - git_reflog_free(reflog); } - git_reference_free(ref); + if (i == -1) { + /* Didn't find a match */ + retcode = GIT_ENOTFOUND; + } + + git_reflog_free(reflog); } } git_buf_free(&datebuf); } - if (reflog) git_reflog_free(reflog); +cleanup: + if (reflog) + git_reflog_free(reflog); git_buf_free(&buf); + git_reference_free(disambiguated); return retcode; } From b8460c2015d0954f3317caf60c1e49fb3cd56ace Mon Sep 17 00:00:00 2001 From: nulltoken Date: Fri, 6 Jul 2012 23:37:44 +0200 Subject: [PATCH 082/123] revparse: do not segfault when retrieving the last entry --- src/revparse.c | 2 +- tests-clar/refs/revparse.c | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/revparse.c b/src/revparse.c index 47437f355..3194cc491 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -263,7 +263,7 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); else if (!git_reflog_read(&reflog, disambiguated)) { int numentries = git_reflog_entrycount(reflog); - if (numentries < n) { + if (numentries < n + 1) { giterr_set(GITERR_REFERENCE, "Reflog for '%s' has only %d entries, asked for %d", git_buf_cstr(&buf), numentries, n); retcode = GIT_ENOTFOUND; diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 3f4fcd68b..f723a1426 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -156,6 +156,7 @@ void test_refs_revparse__ordinal(void) test_object("nope@{0}", NULL); test_object("master@{31415}", NULL); test_object("@{1000}", NULL); + test_object("@{2}", NULL); test_object("@{0}", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); test_object("@{1}", "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); From ce9e8e11cafdbb6895e7fae9b714430de151ba5b Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 7 Jul 2012 07:27:53 +0200 Subject: [PATCH 083/123] revparse: fix invalid test reference name --- tests-clar/refs/revparse.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index f723a1426..31029f726 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -54,10 +54,14 @@ void test_refs_revparse__cleanup(void) void test_refs_revparse__nonexistant_object(void) { - test_object("this doesn't exist", NULL); + test_object("this-does-not-exist", NULL); +} - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist^1")); - cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't exist~2")); +void test_refs_revparse__invalid_reference_name(void) +{ + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense^1")); + cl_git_fail(git_revparse_single(&g_obj, g_repo, "this doesn't make sense~2")); } void test_refs_revparse__shas(void) From 3e82d6c6f0783a5c74b79d7a849e9ca319f171b5 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Sat, 7 Jul 2012 08:25:39 +0200 Subject: [PATCH 084/123] revparse: unfound reference return ENOTFOUND --- src/revparse.c | 74 +++++++++++++++++++++++++------------- tests-clar/refs/revparse.c | 2 ++ 2 files changed, 52 insertions(+), 24 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 3194cc491..f9859b18b 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -47,8 +47,9 @@ static int spec_looks_like_describe_output(const char *spec) regex_error = regcomp(®ex, ".+-[0-9]+-g[0-9a-fA-F]+", REG_EXTENDED); if (regex_error != 0) { giterr_set_regex(®ex, regex_error); - return 1; /* To be safe */ + return regex_error; } + retcode = regexec(®ex, spec, 0, NULL, 0); regfree(®ex); return retcode == 0; @@ -103,39 +104,66 @@ cleanup: return error; } -static int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) +extern int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec); + +static int maybe_describe(git_object**out, git_repository *repo, const char *spec) { - size_t speclen = strlen(spec); - git_object *obj = NULL; - git_oid oid; - int error; - git_reference *ref; const char *substr; + int match; /* "git describe" output; snip everything before/including "-g" */ substr = strstr(spec, "-g"); - if (substr && - spec_looks_like_describe_output(spec) && - !revparse_lookup_object(out, repo, substr+2)) { - return 0; - } - /* SHA or prefix */ - if (!git_oid_fromstrn(&oid, spec, speclen)) { - if (!git_object_lookup_prefix(&obj, repo, &oid, speclen, GIT_OBJ_ANY)) { - *out = obj; - return 0; - } - } + if (substr == NULL) + return GIT_ENOTFOUND; + + if ((match = spec_looks_like_describe_output(spec)) < 0) + return match; + + if (!match) + return GIT_ENOTFOUND; + + return revparse_lookup_object(out, repo, substr+2); +} + +static int maybe_sha_or_abbrev(git_object**out, git_repository *repo, const char *spec) +{ + git_oid oid; + size_t speclen = strlen(spec); + + if (git_oid_fromstrn(&oid, spec, speclen) < 0) + return GIT_ENOTFOUND; + + return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJ_ANY); +} + +int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) +{ + int error; + git_reference *ref; + + error = maybe_describe(out, repo, spec); + if (!error) + return 0; + + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + error = maybe_sha_or_abbrev(out, repo, spec); + if (!error) + return 0; + + if (error < 0 && error != GIT_ENOTFOUND) + return error; error = disambiguate_refname(&ref, repo, spec); if (!error) { error = git_object_lookup(out, repo, git_reference_oid(ref), GIT_OBJ_ANY); git_reference_free(ref); - return error; + return 0; } - if (error < 0) + if (error < 0 && error != GIT_ENOTFOUND) return error; giterr_set(GITERR_REFERENCE, "Refspec '%s' not found.", spec); @@ -711,10 +739,8 @@ int git_revparse_single(git_object **out, git_repository *repo, const char *spec if (current_state != next_state && next_state != REVPARSE_STATE_DONE) { /* Leaving INIT state, find the object specified, in case that state needs it */ - if (revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer)) < 0) { - retcode = GIT_ERROR; + if ((retcode = revparse_lookup_object(&next_obj, repo, git_buf_cstr(&specbuffer))) < 0) next_state = REVPARSE_STATE_DONE; - } } break; diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index 31029f726..dbc002d38 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -55,6 +55,8 @@ void test_refs_revparse__cleanup(void) void test_refs_revparse__nonexistant_object(void) { test_object("this-does-not-exist", NULL); + test_object("this-does-not-exist^1", NULL); + test_object("this-does-not-exist~2", NULL); } void test_refs_revparse__invalid_reference_name(void) From a7a2fccd83a8b27f200179bde7a94dbdfbfcd7ab Mon Sep 17 00:00:00 2001 From: Ignacio Casal Quinteiro Date: Mon, 9 Jul 2012 13:12:16 +0200 Subject: [PATCH 085/123] Point to the libgit2-glib wiki page --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4c23fc870..e8dc36a16 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Here are the bindings to libgit2 that are currently available: * Go * go-git * GObject - * libgit2-glib + * libgit2-glib * Haskell * hgit2 * Lua From 13f9eb242d318508c6d98c886e767ecef4a22ff2 Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Fri, 29 Jun 2012 19:23:36 +0200 Subject: [PATCH 086/123] examples: add README --- examples/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 examples/README.md diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 000000000..38d1ed86b --- /dev/null +++ b/examples/README.md @@ -0,0 +1,8 @@ +libgit2 examples +================ + +These examples might don't work on all platforms and are meant as thin, +easy-to-read snippets for docurium (https://github.com/github/docurium) +rather than full-blown implementations of Git commands. + +For a HTML version check "Examples" at http://libgit2.github.com/libgit2 From 6b9a49cd5fd6addc5b9ce3281ea33a50934f5a94 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 21:50:36 -0700 Subject: [PATCH 087/123] Updating language in examples README --- examples/README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/examples/README.md b/examples/README.md index 38d1ed86b..f2b6d7d23 100644 --- a/examples/README.md +++ b/examples/README.md @@ -1,8 +1,11 @@ libgit2 examples ================ -These examples might don't work on all platforms and are meant as thin, -easy-to-read snippets for docurium (https://github.com/github/docurium) -rather than full-blown implementations of Git commands. +These examples are meant as thin, easy-to-read snippets for Docurium +(https://github.com/github/docurium) rather than full-blown +implementations of Git commands. They are not vetted as carefully +for bugs, error handling, or cross-platform compatibility as the +rest of the code in libgit2, so copy with some caution. + +For HTML versions, check "Examples" at http://libgit2.github.com/libgit2 -For a HTML version check "Examples" at http://libgit2.github.com/libgit2 From 039fc4067989a14a09784ed16ce7126ac75461cb Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:10:14 -0700 Subject: [PATCH 088/123] Add a couple of useful git_buf utilities * `git_buf_rfind` (with tests and tests for `git_buf_rfind_next`) * `git_buf_puts_escaped` and `git_buf_puts_escaped_regex` (with tests) to copy strings into a buffer while injecting an escape sequence (e.g. '\') in front of particular characters. --- src/buffer.c | 34 +++++++++++++++++++++++++++++ src/buffer.h | 19 ++++++++++++++++ tests-clar/core/buffer.c | 47 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index 04aaec3df..d16b17160 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -141,6 +141,40 @@ int git_buf_puts(git_buf *buf, const char *string) return git_buf_put(buf, string, strlen(string)); } +int git_buf_puts_escaped( + git_buf *buf, const char *string, const char *esc_chars, const char *esc_with) +{ + const char *scan = string; + size_t total = 0, esc_with_len = strlen(esc_with); + + while (*scan) { + size_t count = strcspn(scan, esc_chars); + total += count + 1 + esc_with_len; + scan += count + 1; + } + + ENSURE_SIZE(buf, buf->size + total + 1); + + for (scan = string; *scan; ) { + size_t count = strcspn(scan, esc_chars); + + memmove(buf->ptr + buf->size, scan, count); + scan += count; + buf->size += count; + + if (*scan) { + memmove(buf->ptr + buf->size, esc_with, esc_with_len); + buf->size += esc_with_len; + + memmove(buf->ptr + buf->size, scan, 1); + scan += 1; + buf->size += 1; + } + } + + return 0; +} + int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) { int len; diff --git a/src/buffer.h b/src/buffer.h index 50c75f64e..75f3b0e4f 100644 --- a/src/buffer.h +++ b/src/buffer.h @@ -90,6 +90,18 @@ void git_buf_rtruncate_at_char(git_buf *path, char separator); int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...); int git_buf_join(git_buf *buf, char separator, const char *str_a, const char *str_b); +/** + * Copy string into buf prefixing every character that is contained in the + * esc_chars string with the esc_with string. + */ +int git_buf_puts_escaped( + git_buf *buf, const char *string, const char *esc_chars, const char *esc_with); + +GIT_INLINE(int) git_buf_puts_escape_regex(git_buf *buf, const char *string) +{ + return git_buf_puts_escaped(buf, string, "^.[]$()|*+?{}\\", "\\"); +} + /** * Join two strings as paths, inserting a slash between as needed. * @return 0 on success, -1 on failure @@ -121,6 +133,13 @@ GIT_INLINE(ssize_t) git_buf_rfind_next(git_buf *buf, char ch) return idx; } +GIT_INLINE(ssize_t) git_buf_rfind(git_buf *buf, char ch) +{ + ssize_t idx = (ssize_t)buf->size - 1; + while (idx >= 0 && buf->ptr[idx] != ch) idx--; + return idx; +} + /* Remove whitespace from the end of the buffer */ void git_buf_rtrim(git_buf *buf); diff --git a/tests-clar/core/buffer.c b/tests-clar/core/buffer.c index 6a718f459..996cb7bcb 100644 --- a/tests-clar/core/buffer.c +++ b/tests-clar/core/buffer.c @@ -611,3 +611,50 @@ void test_core_buffer__11(void) git_buf_free(&a); } + +void test_core_buffer__rfind_variants(void) +{ + git_buf a = GIT_BUF_INIT; + ssize_t len; + + cl_git_pass(git_buf_sets(&a, "/this/is/it/")); + + len = (ssize_t)git_buf_len(&a); + + cl_assert(git_buf_rfind(&a, '/') == len - 1); + cl_assert(git_buf_rfind_next(&a, '/') == len - 4); + + cl_assert(git_buf_rfind(&a, 'i') == len - 3); + cl_assert(git_buf_rfind_next(&a, 'i') == len - 3); + + cl_assert(git_buf_rfind(&a, 'h') == 2); + cl_assert(git_buf_rfind_next(&a, 'h') == 2); + + cl_assert(git_buf_rfind(&a, 'q') == -1); + cl_assert(git_buf_rfind_next(&a, 'q') == -1); + + git_buf_clear(&a); +} + +void test_core_buffer__puts_escaped(void) +{ + git_buf a = GIT_BUF_INIT; + + git_buf_clear(&a); + cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "", "")); + cl_assert_equal_s("this is a test", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "t", "\\")); + cl_assert_equal_s("\\this is a \\tes\\t", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_puts_escaped(&a, "this is a test", "i ", "__")); + cl_assert_equal_s("th__is__ __is__ a__ test", a.ptr); + + git_buf_clear(&a); + cl_git_pass(git_buf_puts_escape_regex(&a, "^match\\s*[A-Z]+.*")); + cl_assert_equal_s("\\^match\\\\s\\*\\[A-Z\\]\\+\\.\\*", a.ptr); + + git_buf_free(&a); +} From b0fe11292219f5d63f2159e0b0eb24ff21d66b10 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:13:30 -0700 Subject: [PATCH 089/123] Add path utilities to resolve relative paths This makes it easy to take a buffer containing a path with relative references (i.e. .. or . path segments) and resolve all of those into a clean path. This can be applied to URLs as well as file paths which can be useful. As part of this, I made the drive-letter detection apply on all platforms, not just windows. If you give a path that looks like "c:/..." on any platform, it seems like we might as well detect that as a rooted path. I suppose if you create a directory named "x:" on another platform and want to use that as the beginning of a relative path under the root directory of your repo, this could cause a problem, but then it seems like you're asking for trouble. --- src/path.c | 69 ++++++++++++++++++++++++++++++++++++++++-- src/path.h | 23 ++++++++++++++ tests-clar/core/path.c | 51 +++++++++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 3 deletions(-) diff --git a/src/path.c b/src/path.c index 9c88240e0..e9bc4871c 100644 --- a/src/path.c +++ b/src/path.c @@ -17,9 +17,7 @@ #include #include -#ifdef GIT_WIN32 #define LOOKS_LIKE_DRIVE_PREFIX(S) (git__isalpha((S)[0]) && (S)[1] == ':') -#endif /* * Based on the Android implementation, BSD licensed. @@ -172,11 +170,11 @@ int git_path_root(const char *path) { int offset = 0; -#ifdef GIT_WIN32 /* Does the root of the path look like a windows drive ? */ if (LOOKS_LIKE_DRIVE_PREFIX(path)) offset += 2; +#ifdef GIT_WIN32 /* Are we dealing with a windows network path? */ else if ((path[0] == '/' && path[1] == '/') || (path[0] == '\\' && path[1] == '\\')) @@ -464,6 +462,71 @@ int git_path_find_dir(git_buf *dir, const char *path, const char *base) return error; } +int git_path_resolve_relative(git_buf *path, size_t ceiling) +{ + char *base, *to, *from, *next; + size_t len; + + if (!path || git_buf_oom(path)) + return -1; + + if (ceiling > path->size) + ceiling = path->size; + + /* recognize drive prefixes, etc. that should not be backed over */ + if (ceiling == 0) + ceiling = git_path_root(path->ptr) + 1; + + /* recognize URL prefixes that should not be backed over */ + if (ceiling == 0) { + for (next = path->ptr; *next && git__isalpha(*next); ++next); + if (next[0] == ':' && next[1] == '/' && next[2] == '/') + ceiling = (next + 3) - path->ptr; + } + + base = to = from = path->ptr + ceiling; + + while (*from) { + for (next = from; *next && *next != '/'; ++next); + + len = next - from; + + if (len == 1 && from[0] == '.') + /* do nothing with singleton dot */; + + else if (len == 2 && from[0] == '.' && from[1] == '.') { + while (to > base && to[-1] == '/') to--; + while (to > base && to[-1] != '/') to--; + } + + else { + if (*next == '/') + len++; + + if (to != from) + memmove(to, from, len); + + to += len; + } + + from += len; + + while (*from == '/') from++; + } + + *to = '\0'; + + path->size = to - path->ptr; + + return 0; +} + +int git_path_apply_relative(git_buf *target, const char *relpath) +{ + git_buf_joinpath(target, git_buf_cstr(target), relpath); + return git_path_resolve_relative(target, 0); +} + int git_path_cmp( const char *name1, size_t len1, int isdir1, const char *name2, size_t len2, int isdir2) diff --git a/src/path.h b/src/path.h index fd76805e5..d68393b3d 100644 --- a/src/path.h +++ b/src/path.h @@ -185,6 +185,29 @@ extern int git_path_prettify_dir(git_buf *path_out, const char *path, const char */ extern int git_path_find_dir(git_buf *dir, const char *path, const char *base); +/** + * Resolve relative references within a path. + * + * This eliminates "./" and "../" relative references inside a path, + * as well as condensing multiple slashes into single ones. It will + * not touch the path before the "ceiling" length. + * + * Additionally, this will recognize an "c:/" drive prefix or a "xyz://" URL + * prefix and not touch that part of the path. + */ +extern int git_path_resolve_relative(git_buf *path, size_t ceiling); + +/** + * Apply a relative path to base path. + * + * Note that the base path could be a filename or a URL and this + * should still work. The relative path is walked segment by segment + * with three rules: series of slashes will be condensed to a single + * slash, "." will be eaten with no change, and ".." will remove a + * segment from the base path. + */ +extern int git_path_apply_relative(git_buf *target, const char *relpath); + /** * Walk each directory entry, except '.' and '..', calling fn(state). * diff --git a/tests-clar/core/path.c b/tests-clar/core/path.c index d826612ac..864393b70 100644 --- a/tests-clar/core/path.c +++ b/tests-clar/core/path.c @@ -418,3 +418,54 @@ void test_core_path__13_cannot_prettify_a_non_existing_file(void) git_buf_free(&p); } + +void test_core_path__14_apply_relative(void) +{ + git_buf p = GIT_BUF_INIT; + + cl_git_pass(git_buf_sets(&p, "/this/is/a/base")); + + cl_git_pass(git_path_apply_relative(&p, "../test")); + cl_assert_equal_s("/this/is/a/test", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../the/./end")); + cl_assert_equal_s("/this/is/the/end", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "./of/this/../the/string")); + cl_assert_equal_s("/this/is/the/end/of/the/string", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../../..")); + cl_assert_equal_s("/this/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../../")); + cl_assert_equal_s("/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../..")); + cl_assert_equal_s("/", p.ptr); + + + cl_git_pass(git_buf_sets(&p, "d:/another/test")); + + cl_git_pass(git_path_apply_relative(&p, "../../../../..")); + cl_assert_equal_s("d:/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "from/here/to/../and/./back/.")); + cl_assert_equal_s("d:/from/here/and/back/", p.ptr); + + + cl_git_pass(git_buf_sets(&p, "https://my.url.com/test.git")); + + cl_git_pass(git_path_apply_relative(&p, "../another.git")); + cl_assert_equal_s("https://my.url.com/another.git", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../full/path/url.patch")); + cl_assert_equal_s("https://my.url.com/full/path/url.patch", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "..")); + cl_assert_equal_s("https://my.url.com/full/path/", p.ptr); + + cl_git_pass(git_path_apply_relative(&p, "../../../../../")); + cl_assert_equal_s("https://", p.ptr); + + git_buf_free(&p); +} From c3a875c975cde11ffd18947c419b1cd38205e6c3 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:20:08 -0700 Subject: [PATCH 090/123] Adding unicode space to match crlf patterns Adding 0x85 to `git__isspace` since we also look for that in filter.c as a whitespace character. --- src/util.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.h b/src/util.h index adc665027..bc122332f 100644 --- a/src/util.h +++ b/src/util.h @@ -206,7 +206,7 @@ GIT_INLINE(bool) git__isalpha(int c) GIT_INLINE(bool) git__isspace(int c) { - return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v'); + return (c == ' ' || c == '\t' || c == '\n' || c == '\f' || c == '\r' || c == '\v' || c == 0x85 /* Unicode CR+LF */); } GIT_INLINE(bool) git__iswildcard(int c) From b3ff1dab317dc9194c4bc124afd95ae9be2ad57b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:22:39 -0700 Subject: [PATCH 091/123] Adding git_config_foreach_match() iteration fn Adding a new config iteration function that let's you iterate over just the config entries that match a particular regular expression. The old foreach becomes a simple use of this with an empty pattern. This also fixes an apparent bug in the existing `git_config_foreach` where returning a non-zero value from the iteration callback was not correctly aborting the iteration and the returned value was not being propogated back to the caller of foreach. Added to tests to cover all these changes. --- include/git2/config.h | 20 ++++++++++- src/config.c | 16 +++++++-- src/config_file.c | 39 ++++++++++++++++----- src/config_file.h | 17 ++++++++- tests-clar/config/read.c | 75 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 154 insertions(+), 13 deletions(-) diff --git a/include/git2/config.h b/include/git2/config.h index 36946c4a5..c46e7fc9d 100644 --- a/include/git2/config.h +++ b/include/git2/config.h @@ -33,7 +33,7 @@ struct git_config_file { int (*set)(struct git_config_file *, const char *key, const char *value); int (*set_multivar)(git_config_file *cfg, const char *name, const char *regexp, const char *value); int (*del)(struct git_config_file *, const char *key); - int (*foreach)(struct git_config_file *, int (*fn)(const char *, const char *, void *), void *data); + int (*foreach)(struct git_config_file *, const char *, int (*fn)(const char *, const char *, void *), void *data); void (*free)(struct git_config_file *); }; @@ -314,6 +314,24 @@ GIT_EXTERN(int) git_config_foreach( int (*callback)(const char *var_name, const char *value, void *payload), void *payload); +/** + * Perform an operation on each config variable matching a regular expression. + * + * This behaviors like `git_config_foreach` with an additional filter of a + * regular expression that filters which config keys are passed to the + * callback. + * + * @param cfg where to get the variables from + * @param regexp regular expression to match against config names + * @param callback the function to call on each variable + * @param payload the data to pass to the callback + * @return 0 or the return value of the callback which didn't return 0 + */ +GIT_EXTERN(int) git_config_foreach_match( + git_config *cfg, + const char *regexp, + int (*callback)(const char *var_name, const char *value, void *payload), + void *payload); /** * Query the value of a config variable and return it mapped to diff --git a/src/config.c b/src/config.c index d18b85c30..98fb3b20d 100644 --- a/src/config.c +++ b/src/config.c @@ -136,17 +136,27 @@ int git_config_add_file(git_config *cfg, git_config_file *file, int priority) * Loop over all the variables */ -int git_config_foreach(git_config *cfg, int (*fn)(const char *, const char *, void *), void *data) +int git_config_foreach( + git_config *cfg, int (*fn)(const char *, const char *, void *), void *data) +{ + return git_config_foreach_match(cfg, NULL, fn, data); +} + +int git_config_foreach_match( + git_config *cfg, + const char *regexp, + int (*fn)(const char *, const char *, void *), + void *data) { int ret = 0; unsigned int i; file_internal *internal; git_config_file *file; - for(i = 0; i < cfg->files.length && ret == 0; ++i) { + for (i = 0; i < cfg->files.length && ret == 0; ++i) { internal = git_vector_get(&cfg->files, i); file = internal->file; - ret = file->foreach(file, fn, data); + ret = file->foreach(file, regexp, fn, data); } return ret; diff --git a/src/config_file.c b/src/config_file.c index fd1aa8d08..1f3ebfca9 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -188,25 +188,46 @@ static void backend_free(git_config_file *_backend) git__free(backend); } -static int file_foreach(git_config_file *backend, int (*fn)(const char *, const char *, void *), void *data) +static int file_foreach( + git_config_file *backend, + const char *regexp, + int (*fn)(const char *, const char *, void *), + void *data) { diskfile_backend *b = (diskfile_backend *)backend; cvar_t *var; const char *key; + regex_t regex; + int result = 0; if (!b->values) return 0; - git_strmap_foreach(b->values, key, var, - do { - if (fn(key, var->value, data) < 0) - break; + if (regexp != NULL) { + if ((result = regcomp(®ex, regexp, REG_EXTENDED)) < 0) { + giterr_set_regex(®ex, result); + regfree(®ex); + return -1; + } + } - var = CVAR_LIST_NEXT(var); - } while (var != NULL); + git_strmap_foreach(b->values, key, var, + for (; var != NULL; var = CVAR_LIST_NEXT(var)) { + /* skip non-matching keys if regexp was provided */ + if (regexp && regexec(®ex, key, 0, NULL, 0) != 0) + continue; + + /* abort iterator on non-zero return value */ + if ((result = fn(key, var->value, data)) != 0) + goto cleanup; + } ); - return 0; +cleanup: + if (regexp != NULL) + regfree(®ex); + + return result; } static int config_set(git_config_file *cfg, const char *name, const char *value) @@ -337,6 +358,7 @@ static int config_get_multivar( result = regcomp(®ex, regex_str, REG_EXTENDED); if (result < 0) { giterr_set_regex(®ex, result); + regfree(®ex); return -1; } @@ -396,6 +418,7 @@ static int config_set_multivar( if (result < 0) { git__free(key); giterr_set_regex(&preg, result); + regfree(&preg); return -1; } diff --git a/src/config_file.h b/src/config_file.h index 0080b5713..c31292881 100644 --- a/src/config_file.h +++ b/src/config_file.h @@ -19,12 +19,27 @@ GIT_INLINE(void) git_config_file_free(git_config_file *cfg) cfg->free(cfg); } +GIT_INLINE(int) git_config_file_set_string( + git_config_file *cfg, const char *name, const char *value) +{ + return cfg->set(cfg, name, value); +} + GIT_INLINE(int) git_config_file_foreach( git_config_file *cfg, int (*fn)(const char *key, const char *value, void *data), void *data) { - return cfg->foreach(cfg, fn, data); + return cfg->foreach(cfg, NULL, fn, data); +} + +GIT_INLINE(int) git_config_file_foreach_match( + git_config_file *cfg, + const char *regexp, + int (*fn)(const char *key, const char *value, void *data), + void *data) +{ + return cfg->foreach(cfg, regexp, fn, data); } #endif diff --git a/tests-clar/config/read.c b/tests-clar/config/read.c index f33bdd89e..a8504da02 100644 --- a/tests-clar/config/read.c +++ b/tests-clar/config/read.c @@ -191,6 +191,81 @@ void test_config_read__escaping_quotes(void) git_config_free(cfg); } +static int count_cfg_entries( + const char *var_name, const char *value, void *payload) +{ + int *count = payload; + GIT_UNUSED(var_name); + GIT_UNUSED(value); + (*count)++; + return 0; +} + +static int cfg_callback_countdown( + const char *var_name, const char *value, void *payload) +{ + int *count = payload; + GIT_UNUSED(var_name); + GIT_UNUSED(value); + (*count)--; + if (*count == 0) + return -100; + return 0; +} + +void test_config_read__foreach(void) +{ + git_config *cfg; + int count, ret; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9"))); + + count = 0; + cl_git_pass(git_config_foreach(cfg, count_cfg_entries, &count)); + cl_assert_equal_i(5, count); + + count = 3; + cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count)); + cl_assert_equal_i(-100, ret); + + git_config_free(cfg); +} + +void test_config_read__foreach_match(void) +{ + git_config *cfg; + int count; + + cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9"))); + + count = 0; + cl_git_pass( + git_config_foreach_match(cfg, "core.*", count_cfg_entries, &count)); + cl_assert_equal_i(3, count); + + count = 0; + cl_git_pass( + git_config_foreach_match(cfg, "remote\\.ab.*", count_cfg_entries, &count)); + cl_assert_equal_i(2, count); + + count = 0; + cl_git_pass( + git_config_foreach_match(cfg, ".*url$", count_cfg_entries, &count)); + cl_assert_equal_i(2, count); + + count = 0; + cl_git_pass( + git_config_foreach_match(cfg, ".*dummy.*", count_cfg_entries, &count)); + cl_assert_equal_i(2, count); + + count = 0; + cl_git_pass( + git_config_foreach_match(cfg, ".*nomatch.*", count_cfg_entries, &count)); + cl_assert_equal_i(0, count); + + git_config_free(cfg); +} + #if 0 BEGIN_TEST(config10, "a repo's config overrides the global config") From 991a56c704f931e7eb52a0583e5d8684803f3b04 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 15:35:38 -0700 Subject: [PATCH 092/123] Add flag to write gitlink on setting repo workdir This added a flag to the `git_repository_set_workdir()` function that enables generation of a `.git` gitlink file that links the new workdir to the parent repository. Essentially, the flag tells the function to write out the changes to disk to permanently set the workdir of the repository to the new path. If you pass this flag as true, then setting the workdir to something other than the default workdir (i.e. the parent of the .git repo directory), will create a plain file named ".git" with the standard gitlink contents "gitdir: ", and also update the "core.worktree" and "core.bare" config values. Setting the workdir to the default repo workdir will clear the core.worktree flag (but still permanently set core.bare to false). BTW, the libgit2 API does not currently provide a function for clearing the workdir and converting a non-bare repo into a bare one. --- include/git2/repository.h | 5 +- src/repository.c | 92 ++++++++++++++++++++++++++++++++---- tests-clar/repo/setters.c | 31 ++++++++++-- tests-clar/status/worktree.c | 4 +- 4 files changed, 116 insertions(+), 16 deletions(-) diff --git a/include/git2/repository.h b/include/git2/repository.h index 0b56a0870..ff81b75ec 100644 --- a/include/git2/repository.h +++ b/include/git2/repository.h @@ -194,9 +194,12 @@ GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); * * @param repo A repository object * @param workdir The path to a working directory + * @param update_gitlink Create/update gitlink in workdir and set config + * "core.worktree" (if workdir is not the parent of the .git directory) * @return 0, or an error code */ -GIT_EXTERN(int) git_repository_set_workdir(git_repository *repo, const char *workdir); +GIT_EXTERN(int) git_repository_set_workdir( + git_repository *repo, const char *workdir, int update_gitlink); /** * Check if a repository is bare diff --git a/src/repository.c b/src/repository.c index bee7b3ee6..a2931713e 100644 --- a/src/repository.c +++ b/src/repository.c @@ -741,15 +741,24 @@ static int repo_init_config(const char *git_dir, bool is_bare, bool is_reinit) #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) + const char *git_dir, + bool allow_overwrite, + const char *file, + mode_t mode, + const char *content) { git_buf path = GIT_BUF_INIT; - int fd, error = 0; + int fd, error = 0, flags; 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 (allow_overwrite) + flags = O_WRONLY | O_CREAT | O_TRUNC; + else + flags = O_WRONLY | O_CREAT | O_EXCL; + + fd = p_open(git_buf_cstr(&path), flags, mode); if (fd >= 0) { error = p_write(fd, content, strlen(content)); @@ -811,7 +820,7 @@ static int repo_init_structure(const char *git_dir, int is_bare) /* 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) + git_dir, false, tmpl[i].file, tmpl[i].mode, tmpl[i].content) < 0) return -1; } @@ -943,8 +952,47 @@ const char *git_repository_workdir(git_repository *repo) return repo->workdir; } -int git_repository_set_workdir(git_repository *repo, const char *workdir) +static int write_gitlink( + const char *in_dir, const char *to_repo) { + int error; + git_buf buf = GIT_BUF_INIT; + struct stat st; + + if (git_path_dirname_r(&buf, to_repo) < 0 || + git_path_to_dir(&buf) < 0) + return -1; + + /* don't write gitlink to natural workdir */ + if (git__suffixcmp(to_repo, "/" DOT_GIT "/") == 0 && + strcmp(in_dir, buf.ptr) == 0) + return GIT_PASSTHROUGH; + + if (git_buf_joinpath(&buf, in_dir, DOT_GIT) < 0) + return -1; + + if (!p_stat(buf.ptr, &st) && !S_ISREG(st.st_mode)) { + giterr_set(GITERR_REPOSITORY, + "Cannot overwrite gitlink file into path '%s'", in_dir); + return GIT_EEXISTS; + } + + git_buf_clear(&buf); + + if (git_buf_printf(&buf, "%s %s", GIT_FILE_CONTENT_PREFIX, to_repo) < 0) + return -1; + + error = repo_write_template(in_dir, true, DOT_GIT, 0644, buf.ptr); + + git_buf_free(&buf); + + return error; +} + +int git_repository_set_workdir( + git_repository *repo, const char *workdir, int update_gitlink) +{ + int error = 0; git_buf path = GIT_BUF_INIT; assert(repo && workdir); @@ -952,11 +1000,37 @@ int git_repository_set_workdir(git_repository *repo, const char *workdir) if (git_path_prettify_dir(&path, workdir, NULL) < 0) return -1; - git__free(repo->workdir); + if (repo->workdir && strcmp(repo->workdir, path.ptr) == 0) + return 0; - repo->workdir = git_buf_detach(&path); - repo->is_bare = 0; - return 0; + if (update_gitlink) { + git_config *config; + + if (git_repository_config__weakptr(&config, repo) < 0) + return -1; + + error = write_gitlink(path.ptr, git_repository_path(repo)); + + /* passthrough error means gitlink is unnecessary */ + if (error == GIT_PASSTHROUGH) + error = git_config_delete(config, "core.worktree"); + else if (!error) + error = git_config_set_string(config, "core.worktree", path.ptr); + + if (!error) + error = git_config_set_bool(config, "core.bare", false); + } + + if (!error) { + char *old_workdir = repo->workdir; + + repo->workdir = git_buf_detach(&path); + repo->is_bare = 0; + + git__free(old_workdir); + } + + return error; } int git_repository_is_bare(git_repository *repo) diff --git a/tests-clar/repo/setters.c b/tests-clar/repo/setters.c index 6242d8541..cd6e389ae 100644 --- a/tests-clar/repo/setters.c +++ b/tests-clar/repo/setters.c @@ -2,6 +2,8 @@ #include "buffer.h" #include "posix.h" #include "util.h" +#include "path.h" +#include "fileops.h" static git_repository *repo; @@ -16,7 +18,7 @@ void test_repo_setters__cleanup(void) { git_repository_free(repo); cl_fixture_cleanup("testrepo.git"); - cl_must_pass(p_rmdir("new_workdir")); + cl_fixture_cleanup("new_workdir"); } void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standard_one(void) @@ -24,7 +26,7 @@ void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standar cl_assert(git_repository_is_bare(repo) == 1); cl_assert(git_repository_workdir(repo) == NULL); - cl_git_pass(git_repository_set_workdir(repo, "./new_workdir")); + cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false)); cl_assert(git_repository_workdir(repo) != NULL); cl_assert(git_repository_is_bare(repo) == 0); @@ -32,9 +34,30 @@ void test_repo_setters__setting_a_workdir_turns_a_bare_repository_into_a_standar void test_repo_setters__setting_a_workdir_prettifies_its_path(void) { - cl_git_pass(git_repository_set_workdir(repo, "./new_workdir")); + cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", false)); - cl_assert(git__suffixcmp(git_repository_workdir(repo), "/") == 0); + cl_assert(git__suffixcmp(git_repository_workdir(repo), "new_workdir/") == 0); +} + +void test_repo_setters__setting_a_workdir_creates_a_gitlink(void) +{ + git_config *cfg; + const char *val; + git_buf content = GIT_BUF_INIT; + + cl_git_pass(git_repository_set_workdir(repo, "./new_workdir", true)); + + cl_assert(git_path_isfile("./new_workdir/.git")); + + cl_git_pass(git_futils_readbuffer(&content, "./new_workdir/.git")); + cl_assert(git__prefixcmp(git_buf_cstr(&content), "gitdir: ") == 0); + cl_assert(git__suffixcmp(git_buf_cstr(&content), "testrepo.git/") == 0); + git_buf_free(&content); + + cl_git_pass(git_repository_config(&cfg, repo)); + cl_git_pass(git_config_get_string(&val, cfg, "core.worktree")); + cl_assert(git__suffixcmp(val, "new_workdir/") == 0); + git_config_free(cfg); } void test_repo_setters__setting_a_new_index_on_a_repo_which_has_already_loaded_one_properly_honors_the_refcount(void) diff --git a/tests-clar/status/worktree.c b/tests-clar/status/worktree.c index 3670b72a8..fed81e570 100644 --- a/tests-clar/status/worktree.c +++ b/tests-clar/status/worktree.c @@ -459,7 +459,7 @@ void test_status_worktree__status_file_without_index_or_workdir(void) 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_repository_set_workdir(repo, "wd", false)); cl_git_pass(git_index_open(&index, "empty-index")); cl_assert_equal_i(0, git_index_entrycount(index)); @@ -500,7 +500,7 @@ void test_status_worktree__status_file_with_clean_index_and_empty_workdir(void) 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_repository_set_workdir(repo, "wd", false)); cl_git_pass(git_index_open(&index, "my-index")); fill_index_wth_head_entries(repo, index); From 54e29b9380f1cd0fa596d71c317de907da19b13d Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Tue, 10 Jul 2012 23:51:32 -0700 Subject: [PATCH 093/123] Fix missing NUL termination of buffer --- src/buffer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/buffer.c b/src/buffer.c index d16b17160..5d54ee1a5 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -172,6 +172,8 @@ int git_buf_puts_escaped( } } + buf->ptr[buf->size] = '\0'; + return 0; } From 111ee3fe2d4c6de6729b94235c709986b4079c4b Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Wed, 11 Jul 2012 14:37:26 +0200 Subject: [PATCH 094/123] Add missing includes --- include/git2.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/git2.h b/include/git2.h index f260cfacd..2e33f9e4a 100644 --- a/include/git2.h +++ b/include/git2.h @@ -38,6 +38,8 @@ #include "git2/config.h" #include "git2/remote.h" +#include "git2/attr.h" +#include "git2/branch.h" #include "git2/refspec.h" #include "git2/net.h" #include "git2/status.h" From 5b071115294e2c7d4b36ac21842ef09c7edd02b6 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 14:00:19 +0200 Subject: [PATCH 095/123] tests: add test commit with angle brackets in the author name --- tests-clar/network/remotelocal.c | 4 ++-- tests-clar/refs/branches/foreach.c | 4 ++-- tests-clar/refs/foreachglob.c | 4 ++-- .../1b/8cbad43e867676df601306689fe7c3def5e689 | Bin 0 -> 51 bytes .../25/8f0e2a959a364e40ed6603d5d44fbb24765b10 | Bin 0 -> 168 bytes .../resources/testrepo.git/refs/heads/haacked | 1 + tests-clar/revwalk/basic.c | 4 ++-- 7 files changed, 9 insertions(+), 8 deletions(-) create mode 100644 tests-clar/resources/testrepo.git/objects/1b/8cbad43e867676df601306689fe7c3def5e689 create mode 100644 tests-clar/resources/testrepo.git/objects/25/8f0e2a959a364e40ed6603d5d44fbb24765b10 create mode 100644 tests-clar/resources/testrepo.git/refs/heads/haacked diff --git a/tests-clar/network/remotelocal.c b/tests-clar/network/remotelocal.c index 41922975e..5e20b4240 100644 --- a/tests-clar/network/remotelocal.c +++ b/tests-clar/network/remotelocal.c @@ -107,7 +107,7 @@ void test_network_remotelocal__retrieve_advertised_references(void) cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); - cl_assert_equal_i(how_many_refs, 21); + cl_assert_equal_i(how_many_refs, 22); } void test_network_remotelocal__retrieve_advertised_references_from_spaced_repository(void) @@ -121,7 +121,7 @@ void test_network_remotelocal__retrieve_advertised_references_from_spaced_reposi cl_git_pass(git_remote_ls(remote, &count_ref__cb, &how_many_refs)); - cl_assert_equal_i(how_many_refs, 21); + cl_assert_equal_i(how_many_refs, 22); git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ remote = NULL; diff --git a/tests-clar/refs/branches/foreach.c b/tests-clar/refs/branches/foreach.c index 51e3381f8..b6e973799 100644 --- a/tests-clar/refs/branches/foreach.c +++ b/tests-clar/refs/branches/foreach.c @@ -48,7 +48,7 @@ static void assert_retrieval(unsigned int flags, unsigned int expected_count) void test_refs_branches_foreach__retrieve_all_branches(void) { - assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 9); + assert_retrieval(GIT_BRANCH_LOCAL | GIT_BRANCH_REMOTE, 10); } void test_refs_branches_foreach__retrieve_remote_branches(void) @@ -58,7 +58,7 @@ void test_refs_branches_foreach__retrieve_remote_branches(void) void test_refs_branches_foreach__retrieve_local_branches(void) { - assert_retrieval(GIT_BRANCH_LOCAL, 7); + assert_retrieval(GIT_BRANCH_LOCAL, 8); } struct expectations { diff --git a/tests-clar/refs/foreachglob.c b/tests-clar/refs/foreachglob.c index 8bbcd71ed..d1412a94b 100644 --- a/tests-clar/refs/foreachglob.c +++ b/tests-clar/refs/foreachglob.c @@ -46,7 +46,7 @@ static void assert_retrieval(const char *glob, unsigned int flags, int expected_ void test_refs_foreachglob__retrieve_all_refs(void) { /* 7 heads (including one packed head) + 1 note + 2 remotes + 6 tags */ - assert_retrieval("*", GIT_REF_LISTALL, 16); + assert_retrieval("*", GIT_REF_LISTALL, 17); } void test_refs_foreachglob__retrieve_remote_branches(void) @@ -56,7 +56,7 @@ void test_refs_foreachglob__retrieve_remote_branches(void) void test_refs_foreachglob__retrieve_local_branches(void) { - assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 7); + assert_retrieval("refs/heads/*", GIT_REF_LISTALL, 8); } void test_refs_foreachglob__retrieve_partially_named_references(void) diff --git a/tests-clar/resources/testrepo.git/objects/1b/8cbad43e867676df601306689fe7c3def5e689 b/tests-clar/resources/testrepo.git/objects/1b/8cbad43e867676df601306689fe7c3def5e689 new file mode 100644 index 0000000000000000000000000000000000000000..6048d4bad339c5b92a5a4a36002ce3985d5b0bf4 GIT binary patch literal 51 zcmblLAXeIVsSp^AMPkgZGeHH721AUD zWR#;MNoSX>)`Ir>DjW3A9Ucu_#|3Ug@y%&~K9_Rg56$buO)T>OEh_ZdIgN0Zt(4-h W$IZ%r2gH3D>qry)O5zK?(n*;`X-(Du literal 0 HcmV?d00001 diff --git a/tests-clar/resources/testrepo.git/refs/heads/haacked b/tests-clar/resources/testrepo.git/refs/heads/haacked new file mode 100644 index 000000000..17f591222 --- /dev/null +++ b/tests-clar/resources/testrepo.git/refs/heads/haacked @@ -0,0 +1 @@ +258f0e2a959a364e40ed6603d5d44fbb24765b10 diff --git a/tests-clar/revwalk/basic.c b/tests-clar/revwalk/basic.c index a5a9b2eda..6f3c1c06d 100644 --- a/tests-clar/revwalk/basic.c +++ b/tests-clar/revwalk/basic.c @@ -129,8 +129,8 @@ void test_revwalk_basic__glob_heads(void) i++; } - /* git log --branches --oneline | wc -l => 13 */ - cl_assert(i == 13); + /* git log --branches --oneline | wc -l => 14 */ + cl_assert(i == 14); } void test_revwalk_basic__push_head(void) From 118cf57d426ede29b6695204e707810bbe3888ef Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 4 Jul 2012 16:06:07 +0200 Subject: [PATCH 096/123] revwalk: relax the parsing of the commit time --- src/revwalk.c | 31 ++++++++++++++----- tests-clar/revwalk/signatureparsing.c | 44 +++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 tests-clar/revwalk/signatureparsing.c diff --git a/src/revwalk.c b/src/revwalk.c index 7bcdc4af8..9dff283f5 100644 --- a/src/revwalk.c +++ b/src/revwalk.c @@ -188,7 +188,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo const size_t parent_len = strlen("parent ") + GIT_OID_HEXSZ + 1; unsigned char *buffer = raw->data; unsigned char *buffer_end = buffer + raw->len; - unsigned char *parents_start; + unsigned char *parents_start, *committer_start; int i, parents = 0; int commit_time; @@ -219,17 +219,34 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo commit->out_degree = (unsigned short)parents; + if ((committer_start = buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) + return commit_error(commit, "object is corrupted"); + + buffer++; + if ((buffer = memchr(buffer, '\n', buffer_end - buffer)) == NULL) return commit_error(commit, "object is corrupted"); - if ((buffer = memchr(buffer, '<', buffer_end - buffer)) == NULL || - (buffer = memchr(buffer, '>', buffer_end - buffer)) == NULL) - return commit_error(commit, "malformed author information"); + /* Skip trailing spaces */ + while (buffer > committer_start && git__isspace(*buffer)) + buffer--; - while (*buffer == '>' || git__isspace(*buffer)) - buffer++; + /* Seek for the begining of the pack of digits */ + while (buffer > committer_start && git__isdigit(*buffer)) + buffer--; - if (git__strtol32(&commit_time, (char *)buffer, NULL, 10) < 0) + /* Skip potential timezone offset */ + if ((buffer > committer_start) && (*buffer == '+' || *buffer == '-')) { + buffer--; + + while (buffer > committer_start && git__isspace(*buffer)) + buffer--; + + while (buffer > committer_start && git__isdigit(*buffer)) + buffer--; + } + + if ((buffer == committer_start) || (git__strtol32(&commit_time, (char *)(buffer + 1), NULL, 10) < 0)) return commit_error(commit, "cannot parse commit time"); commit->time = (time_t)commit_time; diff --git a/tests-clar/revwalk/signatureparsing.c b/tests-clar/revwalk/signatureparsing.c new file mode 100644 index 000000000..94de1a343 --- /dev/null +++ b/tests-clar/revwalk/signatureparsing.c @@ -0,0 +1,44 @@ +#include "clar_libgit2.h" + +static git_repository *_repo; +static git_revwalk *_walk; + +void test_revwalk_signatureparsing__initialize(void) +{ + cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); + cl_git_pass(git_revwalk_new(&_walk, _repo)); +} + +void test_revwalk_signatureparsing__cleanup(void) +{ + git_revwalk_free(_walk); + git_repository_free(_repo); +} + +void test_revwalk_signatureparsing__do_not_choke_when_name_contains_angle_brackets(void) +{ + git_reference *ref; + git_oid commit_oid; + git_commit *commit; + const git_signature *signature; + + /* + * The branch below points at a commit with angle brackets in the committer/author name + * committer 1323847743 +0100 + */ + cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/haacked")); + + git_revwalk_push(_walk, git_reference_oid(ref)); + cl_git_pass(git_revwalk_next(&commit_oid, _walk)); + + cl_git_pass(git_commit_lookup(&commit, _repo, git_reference_oid(ref))); + + signature = git_commit_committer(commit); + cl_assert_equal_s("Yu V. Bin Haacked", signature->email); + cl_assert_equal_s("", signature->name); + cl_assert_equal_i(1323847743, (int)signature->when.time); + cl_assert_equal_i(60, signature->when.offset); + + git_commit_free(commit); + git_reference_free(ref); +} From 8aedf1d5581f518da286ca4a33d6f7a98db38651 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 5 Jul 2012 17:02:03 +0200 Subject: [PATCH 097/123] signature: prevent angle bracket usage in identity --- include/git2/signature.h | 3 +++ src/signature.c | 24 +++++++++++++---- tests-clar/commit/signature.c | 50 ++++++++++++++++++++++------------- 3 files changed, 54 insertions(+), 23 deletions(-) diff --git a/include/git2/signature.h b/include/git2/signature.h index cbf94269f..cdbe67879 100644 --- a/include/git2/signature.h +++ b/include/git2/signature.h @@ -23,6 +23,9 @@ GIT_BEGIN_DECL * Create a new action signature. The signature must be freed * manually or using git_signature_free * + * Note: angle brackets ('<' and '>') characters are not allowed + * to be used in either the `name` or the `email` parameter. + * * @param sig_out new signature, in case of error NULL * @param name name of the person * @param email email of the person diff --git a/src/signature.c b/src/signature.c index 332bdf65f..1f788356b 100644 --- a/src/signature.c +++ b/src/signature.c @@ -40,7 +40,7 @@ static const char *skip_trailing_spaces(const char *buffer_start, const char *bu static int signature_error(const char *msg) { - giterr_set(GITERR_INVALID, "Failed to parse signature - %s", msg); + giterr_set(GITERR_INVALID, "Failed to process signature - %s", msg); return -1; } @@ -72,9 +72,16 @@ static int process_trimming(const char *input, char **storage, const char *input return 0; } +static bool contains_angle_brackets(const char *input) +{ + if (strchr(input, '<') != NULL) + return true; + + return strchr(input, '>') != NULL; +} + int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset) { - int error; git_signature *p = NULL; assert(name && email); @@ -84,11 +91,18 @@ int git_signature_new(git_signature **sig_out, const char *name, const char *ema p = git__calloc(1, sizeof(git_signature)); GITERR_CHECK_ALLOC(p); - if ((error = process_trimming(name, &p->name, name + strlen(name), 1)) < 0 || - (error = process_trimming(email, &p->email, email + strlen(email), 1)) < 0) + if (process_trimming(name, &p->name, name + strlen(name), 1) < 0 || + process_trimming(email, &p->email, email + strlen(email), 1) < 0) { git_signature_free(p); - return error; + return -1; + } + + if (contains_angle_brackets(p->email) || + contains_angle_brackets(p->name)) + { + git_signature_free(p); + return signature_error("Neither `name` nor `email` should contain angle brackets chars."); } p->when.time = time; diff --git a/tests-clar/commit/signature.c b/tests-clar/commit/signature.c index 290b11fa3..9364efb10 100644 --- a/tests-clar/commit/signature.c +++ b/tests-clar/commit/signature.c @@ -13,17 +13,39 @@ static int try_build_signature(const char *name, const char *email, git_time_t t return error; } - -void test_commit_signature__create_trim(void) +static void assert_name_and_email( + const char *expected_name, + const char *expected_email, + const char *name, + const char *email) { - // creating a signature trims leading and trailing spaces - git_signature *sign; - cl_git_pass(git_signature_new(&sign, " nulltoken ", " emeric.fermas@gmail.com ", 1234567890, 60)); - cl_assert(strcmp(sign->name, "nulltoken") == 0); - cl_assert(strcmp(sign->email, "emeric.fermas@gmail.com") == 0); - git_signature_free((git_signature *)sign); + git_signature *sign; + + cl_git_pass(git_signature_new(&sign, name, email, 1234567890, 60)); + cl_assert_equal_s(expected_name, sign->name); + cl_assert_equal_s(expected_email, sign->email); + + git_signature_free(sign); } +void test_commit_signature__leading_and_trailing_spaces_are_trimmed(void) +{ + assert_name_and_email("nulltoken", "emeric.fermas@gmail.com", " nulltoken ", " emeric.fermas@gmail.com "); +} + +void test_commit_signature__angle_brackets_in_names_are_not_supported(void) +{ + cl_git_fail(try_build_signature("Haack", "phil@haack", 1234567890, 60)); + cl_git_fail(try_build_signature("", "phil@haack", 1234567890, 60)); +} + +void test_commit_signature__angle_brackets_in_email_are_not_supported(void) +{ + cl_git_fail(try_build_signature("Phil Haack", ">phil@haack", 1234567890, 60)); + cl_git_fail(try_build_signature("Phil Haack", "phil@>haack", 1234567890, 60)); + cl_git_fail(try_build_signature("Phil Haack", "", 1234567890, 60)); +} void test_commit_signature__create_empties(void) { @@ -39,21 +61,13 @@ void test_commit_signature__create_empties(void) void test_commit_signature__create_one_char(void) { // creating a one character signature - git_signature *sign; - cl_git_pass(git_signature_new(&sign, "x", "foo@bar.baz", 1234567890, 60)); - cl_assert(strcmp(sign->name, "x") == 0); - cl_assert(strcmp(sign->email, "foo@bar.baz") == 0); - git_signature_free((git_signature *)sign); + assert_name_and_email("x", "foo@bar.baz", "x", "foo@bar.baz"); } void test_commit_signature__create_two_char(void) { // creating a two character signature - git_signature *sign; - cl_git_pass(git_signature_new(&sign, "xx", "x@y.z", 1234567890, 60)); - cl_assert(strcmp(sign->name, "xx") == 0); - cl_assert(strcmp(sign->email, "x@y.z") == 0); - git_signature_free((git_signature *)sign); + assert_name_and_email("xx", "foo@bar.baz", "xx", "foo@bar.baz"); } void test_commit_signature__create_zero_char(void) From 8f17ed801f211e8481b2e0903da547c9e329b010 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Tue, 10 Jul 2012 20:52:56 +0200 Subject: [PATCH 098/123] revparse: simplify the parsing of described object --- src/revparse.c | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index f9859b18b..10b8376f9 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -104,7 +104,16 @@ cleanup: return error; } -extern int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec); +static int maybe_sha_or_abbrev(git_object**out, git_repository *repo, const char *spec) +{ + git_oid oid; + size_t speclen = strlen(spec); + + if (git_oid_fromstrn(&oid, spec, speclen) < 0) + return GIT_ENOTFOUND; + + return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJ_ANY); +} static int maybe_describe(git_object**out, git_repository *repo, const char *spec) { @@ -123,21 +132,10 @@ static int maybe_describe(git_object**out, git_repository *repo, const char *spe if (!match) return GIT_ENOTFOUND; - return revparse_lookup_object(out, repo, substr+2); + return maybe_sha_or_abbrev(out, repo, substr+2); } -static int maybe_sha_or_abbrev(git_object**out, git_repository *repo, const char *spec) -{ - git_oid oid; - size_t speclen = strlen(spec); - - if (git_oid_fromstrn(&oid, spec, speclen) < 0) - return GIT_ENOTFOUND; - - return git_object_lookup_prefix(out, repo, &oid, speclen, GIT_OBJ_ANY); -} - -int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) +static int revparse_lookup_object(git_object **out, git_repository *repo, const char *spec) { int error; git_reference *ref; From 2b92a154b66f213b664e44544048a2df7708b9de Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 11 Jul 2012 11:20:20 +0200 Subject: [PATCH 099/123] commit: reduce code duplication --- src/commit.c | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/commit.c b/src/commit.c index a3baf9d4e..5acbbc39b 100644 --- a/src/commit.c +++ b/src/commit.c @@ -229,30 +229,29 @@ GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) GIT_COMMIT_GETTER(const git_oid *, tree_oid, &commit->tree_oid); - int git_commit_tree(git_tree **tree_out, git_commit *commit) { assert(commit); return git_tree_lookup(tree_out, commit->object.repo, &commit->tree_oid); } -int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) -{ - git_oid *parent_oid; - assert(commit); - - parent_oid = git_vector_get(&commit->parent_oids, n); - if (parent_oid == NULL) { - giterr_set(GITERR_INVALID, "Parent %u does not exist", n); - return GIT_ENOTFOUND; - } - - return git_commit_lookup(parent, commit->object.repo, parent_oid); -} - const git_oid *git_commit_parent_oid(git_commit *commit, unsigned int n) { assert(commit); return git_vector_get(&commit->parent_oids, n); } + +int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) +{ + const git_oid *parent_oid; + assert(commit); + + parent_oid = git_commit_parent_oid(commit, n); + if (parent_oid == NULL) { + giterr_set(GITERR_INVALID, "Parent %u does not exist", n); + return GIT_ENOTFOUND; + } + + return git_commit_lookup(parent, commit->object.repo, parent_oid); +} From b1aca6eae084ebe59c5a092314e94019c59ecec6 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 11 Jul 2012 16:14:12 +0200 Subject: [PATCH 100/123] commit: introduce git_commit_nth_gen_ancestor() --- include/git2/commit.h | 19 +++++++++++++ src/commit.c | 34 +++++++++++++++++++++++ tests-clar/commit/parent.c | 57 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 110 insertions(+) create mode 100644 tests-clar/commit/parent.c diff --git a/include/git2/commit.h b/include/git2/commit.h index 640adf5c2..5b6da520d 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -178,6 +178,25 @@ GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsig */ GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned int n); +/** + * Get the commit object that is the th generation ancestor + * of the named commit object, following only the first parents. + * The returned commit has to be freed by the caller. + * + * Passing `0` as the generation number returns another instance of the + * base commit itself. + * + * @param ancestor Pointer where to store the ancestor commit + * @param commit a previously loaded commit. + * @param n the requested generation + * @return 0 on success; GIT_ENOTFOUND if no matching ancestor exists + * or an error code + */ +int git_commit_nth_gen_ancestor( + git_commit **ancestor, + const git_commit *commit, + unsigned int n); + /** * Create a new commit in the repository using `git_object` * instances as parameters. diff --git a/src/commit.c b/src/commit.c index 5acbbc39b..32c47944b 100644 --- a/src/commit.c +++ b/src/commit.c @@ -255,3 +255,37 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) return git_commit_lookup(parent, commit->object.repo, parent_oid); } + +int git_commit_nth_gen_ancestor( + git_commit **ancestor, + const git_commit *commit, + unsigned int n) +{ + git_commit *current, *parent; + int error; + + assert(ancestor && commit); + + current = (git_commit *)commit; + + if (n == 0) + return git_commit_lookup( + ancestor, + commit->object.repo, + git_object_id((const git_object *)commit)); + + while (n--) { + error = git_commit_parent(&parent, (git_commit *)current, 0); + + if (current != commit) + git_commit_free(current); + + if (error < 0) + return error; + + current = parent; + } + + *ancestor = parent; + return 0; +} diff --git a/tests-clar/commit/parent.c b/tests-clar/commit/parent.c new file mode 100644 index 000000000..a00757732 --- /dev/null +++ b/tests-clar/commit/parent.c @@ -0,0 +1,57 @@ +#include "clar_libgit2.h" + +static git_repository *_repo; +static git_commit *commit; + +void test_commit_parent__initialize(void) +{ + git_oid oid; + + cl_git_pass(git_repository_open(&_repo, cl_fixture("testrepo.git"))); + + git_oid_fromstr(&oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + cl_git_pass(git_commit_lookup(&commit, _repo, &oid)); +} + +void test_commit_parent__cleanup(void) +{ + git_commit_free(commit); + git_repository_free(_repo); +} + +static void assert_nth_gen_parent(unsigned int gen, const char *expected_oid) +{ + git_commit *parent = NULL; + int error; + + error = git_commit_nth_gen_ancestor(&parent, commit, gen); + + if (expected_oid != NULL) { + cl_assert_equal_i(0, error); + cl_assert_equal_i(0, git_oid_streq(git_commit_id(parent), expected_oid)); + } else + cl_assert_equal_i(GIT_ENOTFOUND, error); + + git_commit_free(parent); +} + +/* + * $ git show be35~0 + * commit be3563ae3f795b2b4353bcce3a527ad0a4f7f644 + * + * $ git show be35~1 + * commit 9fd738e8f7967c078dceed8190330fc8648ee56a + * + * $ git show be35~3 + * commit 5b5b025afb0b4c913b4c338a42934a3863bf3644 + * + * $ git show be35~42 + * fatal: ambiguous argument 'be35~42': unknown revision or path not in the working tree. + */ +void test_commit_parent__can_retrieve_nth_generation_parent(void) +{ + assert_nth_gen_parent(0, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + assert_nth_gen_parent(1, "9fd738e8f7967c078dceed8190330fc8648ee56a"); + assert_nth_gen_parent(3, "5b5b025afb0b4c913b4c338a42934a3863bf3644"); + assert_nth_gen_parent(42, NULL); +} From 2d012c0c72e1c7ae6e418340a7bb4ab9dc0288bd Mon Sep 17 00:00:00 2001 From: nulltoken Date: Wed, 11 Jul 2012 16:52:02 +0200 Subject: [PATCH 101/123] revparse: deploy git_commit_nth_gen_ancestor() --- src/revparse.c | 23 ++--------------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 10b8376f9..670f67e1f 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -522,8 +522,7 @@ static int handle_caret_syntax(git_object **out, git_repository *repo, git_objec static int handle_linear_syntax(git_object **out, git_object *obj, const char *movement) { - git_commit *commit1, *commit2; - int i, n; + int n; /* Dereference until we reach a commit. */ if (dereference_to_type(&obj, obj, GIT_OBJ_COMMIT) < 0) { @@ -537,26 +536,8 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m } else if (git__strtol32(&n, movement, NULL, 0) < 0) { return GIT_ERROR; } - commit1 = (git_commit*)obj; - /* "~0" just returns the input */ - if (n == 0) { - *out = obj; - return 0; - } - - for (i=0; i Date: Wed, 11 Jul 2012 23:47:58 +0200 Subject: [PATCH 102/123] refs: readonly tests don't need a sandboxed repo --- tests-clar/refs/read.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests-clar/refs/read.c b/tests-clar/refs/read.c index 6838ead74..ce4eefeba 100644 --- a/tests-clar/refs/read.c +++ b/tests-clar/refs/read.c @@ -16,12 +16,12 @@ static git_repository *g_repo; void test_refs_read__initialize(void) { - g_repo = cl_git_sandbox_init("testrepo"); + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); } void test_refs_read__cleanup(void) { - cl_git_sandbox_cleanup(); + git_repository_free(g_repo); } void test_refs_read__loose_tag(void) From 84f18e358742b77bfc815f2a360a41f3f1b9abd7 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 00:44:07 +0200 Subject: [PATCH 103/123] refs: introduce git_reference_remote_tracking_from_branch() --- include/git2/refs.h | 21 +++++++++ src/refs.c | 74 ++++++++++++++++++++++++++++++++ tests-clar/refs/remotetracking.c | 49 +++++++++++++++++++++ 3 files changed, 144 insertions(+) create mode 100644 tests-clar/refs/remotetracking.c diff --git a/include/git2/refs.h b/include/git2/refs.h index 7f6eb0e9b..b119e90b1 100644 --- a/include/git2/refs.h +++ b/include/git2/refs.h @@ -363,6 +363,27 @@ GIT_EXTERN(int) git_reference_foreach_glob( */ GIT_EXTERN(int) git_reference_has_log(git_reference *ref); + +/** + * Return the reference supporting the remote tracking branch, + * given a reference branch. + * + * The input reference has to be located in the `refs/heads` + * namespace. + * + * @param tracking_ref Pointer where to store the retrieved + * reference. + * + * @param branch_ref A git local branch reference. + * + * @return 0 on success; GIT_ENOTFOUND when no remote tracking + * reference exists, otherwise an error code. + */ +GIT_EXTERN(int) git_reference_remote_tracking_from_branch( + git_reference **tracking_ref, + git_reference *branch_ref +); + /** @} */ GIT_END_DECL #endif diff --git a/src/refs.c b/src/refs.c index e8f9fc8dc..13022c7a5 100644 --- a/src/refs.c +++ b/src/refs.c @@ -11,6 +11,7 @@ #include "fileops.h" #include "pack.h" #include "reflog.h" +#include "config.h" #include #include @@ -1811,3 +1812,76 @@ int git_reference_has_log( return result; } + +//TODO: How about also taking care of local tracking branches? +//cf. http://alblue.bandlem.com/2011/07/git-tip-of-week-tracking-branches.html +int git_reference_remote_tracking_from_branch( + git_reference **tracking_ref, + git_reference *branch_ref) +{ + git_config *config = NULL; + const char *name, *remote, *merge; + git_buf buf = GIT_BUF_INIT; + int error = -1; + + assert(tracking_ref && branch_ref); + + name = git_reference_name(branch_ref); + + if (git__prefixcmp(name, GIT_REFS_HEADS_DIR)) { + giterr_set( + GITERR_INVALID, + "Failed to retrieve tracking reference - '%s' is not a branch.", + name); + return -1; + } + + if (git_repository_config(&config, branch_ref->owner) < 0) + return -1; + + if (git_buf_printf( + &buf, + "branch.%s.remote", + name + strlen(GIT_REFS_HEADS_DIR)) < 0) + goto cleanup; + + if ((error = git_config_get_string(&remote, config, git_buf_cstr(&buf))) < 0) + goto cleanup; + + error = -1; + + git_buf_clear(&buf); + + //TODO: Is it ok to fail when no merge target is found? + if (git_buf_printf( + &buf, + "branch.%s.merge", + name + strlen(GIT_REFS_HEADS_DIR)) < 0) + goto cleanup; + + if (git_config_get_string(&merge, config, git_buf_cstr(&buf)) < 0) + goto cleanup; + + //TODO: Should we test this? + if (git__prefixcmp(merge, GIT_REFS_HEADS_DIR)) + goto cleanup; + + git_buf_clear(&buf); + + if (git_buf_printf( + &buf, + "refs/remotes/%s/%s", + remote, + merge + strlen(GIT_REFS_HEADS_DIR)) < 0) + goto cleanup; + + error = git_reference_lookup( + tracking_ref, + branch_ref->owner, + git_buf_cstr(&buf)); + +cleanup: + git_config_free(config); + git_buf_free(&buf); + return error; +} diff --git a/tests-clar/refs/remotetracking.c b/tests-clar/refs/remotetracking.c new file mode 100644 index 000000000..c4ec588ee --- /dev/null +++ b/tests-clar/refs/remotetracking.c @@ -0,0 +1,49 @@ +#include "clar_libgit2.h" + +static git_repository *g_repo; + +void test_refs_remotetracking__initialize(void) +{ + cl_git_pass(git_repository_open(&g_repo, cl_fixture("testrepo.git"))); +} + +void test_refs_remotetracking__cleanup(void) +{ + git_repository_free(g_repo); +} + +void test_refs_remotetracking__unfound_returns_GIT_ENOTFOUND(void) +{ + git_reference *branch, *tracking; + + cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/heads/subtrees")); + + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_remote_tracking_from_branch(&tracking, branch)); + + git_reference_free(branch); +} + +void test_refs_remotetracking__retrieving_from_a_non_head_fails(void) +{ + git_reference *branch, *tracking; + + cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/tags/e90810b")); + + cl_git_fail(git_reference_remote_tracking_from_branch(&tracking, branch)); + + git_reference_free(branch); +} + +void test_refs_remotetracking__can_retrieve_a_remote_tracking_branch_reference(void) +{ + git_reference *branch, *tracking; + + cl_git_pass(git_reference_lookup(&branch, g_repo, "refs/heads/master")); + + cl_git_pass(git_reference_remote_tracking_from_branch(&tracking, branch)); + + cl_assert_equal_s("refs/remotes/test/master", git_reference_name(tracking)); + + git_reference_free(branch); + git_reference_free(tracking); +} From 12595ab8f91a71e5a596a883b31789d5317e9ec2 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 00:52:01 +0200 Subject: [PATCH 104/123] revparse: deploy git_reference_remote_tracking_from_branch() --- src/revparse.c | 32 ++++++-------------------------- 1 file changed, 6 insertions(+), 26 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 670f67e1f..2b03c86b4 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -249,32 +249,12 @@ static int walk_ref_history(git_object **out, git_repository *repo, const char * date_error = git__date_parse(×tamp, git_buf_cstr(&datebuf)); /* @{u} or @{upstream} -> upstream branch, for a tracking branch. This is stored in the config. */ - if (!git__prefixcmp(git_reference_name(disambiguated), GIT_REFS_HEADS_DIR) && - (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}"))) { - git_config *cfg; - if (!git_repository_config(&cfg, repo)) { - /* Is the ref a tracking branch? */ - const char *remote; - git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.remote", - git_reference_name(disambiguated) + strlen(GIT_REFS_HEADS_DIR)); - - if (!git_config_get_string(&remote, cfg, git_buf_cstr(&buf))) { - /* Yes. Find the first merge target name. */ - const char *mergetarget; - git_buf_clear(&buf); - git_buf_printf(&buf, "branch.%s.merge", - git_reference_name(disambiguated) + strlen(GIT_REFS_HEADS_DIR)); - - if (!git_config_get_string(&mergetarget, cfg, git_buf_cstr(&buf)) && - !git__prefixcmp(mergetarget, "refs/heads/")) { - /* Success. Look up the target and fetch the object. */ - git_buf_clear(&buf); - git_buf_printf(&buf, "refs/remotes/%s/%s", remote, mergetarget+11); - retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_buf_cstr(&buf)); - } - } - git_config_free(cfg); + if (!strcmp(reflogspec, "@{u}") || !strcmp(reflogspec, "@{upstream}")) { + git_reference *tracking; + + if (!(retcode = git_reference_remote_tracking_from_branch(&tracking, disambiguated))) { + retcode = revparse_lookup_fully_qualifed_ref(out, repo, git_reference_name(tracking)); + git_reference_free(tracking); } } From 1ebe432e2f685c72774aa5012f99fbb4845cffba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Jul 2012 20:33:30 +0200 Subject: [PATCH 105/123] commit: properly export git_commit_nth_gen_ancestor() --- include/git2/commit.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/git2/commit.h b/include/git2/commit.h index 5b6da520d..e8ecc808b 100644 --- a/include/git2/commit.h +++ b/include/git2/commit.h @@ -192,7 +192,7 @@ GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned i * @return 0 on success; GIT_ENOTFOUND if no matching ancestor exists * or an error code */ -int git_commit_nth_gen_ancestor( +GIT_EXTERN(int) git_commit_nth_gen_ancestor( git_commit **ancestor, const git_commit *commit, unsigned int n); From eca67c585e555d7999e436fda3f1d8d1ebda2329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Jul 2012 20:40:09 +0200 Subject: [PATCH 106/123] tests: fix git_odb_foreach() object count Some objects were added in another PR --- tests-clar/odb/foreach.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clar/odb/foreach.c b/tests-clar/odb/foreach.c index 6cb4faad2..525c70c09 100644 --- a/tests-clar/odb/foreach.c +++ b/tests-clar/odb/foreach.c @@ -32,5 +32,5 @@ static int foreach_cb(git_oid *oid, void *data) void test_odb_foreach__foreach(void) { cl_git_pass(git_odb_foreach(_odb, foreach_cb, NULL)); - cl_assert(nobj == 1681); + cl_assert(nobj == 1683); } From b7158c53a45a0e926550484f26eae49ffc3a5043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Jul 2012 20:48:46 +0200 Subject: [PATCH 107/123] Use GIT_INLINE instead of inline --- src/odb_loose.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/odb_loose.c b/src/odb_loose.c index ea51c4d14..2197a4264 100644 --- a/src/odb_loose.c +++ b/src/odb_loose.c @@ -682,7 +682,7 @@ struct foreach_state { void *data; }; -static inline int filename_to_oid(git_oid *oid, const char *ptr) +GIT_INLINE(int) filename_to_oid(git_oid *oid, const char *ptr) { int v, i = 0; if (strlen(ptr) != 41) From 72ee07876295c241892edf4ccde15caf2c657413 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 12 Jul 2012 11:48:12 -0700 Subject: [PATCH 108/123] Isolate khash inlines from global namespace khash.h was globally #define'ing "inline" which messes with other files. Let's keep it as "kh_inline". --- src/khash.h | 10 ++++++---- src/submodule.c | 6 +++--- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/khash.h b/src/khash.h index bd67fe1f7..242204464 100644 --- a/src/khash.h +++ b/src/khash.h @@ -131,7 +131,9 @@ typedef unsigned long long khint64_t; #endif #ifdef _MSC_VER -#define inline __inline +#define kh_inline __inline +#else +#define kh_inline inline #endif typedef khint32_t khint_t; @@ -345,7 +347,7 @@ static const double __ac_HASH_UPPER = 0.77; __KHASH_IMPL(name, SCOPE, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) #define KHASH_INIT(name, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) \ - KHASH_INIT2(name, static inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) + KHASH_INIT2(name, static kh_inline, khkey_t, khval_t, kh_is_map, __hash_func, __hash_equal) /* --- BEGIN OF HASH FUNCTIONS --- */ @@ -374,7 +376,7 @@ static const double __ac_HASH_UPPER = 0.77; @param s Pointer to a null terminated string @return The hash value */ -static inline khint_t __ac_X31_hash_string(const char *s) +static kh_inline khint_t __ac_X31_hash_string(const char *s) { khint_t h = (khint_t)*s; if (h) for (++s ; *s; ++s) h = (h << 5) - h + (khint_t)*s; @@ -391,7 +393,7 @@ static inline khint_t __ac_X31_hash_string(const char *s) */ #define kh_str_hash_equal(a, b) (strcmp(a, b) == 0) -static inline khint_t __ac_Wang_hash(khint_t key) +static kh_inline khint_t __ac_Wang_hash(khint_t key) { key += ~(key << 15); key ^= (key >> 10); diff --git a/src/submodule.c b/src/submodule.c index 3c07e657d..b8537cb8c 100644 --- a/src/submodule.c +++ b/src/submodule.c @@ -31,7 +31,7 @@ static git_cvar_map _sm_ignore_map[] = { {GIT_CVAR_STRING, "none", GIT_SUBMODULE_IGNORE_NONE} }; -static inline khint_t str_hash_no_trailing_slash(const char *s) +static kh_inline khint_t str_hash_no_trailing_slash(const char *s) { khint_t h; @@ -42,7 +42,7 @@ static inline khint_t str_hash_no_trailing_slash(const char *s) return h; } -static inline int str_equal_no_trailing_slash(const char *a, const char *b) +static kh_inline int str_equal_no_trailing_slash(const char *a, const char *b) { size_t alen = a ? strlen(a) : 0; size_t blen = b ? strlen(b) : 0; @@ -55,7 +55,7 @@ static inline int str_equal_no_trailing_slash(const char *a, const char *b) return (alen == blen && strncmp(a, b, alen) == 0); } -__KHASH_IMPL(str, static inline, const char *, void *, 1, str_hash_no_trailing_slash, str_equal_no_trailing_slash); +__KHASH_IMPL(str, static kh_inline, const char *, void *, 1, str_hash_no_trailing_slash, str_equal_no_trailing_slash); static git_submodule *submodule_alloc(const char *name) { From 39b8e047b4e18cb1de45335027e9c79a4c70a75b Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 12 Jul 2012 11:52:10 -0700 Subject: [PATCH 109/123] Missed a couple of khash inline dependencies --- src/oidmap.h | 2 +- src/strmap.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/oidmap.h b/src/oidmap.h index 858268c92..5a0bab6ec 100644 --- a/src/oidmap.h +++ b/src/oidmap.h @@ -34,7 +34,7 @@ GIT_INLINE(int) hash_git_oid_equal(const git_oid *a, const git_oid *b) } #define GIT__USE_OIDMAP \ - __KHASH_IMPL(oid, static inline, const git_oid *, void *, 1, hash_git_oid, hash_git_oid_equal) + __KHASH_IMPL(oid, static kh_inline, const git_oid *, void *, 1, hash_git_oid, hash_git_oid_equal) #define git_oidmap_alloc() kh_init(oid) #define git_oidmap_free(h) kh_destroy(oid,h), h = NULL diff --git a/src/strmap.h b/src/strmap.h index da5ca0dba..9972039a0 100644 --- a/src/strmap.h +++ b/src/strmap.h @@ -19,7 +19,7 @@ __KHASH_TYPE(str, const char *, void *); typedef khash_t(str) git_strmap; #define GIT__USE_STRMAP \ - __KHASH_IMPL(str, static inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) + __KHASH_IMPL(str, static kh_inline, const char *, void *, 1, kh_str_hash_func, kh_str_hash_equal) #define git_strmap_alloc() kh_init(str) #define git_strmap_free(h) kh_destroy(str, h), h = NULL From 465092ce3fd05a634cea1c0a81687d01390e6f00 Mon Sep 17 00:00:00 2001 From: Russell Belfer Date: Thu, 12 Jul 2012 11:56:50 -0700 Subject: [PATCH 110/123] Fix memory leak in test --- tests-clar/core/buffer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-clar/core/buffer.c b/tests-clar/core/buffer.c index 996cb7bcb..21aaaed7e 100644 --- a/tests-clar/core/buffer.c +++ b/tests-clar/core/buffer.c @@ -633,7 +633,7 @@ void test_core_buffer__rfind_variants(void) cl_assert(git_buf_rfind(&a, 'q') == -1); cl_assert(git_buf_rfind_next(&a, 'q') == -1); - git_buf_clear(&a); + git_buf_free(&a); } void test_core_buffer__puts_escaped(void) From 9f99c5de2e297a9aabc64b028069a4ca870db9d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Thu, 12 Jul 2012 21:04:09 +0200 Subject: [PATCH 111/123] travis: make it run the tests under valgrind --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2713651a8..c9d99d6f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: # Make sure CMake is installed install: - - sudo apt-get install cmake + - sudo apt-get install cmake valgrind # Run the Build script script: @@ -24,6 +24,7 @@ script: # Run Tests after_script: - ctest -V . + - if [ -f ./libgit2_clar ]; then valgrind --leak-check=full --show-reachable=yes ./libgit2_clar; else echo "Skipping valgrind"; fi # Only watch the development branch branches: From 1c3edb307842dede8d20cecc734359b68c67fd65 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 09:46:45 +0200 Subject: [PATCH 112/123] tree: prevent git_tree_entry_free() from segfaulting when being passed a NULL tree_entry --- src/tree.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tree.c b/src/tree.c index b609eea33..4d22f2f63 100644 --- a/src/tree.c +++ b/src/tree.c @@ -140,6 +140,9 @@ static int tree_key_search(git_vector *entries, const char *filename, size_t fil void git_tree_entry_free(git_tree_entry *entry) { + if (entry == NULL) + return; + git__free(entry); } From dc1f4b32d30ce715a58acdd249f15d08ce844233 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 10:52:19 +0200 Subject: [PATCH 113/123] tree: unfound tree entry returns GIT_ENOTFOUND --- src/tree.c | 2 +- tests-clar/object/tree/frompath.c | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tree.c b/src/tree.c index 4d22f2f63..31a581cdb 100644 --- a/src/tree.c +++ b/src/tree.c @@ -730,7 +730,7 @@ int git_tree_entry_bypath( if (!git_tree_entry__is_tree(entry)) { giterr_set(GITERR_TREE, "The path '%s' does not exist in the given tree", path); - return -1; + return GIT_ENOTFOUND; } /* If there's only a slash left in the path, we diff --git a/tests-clar/object/tree/frompath.c b/tests-clar/object/tree/frompath.c index ef092d1db..fd425517c 100644 --- a/tests-clar/object/tree/frompath.c +++ b/tests-clar/object/tree/frompath.c @@ -46,12 +46,12 @@ void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void) assert_tree_from_path(tree, "ab/", "ab"); assert_tree_from_path(tree, "ab/de/", "de"); - cl_must_fail(git_tree_entry_bypath(&e, tree, "i-do-not-exist.txt")); - cl_must_fail(git_tree_entry_bypath(&e, tree, "README/")); - cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/de/fgh/i-do-not-exist.txt")); - cl_must_fail(git_tree_entry_bypath(&e, tree, "nope/de/fgh/1.txt")); - cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt")); - cl_must_fail(git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt/")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "i-do-not-exist.txt")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "README/")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/de/fgh/i-do-not-exist.txt")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "nope/de/fgh/1.txt")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt")); + cl_assert_equal_i(GIT_ENOTFOUND, git_tree_entry_bypath(&e, tree, "ab/me-neither/fgh/2.txt/")); } void test_object_tree_frompath__fail_when_processing_an_invalid_path(void) From bb89cf9478bd6c1c5df1fbda2d82cc86a3ba5aed Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 10:57:31 +0200 Subject: [PATCH 114/123] revparse: simplify handling of the colon syntax --- src/revparse.c | 91 +++++++++----------------------------- tests-clar/refs/revparse.c | 18 +++++++- 2 files changed, 36 insertions(+), 73 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 2b03c86b4..e35c01add 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -520,88 +520,37 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m return git_commit_nth_gen_ancestor((git_commit **)out, (git_commit*)obj, n); } -static int oid_for_tree_path(git_oid *out, git_tree *tree, git_repository *repo, const char *path) -{ - char *str, *tok; - void *alloc; - git_tree *tree2 = tree; - const git_tree_entry *entry = NULL; - git_otype type; - - if (*path == '\0') { - git_oid_cpy(out, git_object_id((git_object *)tree)); - return 0; - } - - alloc = str = git__strdup(path); - - while ((tok = git__strtok(&str, "/\\")) != NULL) { - entry = git_tree_entry_byname(tree2, tok); - if (tree2 != tree) git_tree_free(tree2); - - if (entry == NULL) - break; - - type = git_tree_entry_type(entry); - - switch (type) { - case GIT_OBJ_TREE: - if (*str == '\0') - break; - if (git_tree_lookup(&tree2, repo, &entry->oid) < 0) { - git__free(alloc); - return GIT_ERROR; - } - break; - case GIT_OBJ_BLOB: - if (*str != '\0') { - entry = NULL; - goto out; - } - break; - default: - /* TODO: support submodules? */ - giterr_set(GITERR_INVALID, "Unimplemented"); - git__free(alloc); - return GIT_ERROR; - } - } - -out: - if (!entry) { - giterr_set(GITERR_INVALID, "Invalid tree path '%s'", path); - git__free(alloc); - return GIT_ENOTFOUND; - } - - git_oid_cpy(out, git_tree_entry_id(entry)); - git__free(alloc); - return 0; -} - static int handle_colon_syntax(git_object **out, git_repository *repo, git_object *obj, const char *path) { - git_tree *tree; - git_oid oid; - int error; + git_object *tree = obj; + int error = -1; + git_tree_entry *entry = NULL; /* Dereference until we reach a tree. */ - if (dereference_to_type(&obj, obj, GIT_OBJ_TREE) < 0) { + if (dereference_to_type(&tree, obj, GIT_OBJ_TREE) < 0) return GIT_ERROR; - } - tree = (git_tree*)obj; - /* Find the blob or tree at the given path. */ - error = oid_for_tree_path(&oid, tree, repo, path); - git_tree_free(tree); + if (*path == '\0') + return git_object_lookup(out, repo, git_object_id(tree), GIT_OBJ_TREE); - if (error < 0) - return error; + /* + * TODO: Handle the relative path syntax + * (:./relative/path and :../relative/path) + */ + if ((error = git_tree_entry_bypath(&entry, (git_tree *)tree, path)) < 0) + goto cleanup; - return git_object_lookup(out, repo, &oid, GIT_OBJ_ANY); + error = git_tree_entry_to_object(out, repo, entry); + +cleanup: + git_tree_entry_free(entry); + if (tree != obj) + git_object_free(tree); + + return error; } static int revparse_global_grep(git_object **out, git_repository *repo, const char *pattern) diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index dbc002d38..aba105bc0 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -325,12 +325,26 @@ void test_refs_revparse__colon(void) test_object("subtrees:nope", NULL); test_object("test/master^1:branch_file.txt", NULL); - /* Trees */ + /* From tags */ + test_object("test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); + test_object("tags/test:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); + test_object("e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); + test_object("tags/e90810b:readme.txt", "0266163a49e280c4f5ed1e08facd36a2bd716bcf"); + + /* From commits */ + test_object("a65f:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); + + /* From trees */ + test_object("a65f^{tree}:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); + test_object("944c:branch_file.txt", "3697d64be941a53d4ae8f6a271e4e3fa56b022cc"); + + /* Retrieving trees */ test_object("master:", "944c0f6e4dfa41595e6eb3ceecdb14f50fe18162"); test_object("subtrees:", "ae90f12eea699729ed24555e40b9fd669da12a12"); test_object("subtrees:ab", "f1425cef211cc08caa31e7b545ffb232acb098c3"); + test_object("subtrees:ab/", "f1425cef211cc08caa31e7b545ffb232acb098c3"); - /* Blobs */ + /* Retrieving blobs */ test_object("subtrees:ab/4.txt", "d6c93164c249c8000205dd4ec5cbca1b516d487f"); test_object("subtrees:ab/de/fgh/1.txt", "1f67fc4386b2d171e0d21be1c447e12660561f9b"); test_object("master:README", "a8233120f6ad708f843d861ce2b7228ec4e3dec6"); From d1b7921a48161cf6fe5bb85a5da4c0bdac3c0df7 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 11:46:20 +0200 Subject: [PATCH 115/123] revparse: fix disambiguation of refs and abbrev oids --- src/revparse.c | 14 +++++------ tests-clar/refs/revparse.c | 49 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index e35c01add..270bdaa23 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -147,13 +147,6 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const if (error < 0 && error != GIT_ENOTFOUND) return error; - error = maybe_sha_or_abbrev(out, repo, spec); - if (!error) - return 0; - - if (error < 0 && error != GIT_ENOTFOUND) - return error; - error = disambiguate_refname(&ref, repo, spec); if (!error) { error = git_object_lookup(out, repo, git_reference_oid(ref), GIT_OBJ_ANY); @@ -161,6 +154,13 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const return 0; } + if (error < 0 && error != GIT_ENOTFOUND) + return error; + + error = maybe_sha_or_abbrev(out, repo, spec); + if (!error) + return 0; + if (error < 0 && error != GIT_ENOTFOUND) return error; diff --git a/tests-clar/refs/revparse.c b/tests-clar/refs/revparse.c index aba105bc0..56d57b21c 100644 --- a/tests-clar/refs/revparse.c +++ b/tests-clar/refs/revparse.c @@ -354,3 +354,52 @@ void test_refs_revparse__colon(void) test_object(":/packed commit t", "41bc8c69075bbdb46c5c6f0566cc8cc5b46e8bd9"); test_object("test/master^2:branch_file.txt", "45b983be36b73c0788dc9cbcb76cbb80fc7bb057"); } + +void test_refs_revparse__disambiguation(void) +{ + /* + * $ git show e90810b + * tag e90810b + * Tagger: Vicent Marti + * Date: Thu Aug 12 03:59:17 2010 +0200 + * + * This is a very simple tag. + * + * commit e90810b8df3e80c413d903f631643c716887138d + * Author: Vicent Marti + * Date: Thu Aug 5 18:42:20 2010 +0200 + * + * Test commit 2 + * + * diff --git a/readme.txt b/readme.txt + * index 6336846..0266163 100644 + * --- a/readme.txt + * +++ b/readme.txt + * @@ -1 +1,2 @@ + * Testing a readme.txt + * +Now we add a single line here + * + * $ git show-ref e90810b + * 7b4384978d2493e851f9cca7858815fac9b10980 refs/tags/e90810b + * + */ + test_object("e90810b", "7b4384978d2493e851f9cca7858815fac9b10980"); + + /* + * $ git show e90810 + * commit e90810b8df3e80c413d903f631643c716887138d + * Author: Vicent Marti + * Date: Thu Aug 5 18:42:20 2010 +0200 + * + * Test commit 2 + * + * diff --git a/readme.txt b/readme.txt + * index 6336846..0266163 100644 + * --- a/readme.txt + * +++ b/readme.txt + * @@ -1 +1,2 @@ + * Testing a readme.txt + * +Now we add a single line here + */ + test_object("e90810", "e90810b8df3e80c413d903f631643c716887138d"); +} From 5a6f31f28b58d93232b742f02ad0a6f64c0dfbb8 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 13:20:29 +0200 Subject: [PATCH 116/123] revparse: only allow decimal specifiers in carete and tilde synatx passing 0 to git_strol(32|64) let the implementation guess if it's dealing with an octal number or a decimal one. Let's make it safe and ensure that both 'HEAD@{010}' and 'HEAD@{10}' point at the same commit. --- src/revparse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/revparse.c b/src/revparse.c index 270bdaa23..2631e50d2 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -482,7 +482,7 @@ static int handle_caret_syntax(git_object **out, git_repository *repo, git_objec if (movementlen == 0) { n = 1; } else { - git__strtol32(&n, movement, NULL, 0); + git__strtol32(&n, movement, NULL, 10); } commit = (git_commit*)obj; @@ -513,7 +513,7 @@ static int handle_linear_syntax(git_object **out, git_object *obj, const char *m /* "~" is the same as "~1" */ if (*movement == '\0') { n = 1; - } else if (git__strtol32(&n, movement, NULL, 0) < 0) { + } else if (git__strtol32(&n, movement, NULL, 10) < 0) { return GIT_ERROR; } From b5f90115240e333a60809ef912934bce8afae0c1 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 22:31:53 +0200 Subject: [PATCH 117/123] revparse: fix propagation of error --- src/revparse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/revparse.c b/src/revparse.c index 2631e50d2..777dee685 100644 --- a/src/revparse.c +++ b/src/revparse.c @@ -151,7 +151,7 @@ static int revparse_lookup_object(git_object **out, git_repository *repo, const if (!error) { error = git_object_lookup(out, repo, git_reference_oid(ref), GIT_OBJ_ANY); git_reference_free(ref); - return 0; + return error; } if (error < 0 && error != GIT_ENOTFOUND) From 151d81a647600601a867a1415336b74d4888d7d8 Mon Sep 17 00:00:00 2001 From: nulltoken Date: Thu, 12 Jul 2012 22:03:28 +0200 Subject: [PATCH 118/123] refs: fix a memory leak --- src/refs.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/refs.c b/src/refs.c index 13022c7a5..b3c140bec 100644 --- a/src/refs.c +++ b/src/refs.c @@ -1397,6 +1397,9 @@ int git_reference_rename(git_reference *ref, const char *new_name, int force) head_target = git_reference_target(head); if (head_target && !strcmp(head_target, ref->name)) { + git_reference_free(head); + head = NULL; + if (git_reference_create_symbolic(&head, ref->owner, "HEAD", new_name, 1) < 0) { giterr_set(GITERR_REFERENCE, "Failed to update HEAD after renaming reference"); From b3237ac31313240272ee0d48a19b4edfdfc1d718 Mon Sep 17 00:00:00 2001 From: Ignacio Casal Quinteiro Date: Fri, 13 Jul 2012 17:13:35 +0200 Subject: [PATCH 119/123] Add support for the more standard LIB_INSTALL_DIR variable --- CMakeLists.txt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a8e646d06..6a0ffdd42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -62,7 +62,7 @@ ENDIF() # Installation paths SET(INSTALL_BIN bin CACHE PATH "Where to install binaries to.") -SET(INSTALL_LIB lib CACHE PATH "Where to install libraries to.") +SET(LIB_INSTALL_DIR lib CACHE PATH "Where to install libraries to.") SET(INSTALL_INC include CACHE PATH "Where to install headers to.") # Build options @@ -159,13 +159,18 @@ IF (MSVC) SET_SOURCE_FILES_PROPERTIES(src/win32/precompiled.c COMPILE_FLAGS "/Ycprecompiled.h") ENDIF () +# Backward compatibility with INSTALL_LIB variable +if (INSTALL_LIB) + set(LIB_INSTALL_DIR "${INSTALL_LIB}") +ENDIF() + # Install INSTALL(TARGETS git2 RUNTIME DESTINATION ${INSTALL_BIN} - LIBRARY DESTINATION ${INSTALL_LIB} - ARCHIVE DESTINATION ${INSTALL_LIB} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} ) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${INSTALL_LIB}/pkgconfig ) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/libgit2.pc DESTINATION ${LIB_INSTALL_DIR}/pkgconfig ) INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} ) INSTALL(FILES include/git2.h DESTINATION ${INSTALL_INC} ) From 7b8c9e123d3925f4d7aaa614a591e4188a80d464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 13 Jul 2012 20:46:16 +0200 Subject: [PATCH 120/123] pkt: correctly advertise capabilitites The correct way to advertise out capabilities is by appending them to the first 'want' line, using SP as separator, instead of NUL as the server does. Inconsistent documentation lead to the use of NUL in libgit2. Fix this so we can request much more efficient packs from the remote which reduces the indexing time considerably. --- src/pkt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pkt.c b/src/pkt.c index 88510f4b1..e003b97e2 100644 --- a/src/pkt.c +++ b/src/pkt.c @@ -296,7 +296,7 @@ static int buffer_want_with_caps(git_remote_head *head, git_transport_caps *caps git_buf_grow(buf, git_buf_len(buf) + len); git_oid_fmt(oid, &head->oid); - return git_buf_printf(buf, "%04xwant %s%c%s\n", len, oid, 0, capstr); + return git_buf_printf(buf, "%04xwant %s %s\n", len, oid, capstr); } /* From d1af70b0509916abcb4724e0d8cdbee8ebf6bb2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Fri, 13 Jul 2012 20:43:56 +0200 Subject: [PATCH 121/123] indexer: delay resolving deltas Not all delta bases are available on the first try. By delaying resolving all deltas until the end, we avoid decompressing some of the data twice or even more times, saving effort and time. --- src/indexer.c | 58 ++++++++++++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/src/indexer.c b/src/indexer.c index 1f0ca82a2..797a58275 100644 --- a/src/indexer.c +++ b/src/indexer.c @@ -169,29 +169,14 @@ cleanup: } /* Try to store the delta so we can try to resolve it later */ -static int store_delta(git_indexer_stream *idx) +static int store_delta(git_indexer_stream *idx, git_off_t entry_start, size_t entry_size, git_otype type) { - git_otype type; git_mwindow *w = NULL; - git_mwindow_file *mwf = &idx->pack->mwf; - git_off_t entry_start = idx->off; struct delta_info *delta; - size_t entry_size; git_rawobj obj; int error; - /* - * ref-delta objects can refer to object that we haven't - * found yet, so give it another opportunity - */ - if (git_packfile_unpack_header(&entry_size, &type, mwf, &w, &idx->off) < 0) - return -1; - - git_mwindow_close(&w); - - /* If it's not a delta, mark it as failure, we can't do anything with it */ - if (type != GIT_OBJ_REF_DELTA && type != GIT_OBJ_OFS_DELTA) - return -1; + assert(type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA); if (type == GIT_OBJ_REF_DELTA) { idx->off += GIT_OID_RAWSZ; @@ -350,26 +335,43 @@ int git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t siz while (processed < idx->nr_objects) { git_rawobj obj; git_off_t entry_start = idx->off; + size_t entry_size; + git_otype type; + git_mwindow *w = NULL; if (idx->pack->mwf.size <= idx->off + 20) return 0; + error = git_packfile_unpack_header(&entry_size, &type, mwf, &w, &idx->off); + if (error == GIT_EBUFS) { + idx->off = entry_start; + return 0; + } + if (error < 0) + return -1; + + git_mwindow_close(&w); + + if (type == GIT_OBJ_REF_DELTA || type == GIT_OBJ_OFS_DELTA) { + error = store_delta(idx, entry_start, entry_size, type); + if (error == GIT_EBUFS) { + idx->off = entry_start; + return 0; + } + if (error < 0) + return error; + + continue; + } + + idx->off = entry_start; error = git_packfile_unpack(&obj, idx->pack, &idx->off); if (error == GIT_EBUFS) { idx->off = entry_start; return 0; } - - if (error < 0) { - idx->off = entry_start; - error = store_delta(idx); - - if (error == GIT_EBUFS) - return 0; - if (error < 0) - return error; - continue; - } + if (error < 0) + return -1; if (hash_and_save(idx, &obj, entry_start) < 0) goto on_error; From 227f31311979a2fdb1ffc8dbcb4cf0737e7bc899 Mon Sep 17 00:00:00 2001 From: Vicent Marti Date: Sun, 15 Jul 2012 14:11:58 +0200 Subject: [PATCH 122/123] attr: Rename the `git_attr__` exports Pevents collisions with the original libgit, which also exports those exact symbols. Fixes #822 --- include/git2/attr.h | 16 ++++++++-------- src/attr_file.c | 14 +++++++------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/include/git2/attr.h b/include/git2/attr.h index 8f5a1268d..fad7183da 100644 --- a/include/git2/attr.h +++ b/include/git2/attr.h @@ -30,7 +30,7 @@ GIT_BEGIN_DECL * Then for file `xyz.c` looking up attribute "foo" gives a value for * which `GIT_ATTR_TRUE(value)` is true. */ -#define GIT_ATTR_TRUE(attr) ((attr) == git_attr__true) +#define GIT_ATTR_TRUE(attr) ((attr) == git_l_attr__true) /** * GIT_ATTR_FALSE checks if an attribute is set off. In core git @@ -44,7 +44,7 @@ GIT_BEGIN_DECL * Then for file `zyx.h` looking up attribute "foo" gives a value for * which `GIT_ATTR_FALSE(value)` is true. */ -#define GIT_ATTR_FALSE(attr) ((attr) == git_attr__false) +#define GIT_ATTR_FALSE(attr) ((attr) == git_l_attr__false) /** * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This @@ -62,7 +62,7 @@ GIT_BEGIN_DECL * file `onefile.rb` or looking up "bar" on any file will all give * `GIT_ATTR_UNSPECIFIED(value)` of true. */ -#define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_attr__unset) +#define GIT_ATTR_UNSPECIFIED(attr) (!(attr) || (attr) == git_l_attr__unset) /** * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as @@ -75,12 +75,12 @@ GIT_BEGIN_DECL * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true. */ #define GIT_ATTR_HAS_VALUE(attr) \ - ((attr) && (attr) != git_attr__unset && \ - (attr) != git_attr__true && (attr) != git_attr__false) + ((attr) && (attr) != git_l_attr__unset && \ + (attr) != git_l_attr__true && (attr) != git_attr__false) -GIT_EXTERN(const char *) git_attr__true; -GIT_EXTERN(const char *) git_attr__false; -GIT_EXTERN(const char *) git_attr__unset; +GIT_EXTERN(const char *) git_l_attr__true; +GIT_EXTERN(const char *) git_l_attr__false; +GIT_EXTERN(const char *) git_l_attr__unset; /** * Check attribute flags: Reading values from index and working directory. diff --git a/src/attr_file.c b/src/attr_file.c index ca2f8fb58..0dad09727 100644 --- a/src/attr_file.c +++ b/src/attr_file.c @@ -5,9 +5,9 @@ #include "git2/tree.h" #include -const char *git_attr__true = "[internal]__TRUE__"; -const char *git_attr__false = "[internal]__FALSE__"; -const char *git_attr__unset = "[internal]__UNSET__"; +const char *git_l_attr__true = "[internal]__TRUE__"; +const char *git_l_attr__false = "[internal]__FALSE__"; +const char *git_l_attr__unset = "[internal]__UNSET__"; static int sort_by_hash_and_name(const void *a_raw, const void *b_raw); static void git_attr_rule__clear(git_attr_rule *rule); @@ -503,14 +503,14 @@ int git_attr_assignment__parse( } assign->name_hash = 5381; - assign->value = git_attr__true; + assign->value = git_l_attr__true; /* look for magic name prefixes */ if (*scan == '-') { - assign->value = git_attr__false; + assign->value = git_l_attr__false; scan++; } else if (*scan == '!') { - assign->value = git_attr__unset; /* explicit unspecified state */ + assign->value = git_l_attr__unset; /* explicit unspecified state */ scan++; } else if (*scan == '#') /* comment rest of line */ break; @@ -546,7 +546,7 @@ int git_attr_assignment__parse( } /* expand macros (if given a repo with a macro cache) */ - if (repo != NULL && assign->value == git_attr__true) { + if (repo != NULL && assign->value == git_l_attr__true) { git_attr_rule *macro = git_attr_cache__lookup_macro(repo, assign->name); From 77ace82d7ab60fad62a02d272a37d8c4891f59a3 Mon Sep 17 00:00:00 2001 From: Michael Schubert Date: Mon, 16 Jul 2012 12:41:30 +0200 Subject: [PATCH 123/123] libgit2.pc.in: also switch to LIB_INSTALL_DIR b3237ac3 changed CMakeList.txt to use the more standard LIB_INSTALL_DIR variable instead of INSTALL_LIB, but forgot to change libgit2.pc.in etc. accordingly. --- README.md | 2 +- libgit2.pc.in | 2 +- packaging/rpm/libgit2.spec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e8dc36a16..0075e53db 100644 --- a/README.md +++ b/README.md @@ -67,7 +67,7 @@ For more advanced use or questions about CMake please read