Commit 54993167 by Ben Straub

Merge branch 'development' into blame_rebased

Conflicts:
	include/git2.h
parents 1a68c168 8821c9aa
# Travis-CI Build for libgit2 # Travis-CI Build for libgit2
# see travis-ci.org for details # see travis-ci.org for details
# As CMake is not officially supported we use erlang VMs
language: c language: c
compiler: compiler:
...@@ -18,26 +17,18 @@ matrix: ...@@ -18,26 +17,18 @@ matrix:
- compiler: i586-mingw32msvc-gcc - compiler: i586-mingw32msvc-gcc
env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON" env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON"
# Make sure CMake is installed
install: install:
- sudo apt-get update >/dev/null - sudo apt-get -qq update
- sudo apt-get -q install cmake valgrind - sudo apt-get -qq install cmake libssh2-1-dev openssh-client openssh-server
# Run the Build script # Run the Build script and tests
script: script:
- mkdir _temp - script/cibuild.sh
- git init --bare _temp/test.git
- git daemon --listen=localhost --export-all --enable=receive-pack --base-path=_temp _temp 2>/dev/null &
- export GITTEST_REMOTE_URL="git://localhost/test.git"
- mkdir _build
- cd _build
- cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS
- cmake --build . --target install
- ctest -V .
# Run Tests # Run Tests
after_success: after_success:
- valgrind --leak-check=full --show-reachable=yes --suppressions=../libgit2_clar.supp ./libgit2_clar -ionline - sudo apt-get -qq install valgrind
- valgrind --leak-check=full --show-reachable=yes --suppressions=./libgit2_clar.supp _build/libgit2_clar -ionline
# Only watch the development branch # Only watch the development branch
branches: branches:
......
...@@ -29,17 +29,16 @@ OPTION( PROFILE "Generate profiling information" OFF ) ...@@ -29,17 +29,16 @@ OPTION( PROFILE "Generate profiling information" OFF )
OPTION( ENABLE_TRACE "Enables tracing support" OFF ) OPTION( ENABLE_TRACE "Enables tracing support" OFF )
OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF ) OPTION( LIBGIT2_FILENAME "Name of the produced binary" OFF )
OPTION( ANDROID "Build for android NDK" OFF )
IF(MSVC) IF(MSVC)
# This option is only availalbe when building with MSVC. By default, # This option is only available when building with MSVC. By default, libgit2
# libgit2 is build using the stdcall calling convention, as that's what # is build using the cdecl calling convention, which is useful if you're
# the CLR expects by default and how the Windows API is built. # writing C. However, the CLR and Win32 API both expect stdcall.
#
# If you are writing a C or C++ program and want to link to libgit2, you
# have to either:
# - Add /Gz to the compiler options of _your_ program / library.
# - Turn this off by invoking CMake with the "-DSTDCALL=Off" argument.
# #
OPTION( STDCALL "Build libgit2 with the __stdcall convention" ON ) # If you are writing a CLR program and want to link to libgit2, you'll want
# to turn this on by invoking CMake with the "-DSTDCALL=ON" argument.
OPTION( STDCALL "Build libgit2 with the __stdcall convention" OFF )
# This option must match the settings used in your program, in particular if you # This option must match the settings used in your program, in particular if you
# are linking statically # are linking statically
...@@ -110,7 +109,7 @@ ELSE () ...@@ -110,7 +109,7 @@ ELSE ()
ELSE() ELSE()
MESSAGE("http-parser was not found or is too old; using bundled 3rd-party sources.") MESSAGE("http-parser was not found or is too old; using bundled 3rd-party sources.")
INCLUDE_DIRECTORIES(deps/http-parser) INCLUDE_DIRECTORIES(deps/http-parser)
FILE(GLOB SRC_HTTP deps/http-parser/*.c) FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
ENDIF() ENDIF()
ENDIF() ENDIF()
...@@ -130,30 +129,28 @@ IF (ENABLE_TRACE STREQUAL "ON") ...@@ -130,30 +129,28 @@ IF (ENABLE_TRACE STREQUAL "ON")
ENDIF() ENDIF()
# Include POSIX regex when it is required # Include POSIX regex when it is required
IF(WIN32 OR AMIGA) IF(WIN32 OR AMIGA OR ANDROID)
INCLUDE_DIRECTORIES(deps/regex) INCLUDE_DIRECTORIES(deps/regex)
SET(SRC_REGEX deps/regex/regex.c) SET(SRC_REGEX deps/regex/regex.c)
ENDIF() ENDIF()
# Optional external dependency: zlib # Optional external dependency: zlib
IF(NOT ZLIB_LIBRARY) # It's optional, but FIND_PACKAGE gives a warning that looks more like an
# It's optional, but FIND_PACKAGE gives a warning that looks more like an # error.
# error. FIND_PACKAGE(ZLIB QUIET)
FIND_PACKAGE(ZLIB QUIET)
ENDIF()
IF (ZLIB_FOUND) IF (ZLIB_FOUND)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
LINK_LIBRARIES(${ZLIB_LIBRARIES}) LINK_LIBRARIES(${ZLIB_LIBRARIES})
# Fake the message CMake would have shown # Fake the message CMake would have shown
MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}") MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}")
ELSEIF (NOT ZLIB_LIBRARY) ELSE()
MESSAGE( "zlib was not found; using bundled 3rd-party sources." ) MESSAGE( "zlib was not found; using bundled 3rd-party sources." )
INCLUDE_DIRECTORIES(deps/zlib) INCLUDE_DIRECTORIES(deps/zlib)
ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP) ADD_DEFINITIONS(-DNO_VIZ -DSTDC -DNO_GZIP)
FILE(GLOB SRC_ZLIB deps/zlib/*.c) FILE(GLOB SRC_ZLIB deps/zlib/*.c deps/zlib/*.h)
ENDIF() ENDIF()
IF(NOT LIBSSH2_LIBRARY) IF (NOT MINGW)
FIND_PACKAGE(LIBSSH2 QUIET) FIND_PACKAGE(LIBSSH2 QUIET)
ENDIF() ENDIF()
IF (LIBSSH2_FOUND) IF (LIBSSH2_FOUND)
...@@ -162,6 +159,7 @@ IF (LIBSSH2_FOUND) ...@@ -162,6 +159,7 @@ IF (LIBSSH2_FOUND)
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES}) SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
ENDIF() ENDIF()
# Platform specific compilation flags # Platform specific compilation flags
IF (MSVC) IF (MSVC)
...@@ -287,19 +285,19 @@ ENDIF() ...@@ -287,19 +285,19 @@ ENDIF()
ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64) ADD_DEFINITIONS(-D_FILE_OFFSET_BITS=64)
# Collect sourcefiles # Collect sourcefiles
FILE(GLOB SRC_H include/git2/*.h) FILE(GLOB SRC_H include/git2.h include/git2/*.h include/git2/sys/*.h)
# On Windows use specific platform sources # On Windows use specific platform sources
IF (WIN32 AND NOT CYGWIN) IF (WIN32 AND NOT CYGWIN)
ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501) ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0501)
FILE(GLOB SRC_OS src/win32/*.c) FILE(GLOB SRC_OS src/win32/*.c src/win32/*.h)
ELSEIF (AMIGA) ELSEIF (AMIGA)
ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R) ADD_DEFINITIONS(-DNO_ADDRINFO -DNO_READDIR_R)
FILE(GLOB SRC_OS src/amiga/*.c) FILE(GLOB SRC_OS src/amiga/*.c src/amiga/*.h)
ELSE() ELSE()
FILE(GLOB SRC_OS src/unix/*.c) FILE(GLOB SRC_OS src/unix/*.c src/unix/*.h)
ENDIF() ENDIF()
FILE(GLOB SRC_GIT2 src/*.c src/transports/*.c src/xdiff/*.c) FILE(GLOB SRC_GIT2 src/*.c src/*.h src/transports/*.c src/transports/*.h src/xdiff/*.c src/xdiff/*.h)
# Determine architecture of the machine # Determine architecture of the machine
IF (CMAKE_SIZEOF_VOID_P EQUAL 8) IF (CMAKE_SIZEOF_VOID_P EQUAL 8)
...@@ -311,7 +309,7 @@ ELSE() ...@@ -311,7 +309,7 @@ ELSE()
ENDIF() ENDIF()
# Compile and link libgit2 # Compile and link libgit2
ADD_LIBRARY(git2 ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC}) ADD_LIBRARY(git2 ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1} ${WIN_RC})
TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(git2 ${SSL_LIBRARIES})
TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES}) TARGET_LINK_LIBRARIES(git2 ${SSH_LIBRARIES})
TARGET_OS_LIBRARIES(git2) TARGET_OS_LIBRARIES(git2)
...@@ -361,12 +359,12 @@ IF (BUILD_CLAR) ...@@ -361,12 +359,12 @@ IF (BUILD_CLAR)
ADD_DEFINITIONS(-DCLAR_RESOURCES=\"${TEST_RESOURCES}\") ADD_DEFINITIONS(-DCLAR_RESOURCES=\"${TEST_RESOURCES}\")
INCLUDE_DIRECTORIES(${CLAR_PATH}) INCLUDE_DIRECTORIES(${CLAR_PATH})
FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c) FILE(GLOB_RECURSE SRC_TEST ${CLAR_PATH}/*/*.c ${CLAR_PATH}/*/*.h)
SET(SRC_CLAR "${CLAR_PATH}/main.c" "${CLAR_PATH}/clar_libgit2.c" "${CLAR_PATH}/clar.c") SET(SRC_CLAR "${CLAR_PATH}/main.c" "${CLAR_PATH}/clar_libgit2.c" "${CLAR_PATH}/clar.c")
ADD_CUSTOM_COMMAND( ADD_CUSTOM_COMMAND(
OUTPUT ${CLAR_PATH}/clar.suite OUTPUT ${CLAR_PATH}/clar.suite
COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline . COMMAND ${PYTHON_EXECUTABLE} generate.py -f -xonline -xstress .
DEPENDS ${SRC_TEST} DEPENDS ${SRC_TEST}
WORKING_DIRECTORY ${CLAR_PATH} WORKING_DIRECTORY ${CLAR_PATH}
) )
...@@ -375,7 +373,7 @@ IF (BUILD_CLAR) ...@@ -375,7 +373,7 @@ IF (BUILD_CLAR)
${CLAR_PATH}/clar.c ${CLAR_PATH}/clar.c
PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite) PROPERTIES OBJECT_DEPENDS ${CLAR_PATH}/clar.suite)
ADD_EXECUTABLE(libgit2_clar ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1}) ADD_EXECUTABLE(libgit2_clar ${SRC_H} ${SRC_GIT2} ${SRC_OS} ${SRC_CLAR} ${SRC_TEST} ${SRC_ZLIB} ${SRC_HTTP} ${SRC_REGEX} ${SRC_SHA1})
TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSL_LIBRARIES})
TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES}) TARGET_LINK_LIBRARIES(libgit2_clar ${SSH_LIBRARIES})
...@@ -411,23 +409,5 @@ IF (TAGS) ...@@ -411,23 +409,5 @@ IF (TAGS)
ENDIF () ENDIF ()
IF (BUILD_EXAMPLES) IF (BUILD_EXAMPLES)
FILE(GLOB_RECURSE EXAMPLE_SRC examples/network/*.c) ADD_SUBDIRECTORY(examples)
ADD_EXECUTABLE(cgit2 ${EXAMPLE_SRC})
IF(WIN32)
TARGET_LINK_LIBRARIES(cgit2 git2)
ELSE()
TARGET_LINK_LIBRARIES(cgit2 git2 pthread)
ENDIF()
ADD_EXECUTABLE(git-diff examples/diff.c)
TARGET_LINK_LIBRARIES(git-diff git2)
ADD_EXECUTABLE(git-general examples/general.c)
TARGET_LINK_LIBRARIES(git-general git2)
ADD_EXECUTABLE(git-showindex examples/showindex.c)
TARGET_LINK_LIBRARIES(git-showindex git2)
ADD_EXECUTABLE(git-rev-list examples/rev-list.c)
TARGET_LINK_LIBRARIES(git-rev-list git2)
ENDIF () ENDIF ()
...@@ -48,6 +48,12 @@ Please include a nice description of your changes with your PR; if we have ...@@ -48,6 +48,12 @@ Please include a nice description of your changes with your PR; if we have
to read the whole diff to figure out why you're contributing in the first to read the whole diff to figure out why you're contributing in the first
place, you're less likely to get feedback and have your change merged in. place, you're less likely to get feedback and have your change merged in.
If you are working on a particular area then feel free to submit a PR that
highlights your work in progress (and flag in the PR title that it's not
ready to merge). This will help in getting visibility for your fix, allow
others to comment early on the changes and also let others know that you
are currently working on something.
## Porting Code From Other Open-Source Projects ## Porting Code From Other Open-Source Projects
`libgit2` is licensed under the terms of the GPL v2 with a linking `libgit2` is licensed under the terms of the GPL v2 with a linking
...@@ -57,14 +63,17 @@ The most common case is porting code from core Git. Git is a pure GPL ...@@ -57,14 +63,17 @@ The most common case is porting code from core Git. Git is a pure GPL
project, which means that in order to port code to this project, we need the project, which means that in order to port code to this project, we need the
explicit permission of the author. Check the explicit permission of the author. Check the
[`git.git-authors`](https://github.com/libgit2/libgit2/blob/development/git.git-authors) [`git.git-authors`](https://github.com/libgit2/libgit2/blob/development/git.git-authors)
file for authors who have already consented; feel free to add someone if file for authors who have already consented.
you've obtained their consent.
Other licenses have other requirements; check the license of the library Other licenses have other requirements; check the license of the library
you're porting code *from* to see what you need to do. As a general rule, you're porting code *from* to see what you need to do. As a general rule,
MIT and BSD (3-clause) licenses are typically no problem. Apache 2.0 MIT and BSD (3-clause) licenses are typically no problem. Apache 2.0
license typically doesn't work due to GPL incompatibility. license typically doesn't work due to GPL incompatibility.
If you are pulling in code from core Git, another project or code you've pulled from
a forum / Stack Overflow then please flag this in your PR and also make sure you've
given proper credit to the original author in the code snippet.
## Style Guide ## Style Guide
`libgit2` is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C) `libgit2` is written in [ANSI C](http://en.wikipedia.org/wiki/ANSI_C)
......
...@@ -928,3 +928,66 @@ necessary. Here is a sample; alter the names: ...@@ -928,3 +928,66 @@ necessary. Here is a sample; alter the names:
Ty Coon, President of Vice Ty Coon, President of Vice
That's all there is to it! That's all there is to it!
----------------------------------------------------------------------
Portions of src/win32/posix_w32.c are derrived from link_win32.c in PHP:
--------------------------------------------------------------------
The PHP License, version 3.01
Copyright (c) 1999 - 2012 The PHP Group. All rights reserved.
--------------------------------------------------------------------
Redistribution and use in source and binary forms, with or without
modification, is permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
3. The name "PHP" must not be used to endorse or promote products
derived from this software without prior written permission. For
written permission, please contact group@php.net.
4. Products derived from this software may not be called "PHP", nor
may "PHP" appear in their name, without prior written permission
from group@php.net. You may indicate that your software works in
conjunction with PHP by saying "Foo for PHP" instead of calling
it "PHP Foo" or "phpfoo"
5. The PHP Group may publish revised and/or new versions of the
license from time to time. Each version will be given a
distinguishing version number.
Once covered code has been published under a particular version
of the license, you may always continue to use it under the terms
of that version. You may also choose to use such covered code
under the terms of any subsequent version of the license
published by the PHP Group. No one other than the PHP Group has
the right to modify the terms applicable to covered code created
under this License.
6. Redistributions of any form whatsoever must retain the following
acknowledgment:
"This product includes PHP software, freely available from
<http://www.php.net/software/>".
THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND
ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP
DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------
PLATFORM=$(shell uname -o) PLATFORM=$(shell uname -s)
ifneq (,$(CROSS_COMPILE))
PREFIX=$(CROSS_COMPILE)-
else
PREFIX=
endif
MINGW=0
ifneq (,$(findstring MINGW32,$(PLATFORM)))
MINGW=1
endif
ifneq (,$(findstring mingw,$(CROSS_COMPILE)))
MINGW=1
endif
rm=rm -f rm=rm -f
AR=ar cq AR=$(PREFIX)ar cq
RANLIB=ranlib RANLIB=$(PREFIX)ranlib
LIBNAME=libgit2.a LIBNAME=libgit2.a
ifeq ($(PLATFORM),Msys)
ifeq ($(MINGW),1)
CC=gcc CC=gcc
else else
CC=cc CC=cc
endif endif
CC:=$(PREFIX)$(CC)
INCLUDES= -I. -Isrc -Iinclude -Ideps/http-parser -Ideps/zlib INCLUDES= -I. -Isrc -Iinclude -Ideps/http-parser -Ideps/zlib
DEFINES= $(INCLUDES) -DNO_VIZ -DSTDC -DNO_GZIP -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(EXTRA_DEFINES) DEFINES= $(INCLUDES) -DNO_VIZ -DSTDC -DNO_GZIP -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE $(EXTRA_DEFINES)
...@@ -17,10 +35,10 @@ CFLAGS= -g $(DEFINES) -Wall -Wextra -O2 $(EXTRA_CFLAGS) ...@@ -17,10 +35,10 @@ CFLAGS= -g $(DEFINES) -Wall -Wextra -O2 $(EXTRA_CFLAGS)
SRCS = $(wildcard src/*.c) $(wildcard src/transports/*.c) $(wildcard src/xdiff/*.c) $(wildcard deps/http-parser/*.c) $(wildcard deps/zlib/*.c) src/hash/hash_generic.c SRCS = $(wildcard src/*.c) $(wildcard src/transports/*.c) $(wildcard src/xdiff/*.c) $(wildcard deps/http-parser/*.c) $(wildcard deps/zlib/*.c) src/hash/hash_generic.c
ifeq ($(PLATFORM),Msys) ifeq ($(MINGW),1)
SRCS += $(wildcard src/win32/*.c) $(wildcard src/compat/*.c) deps/regex/regex.c SRCS += $(wildcard src/win32/*.c) $(wildcard src/compat/*.c) deps/regex/regex.c
INCLUDES += -Ideps/regex INCLUDES += -Ideps/regex
DEFINES += -DWIN32 -D_WIN32_WINNT=0x0501 DEFINES += -DWIN32 -D_WIN32_WINNT=0x0501 -D__USE_MINGW_ANSI_STDIO=1
else else
SRCS += $(wildcard src/unix/*.c) SRCS += $(wildcard src/unix/*.c)
CFLAGS += -fPIC CFLAGS += -fPIC
......
...@@ -11,20 +11,24 @@ libgit2 is licensed under a **very permissive license** (GPLv2 with a special Li ...@@ -11,20 +11,24 @@ libgit2 is licensed under a **very permissive license** (GPLv2 with a special Li
This basically means that you can link it (unmodified) with any kind of software without having to This basically means that you can link it (unmodified) with any kind of software without having to
release its source code. release its source code.
* Mailing list: ~~<libgit2@librelist.org>~~
The libgit2 mailing list has
traditionally been hosted in Librelist, but Librelist is and has always
been a shitshow. We encourage you to [open an issue](https://github.com/libgit2/libgit2/issues)
on GitHub instead for any questions regarding the library.
* Archives: <http://librelist.com/browser/libgit2/>
* Website: <http://libgit2.github.com> * Website: <http://libgit2.github.com>
* StackOverflow Tag: [libgit2](http://stackoverflow.com/questions/tagged/libgit2)
* Issues: <https://github.com/libgit2/libgit2/issues>
* API documentation: <http://libgit2.github.com/libgit2> * API documentation: <http://libgit2.github.com/libgit2>
* IRC: #libgit2 on irc.freenode.net. * IRC: #libgit2 on irc.freenode.net.
* Mailing list: The libgit2 mailing list was
traditionally hosted in Librelist but has been deprecated. We encourage you to
[use StackOverflow](http://stackoverflow.com/questions/tagged/libgit2) instead for any questions regarding
the library, or [open an issue](https://github.com/libgit2/libgit2/issues)
on GitHub for bug reports. The mailing list archives are still available at
<http://librelist.com/browser/libgit2/>.
What It Can Do What It Can Do
================================== ==================================
libgit2 is already very usable. libgit2 is already very usable and is being used in production for many applications including the GitHub.com site, in Plastic SCM
and also powering Microsoft's Visual Studio tools for Git. The library provides:
* SHA conversions, formatting and shortening * SHA conversions, formatting and shortening
* abstracted ODB backend system * abstracted ODB backend system
...@@ -104,6 +108,28 @@ See [the wiki] ...@@ -104,6 +108,28 @@ See [the wiki]
(https://github.com/libgit2/libgit2/wiki/Building-libgit2-on-Windows) (https://github.com/libgit2/libgit2/wiki/Building-libgit2-on-Windows)
for more detailed instructions. for more detailed instructions.
Android
-------
Extract toolchain from NDK using, `make-standalone-toolchain.sh` script.
Optionaly, crosscompile and install OpenSSL inside of it. Then create CMake
toolchain file that configures paths to your crosscompiler (substitude `{PATH}`
with full path to the toolchain):
SET(CMAKE_SYSTEM_NAME Linux)
SET(CMAKE_SYSTEM_VERSION Android)
SET(CMAKE_C_COMPILER {PATH}/bin/arm-linux-androideabi-gcc)
SET(CMAKE_CXX_COMPILER {PATH}/bin/arm-linux-androideabi-g++)
SET(CMAKE_FIND_ROOT_PATH {PATH}/sysroot/)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Add `-DCMAKE_TOOLCHAIN_FILE={pathToToolchainFile} -DANDROID=1` to cmake command
when configuring.
Language Bindings Language Bindings
================================== ==================================
...@@ -118,9 +144,9 @@ Here are the bindings to libgit2 that are currently available: ...@@ -118,9 +144,9 @@ Here are the bindings to libgit2 that are currently available:
* Delphi * Delphi
* GitForDelphi <https://github.com/libgit2/GitForDelphi> * GitForDelphi <https://github.com/libgit2/GitForDelphi>
* Erlang * Erlang
* Geef <https://github.com/schacon/geef> * Geef <https://github.com/carlosmn/geef>
* Go * Go
* go-git <https://github.com/str1ngs/go-git> * git2go <https://github.com/libgit2/git2go>
* GObject * GObject
* libgit2-glib <https://live.gnome.org/Libgit2-glib> * libgit2-glib <https://live.gnome.org/Libgit2-glib>
* Haskell * Haskell
...@@ -128,8 +154,8 @@ Here are the bindings to libgit2 that are currently available: ...@@ -128,8 +154,8 @@ Here are the bindings to libgit2 that are currently available:
* Lua * Lua
* luagit2 <https://github.com/libgit2/luagit2> * luagit2 <https://github.com/libgit2/luagit2>
* .NET * .NET
* libgit2net, low level bindings <https://github.com/txdv/libgit2net>
* libgit2sharp <https://github.com/libgit2/libgit2sharp> * libgit2sharp <https://github.com/libgit2/libgit2sharp>
* libgit2net, low level bindings superceeded by libgit2sharp <https://github.com/txdv/libgit2net>
* Node.js * Node.js
* node-gitteh <https://github.com/libgit2/node-gitteh> * node-gitteh <https://github.com/libgit2/node-gitteh>
* nodegit <https://github.com/tbranyen/nodegit> * nodegit <https://github.com/tbranyen/nodegit>
......
FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h)
ADD_EXECUTABLE(cgit2 ${SRC_EXAMPLE_GIT2})
IF(WIN32 OR ANDROID)
TARGET_LINK_LIBRARIES(cgit2 git2)
ELSE()
TARGET_LINK_LIBRARIES(cgit2 git2 pthread)
ENDIF()
FILE(GLOB SRC_EXAMPLE_APPS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.c)
FOREACH(src_app ${SRC_EXAMPLE_APPS})
STRING(REPLACE ".c" "" app_name ${src_app})
ADD_EXECUTABLE(${app_name} ${src_app})
TARGET_LINK_LIBRARIES(${app_name} git2)
ENDFOREACH()
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
CC = gcc CC = gcc
CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers CFLAGS = -g -I../include -I../src -Wall -Wextra -Wmissing-prototypes -Wno-missing-field-initializers
LFLAGS = -L../build -lgit2 -lz LFLAGS = -L../build -lgit2 -lz
APPS = general showindex diff rev-list cat-file APPS = general showindex diff rev-list cat-file status log rev-parse init
all: $(APPS) all: $(APPS)
......
#include <git2.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
enum print_options {
SKIP = 1,
VERBOSE = 2,
UPDATE = 4,
};
struct print_payload {
enum print_options options;
git_repository *repo;
};
void init_array(git_strarray *array, int argc, char **argv)
{
unsigned int i;
array->count = argc;
array->strings = malloc(sizeof(char*) * array->count);
assert(array->strings!=NULL);
for(i=0; i<array->count; i++) {
array->strings[i]=argv[i];
}
return;
}
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload)
{
struct print_payload p = *(struct print_payload*)(payload);
int ret;
git_status_t status;
(void)matched_pathspec;
if (git_status_file(&status, p.repo, path)) {
return -1; //abort
}
if (status & GIT_STATUS_WT_MODIFIED ||
status & GIT_STATUS_WT_NEW) {
printf("add '%s'\n", path);
ret = 0;
} else {
ret = 1;
}
if(p.options & SKIP) {
ret = 1;
}
return ret;
}
void print_usage(void)
{
fprintf(stderr, "usage: add [options] [--] file-spec [file-spec] [...]\n\n");
fprintf(stderr, "\t-n, --dry-run dry run\n");
fprintf(stderr, "\t-v, --verbose be verbose\n");
fprintf(stderr, "\t-u, --update update tracked files\n");
}
int main (int argc, char** argv)
{
git_index_matched_path_cb matched_cb = NULL;
git_repository *repo = NULL;
git_index *index;
git_strarray array = {0};
int i, options = 0;
struct print_payload payload = {0};
for (i = 1; i < argc; ++i) {
if (argv[i][0] != '-') {
break;
}
else if(!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")) {
options |= VERBOSE;
}
else if(!strcmp(argv[i], "--dry-run") || !strcmp(argv[i], "-n")) {
options |= SKIP;
}
else if(!strcmp(argv[i], "--update") || !strcmp(argv[i], "-u")) {
options |= UPDATE;
}
else if(!strcmp(argv[i], "-h")) {
print_usage();
break;
}
else if(!strcmp(argv[i], "--")) {
i++;
break;
}
else {
fprintf(stderr, "Unsupported option %s.\n", argv[i]);
print_usage();
return 1;
}
}
if (argc<=i) {
print_usage();
return 1;
}
git_threads_init();
init_array(&array, argc-i, argv+i);
if (git_repository_open(&repo, ".") < 0) {
fprintf(stderr, "No git repository\n");
return 1;
}
if (git_repository_index(&index, repo) < 0) {
fprintf(stderr, "Could not open repository index\n");
return 1;
}
if (options&VERBOSE || options&SKIP) {
matched_cb = &print_matched_cb;
}
payload.options = options;
payload.repo = repo;
if (options&UPDATE) {
git_index_update_all(index, &array, matched_cb, &payload);
} else {
git_index_add_all(index, &array, 0, matched_cb, &payload);
}
git_index_write(index);
git_index_free(index);
git_repository_free(repo);
git_threads_shutdown();
return 0;
}
/*
* This is a sample program that is similar to "git init". See the
* documentation for that (try "git help init") to understand what this
* program is emulating.
*
* This demonstrates using the libgit2 APIs to initialize a new repository.
*
* This also contains a special additional option that regular "git init"
* does not support which is "--initial-commit" to make a first empty commit.
* That is demonstrated in the "create_initial_commit" helper function.
*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* 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 <stdio.h>
#include <git2.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/* not actually good error handling */
static void fail(const char *msg, const char *arg)
{
if (arg)
fprintf(stderr, "%s %s\n", msg, arg);
else
fprintf(stderr, "%s\n", msg);
exit(1);
}
static void usage(const char *error, const char *arg)
{
fprintf(stderr, "error: %s '%s'\n", error, arg);
fprintf(stderr, "usage: init [-q | --quiet] [--bare] "
"[--template=<dir>] [--shared[=perms]] <directory>\n");
exit(1);
}
/* simple string prefix test used in argument parsing */
static size_t is_prefixed(const char *arg, const char *pfx)
{
size_t len = strlen(pfx);
return !strncmp(arg, pfx, len) ? len : 0;
}
/* parse the tail of the --shared= argument */
static uint32_t parse_shared(const char *shared)
{
if (!strcmp(shared, "false") || !strcmp(shared, "umask"))
return GIT_REPOSITORY_INIT_SHARED_UMASK;
else if (!strcmp(shared, "true") || !strcmp(shared, "group"))
return GIT_REPOSITORY_INIT_SHARED_GROUP;
else if (!strcmp(shared, "all") || !strcmp(shared, "world") ||
!strcmp(shared, "everybody"))
return GIT_REPOSITORY_INIT_SHARED_ALL;
else if (shared[0] == '0') {
long val;
char *end = NULL;
val = strtol(shared + 1, &end, 8);
if (end == shared + 1 || *end != 0)
usage("invalid octal value for --shared", shared);
return (uint32_t)val;
}
else
usage("unknown value for --shared", shared);
return 0;
}
/* forward declaration of helper to make an empty parent-less commit */
static void create_initial_commit(git_repository *repo);
int main(int argc, char *argv[])
{
git_repository *repo = NULL;
int no_options = 1, quiet = 0, bare = 0, initial_commit = 0, i;
uint32_t shared = GIT_REPOSITORY_INIT_SHARED_UMASK;
const char *template = NULL, *gitdir = NULL, *dir = NULL;
size_t pfxlen;
git_threads_init();
/* Process arguments */
for (i = 1; i < argc; ++i) {
char *a = argv[i];
if (a[0] == '-')
no_options = 0;
if (a[0] != '-') {
if (dir != NULL)
usage("extra argument", a);
dir = a;
}
else if (!strcmp(a, "-q") || !strcmp(a, "--quiet"))
quiet = 1;
else if (!strcmp(a, "--bare"))
bare = 1;
else if ((pfxlen = is_prefixed(a, "--template=")) > 0)
template = a + pfxlen;
else if (!strcmp(a, "--separate-git-dir"))
gitdir = argv[++i];
else if ((pfxlen = is_prefixed(a, "--separate-git-dir=")) > 0)
gitdir = a + pfxlen;
else if (!strcmp(a, "--shared"))
shared = GIT_REPOSITORY_INIT_SHARED_GROUP;
else if ((pfxlen = is_prefixed(a, "--shared=")) > 0)
shared = parse_shared(a + pfxlen);
else if (!strcmp(a, "--initial-commit"))
initial_commit = 1;
else
usage("unknown option", a);
}
if (!dir)
usage("must specify directory to init", NULL);
/* Initialize repository */
if (no_options) {
/* No options were specified, so let's demonstrate the default
* simple case of git_repository_init() API usage...
*/
if (git_repository_init(&repo, dir, 0) < 0)
fail("Could not initialize repository", dir);
}
else {
/* Some command line options were specified, so we'll use the
* extended init API to handle them
*/
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
if (bare)
opts.flags |= GIT_REPOSITORY_INIT_BARE;
if (template) {
opts.flags |= GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
opts.template_path = template;
}
if (gitdir) {
/* if you specified a separate git directory, then initialize
* the repository at that path and use the second path as the
* working directory of the repository (with a git-link file)
*/
opts.workdir_path = dir;
dir = gitdir;
}
if (shared != 0)
opts.mode = shared;
if (git_repository_init_ext(&repo, dir, &opts) < 0)
fail("Could not initialize repository", dir);
}
/* Print a message to stdout like "git init" does */
if (!quiet) {
if (bare || gitdir)
dir = git_repository_path(repo);
else
dir = git_repository_workdir(repo);
printf("Initialized empty Git repository in %s\n", dir);
}
/* As an extension to the basic "git init" command, this example
* gives the option to create an empty initial commit. This is
* mostly to demonstrate what it takes to do that, but also some
* people like to have that empty base commit in their repo.
*/
if (initial_commit) {
create_initial_commit(repo);
printf("Created empty initial commit\n");
}
git_repository_free(repo);
git_threads_shutdown();
return 0;
}
/* Unlike regular "git init", this example shows how to create an initial
* empty commit in the repository. This is the helper function that does
* that.
*/
static void create_initial_commit(git_repository *repo)
{
git_signature *sig;
git_index *index;
git_oid tree_id, commit_id;
git_tree *tree;
/* First use the config to initialize a commit signature for the user */
if (git_signature_default(&sig, repo) < 0)
fail("Unable to create a commit signature.",
"Perhaps 'user.name' and 'user.email' are not set");
/* Now let's create an empty tree for this commit */
if (git_repository_index(&index, repo) < 0)
fail("Could not open repository index", NULL);
/* Outside of this example, you could call git_index_add_bypath()
* here to put actual files into the index. For our purposes, we'll
* leave it empty for now.
*/
if (git_index_write_tree(&tree_id, index) < 0)
fail("Unable to write initial tree from index", NULL);
git_index_free(index);
if (git_tree_lookup(&tree, repo, &tree_id) < 0)
fail("Could not look up initial tree", NULL);
/* Ready to create the initial commit
*
* Normally creating a commit would involve looking up the current
* HEAD commit and making that be the parent of the initial commit,
* but here this is the first commit so there will be no parent.
*/
if (git_commit_create_v(
&commit_id, repo, "HEAD", sig, sig,
NULL, "Initial commit", tree, 0) < 0)
fail("Could not create the initial commit", NULL);
/* Clean up so we don't leak memory */
git_tree_free(tree);
git_signature_free(sig);
}
This diff is collapsed. Click to expand it.
...@@ -11,7 +11,8 @@ OBJECTS = \ ...@@ -11,7 +11,8 @@ OBJECTS = \
ls-remote.o \ ls-remote.o \
fetch.o \ fetch.o \
clone.o \ clone.o \
index-pack.o index-pack.o \
common.o
all: $(OBJECTS) all: $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES) $(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES)
......
...@@ -9,19 +9,6 @@ ...@@ -9,19 +9,6 @@
# include <unistd.h> # include <unistd.h>
#endif #endif
/* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/
* with permission of the original author, Martin Pool.
* http://sourcefrog.net/weblog/software/languages/C/unused.html
*/
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
typedef struct progress_data { typedef struct progress_data {
git_transfer_progress fetch_progress; git_transfer_progress fetch_progress;
size_t completed_steps; size_t completed_steps;
...@@ -63,24 +50,6 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa ...@@ -63,24 +50,6 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa
print_progress(pd); print_progress(pd);
} }
static int cred_acquire(git_cred **out,
const char * UNUSED(url),
const char * UNUSED(username_from_url),
unsigned int UNUSED(allowed_types),
void * UNUSED(payload))
{
char username[128] = {0};
char password[128] = {0};
printf("Username: ");
scanf("%s", username);
/* Yup. Right there on your terminal. Careful where you copy/paste output. */
printf("Password: ");
scanf("%s", password);
return git_cred_userpass_plaintext_new(out, username, password);
}
int do_clone(git_repository *repo, int argc, char **argv) int do_clone(git_repository *repo, int argc, char **argv)
{ {
...@@ -107,7 +76,7 @@ int do_clone(git_repository *repo, int argc, char **argv) ...@@ -107,7 +76,7 @@ int do_clone(git_repository *repo, int argc, char **argv)
clone_opts.checkout_opts = checkout_opts; clone_opts.checkout_opts = checkout_opts;
clone_opts.fetch_progress_cb = &fetch_progress; clone_opts.fetch_progress_cb = &fetch_progress;
clone_opts.fetch_progress_payload = &pd; clone_opts.fetch_progress_payload = &pd;
clone_opts.cred_acquire_cb = cred_acquire; clone_opts.cred_acquire_cb = cred_acquire_cb;
// Do the clone // Do the clone
error = git_clone(&cloned_repo, url, path, &clone_opts); error = git_clone(&cloned_repo, url, path, &clone_opts);
......
#include "common.h"
#include <stdio.h>
/* Shamelessly borrowed from http://stackoverflow.com/questions/3417837/
* with permission of the original author, Martin Pool.
* http://sourcefrog.net/weblog/software/languages/C/unused.html
*/
#ifdef UNUSED
#elif defined(__GNUC__)
# define UNUSED(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define UNUSED(x) /*@unused@*/ x
#else
# define UNUSED(x) x
#endif
int cred_acquire_cb(git_cred **out,
const char * UNUSED(url),
const char * UNUSED(username_from_url),
unsigned int UNUSED(allowed_types),
void * UNUSED(payload))
{
char username[128] = {0};
char password[128] = {0};
printf("Username: ");
scanf("%s", username);
/* Yup. Right there on your terminal. Careful where you copy/paste output. */
printf("Password: ");
scanf("%s", password);
return git_cred_userpass_plaintext_new(out, username, password);
}
...@@ -12,6 +12,12 @@ int fetch(git_repository *repo, int argc, char **argv); ...@@ -12,6 +12,12 @@ int fetch(git_repository *repo, int argc, char **argv);
int index_pack(git_repository *repo, int argc, char **argv); int index_pack(git_repository *repo, int argc, char **argv);
int do_clone(git_repository *repo, int argc, char **argv); int do_clone(git_repository *repo, int argc, char **argv);
int cred_acquire_cb(git_cred **out,
const char * url,
const char * username_from_url,
unsigned int allowed_types,
void *payload);
#ifndef PRIuZ #ifndef PRIuZ
/* Define the printf format specifer to use for size_t output */ /* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__) #if defined(_MSC_VER) || defined(__MINGW32__)
......
...@@ -92,6 +92,7 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -92,6 +92,7 @@ int fetch(git_repository *repo, int argc, char **argv)
callbacks.update_tips = &update_cb; callbacks.update_tips = &update_cb;
callbacks.progress = &progress_cb; callbacks.progress = &progress_cb;
git_remote_set_callbacks(remote, &callbacks); git_remote_set_callbacks(remote, &callbacks);
git_remote_set_cred_acquire_cb(remote, &cred_acquire_cb, NULL);
// Set up the information for the background worker thread // Set up the information for the background worker thread
data.remote = remote; data.remote = remote;
......
...@@ -14,31 +14,6 @@ static int show_ref__cb(git_remote_head *head, void *payload) ...@@ -14,31 +14,6 @@ static int show_ref__cb(git_remote_head *head, void *payload)
return 0; return 0;
} }
static int use_unnamed(git_repository *repo, const char *url)
{
git_remote *remote = NULL;
int error;
// Create an instance of a remote from the URL. The transport to use
// is detected from the URL
error = git_remote_create_inmemory(&remote, repo, NULL, url);
if (error < 0)
goto cleanup;
// When connecting, the underlying code needs to know wether we
// want to push or fetch
error = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (error < 0)
goto cleanup;
// With git_remote_ls we can retrieve the advertised heads
error = git_remote_ls(remote, &show_ref__cb, NULL);
cleanup:
git_remote_free(remote);
return error;
}
static int use_remote(git_repository *repo, char *name) static int use_remote(git_repository *repo, char *name)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
...@@ -46,8 +21,13 @@ static int use_remote(git_repository *repo, char *name) ...@@ -46,8 +21,13 @@ static int use_remote(git_repository *repo, char *name)
// Find the remote by name // Find the remote by name
error = git_remote_load(&remote, repo, name); error = git_remote_load(&remote, repo, name);
if (error < 0) if (error < 0) {
goto cleanup; error = git_remote_create_inmemory(&remote, repo, NULL, name);
if (error < 0)
goto cleanup;
}
git_remote_set_cred_acquire_cb(remote, &cred_acquire_cb, NULL);
error = git_remote_connect(remote, GIT_DIRECTION_FETCH); error = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (error < 0) if (error < 0)
...@@ -72,12 +52,7 @@ int ls_remote(git_repository *repo, int argc, char **argv) ...@@ -72,12 +52,7 @@ int ls_remote(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
/* If there's a ':' in the name, assume it's an URL */ error = use_remote(repo, argv[1]);
if (strchr(argv[1], ':') != NULL) {
error = use_unnamed(repo, argv[1]);
} else {
error = use_remote(repo, argv[1]);
}
return error; return error;
} }
#include <stdio.h>
#include <git2.h>
#include <stdlib.h>
#include <string.h>
static void check(int error, const char *message, const char *arg)
{
if (!error)
return;
if (arg)
fprintf(stderr, "%s %s (%d)\n", message, arg, error);
else
fprintf(stderr, "%s(%d)\n", message, error);
exit(1);
}
static void usage(const char *message, const char *arg)
{
if (message && arg)
fprintf(stderr, "%s: %s\n", message, arg);
else if (message)
fprintf(stderr, "%s\n", message);
fprintf(stderr, "usage: rev-parse [ --option ] <args>...\n");
exit(1);
}
struct parse_state {
git_repository *repo;
const char *repodir;
int not;
};
static int parse_revision(struct parse_state *ps, const char *revstr)
{
git_revspec rs;
char str[GIT_OID_HEXSZ + 1];
if (!ps->repo) {
if (!ps->repodir)
ps->repodir = ".";
check(git_repository_open_ext(&ps->repo, ps->repodir, 0, NULL),
"Could not open repository from", ps->repodir);
}
check(git_revparse(&rs, ps->repo, revstr), "Could not parse", revstr);
if ((rs.flags & GIT_REVPARSE_SINGLE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
printf("%s\n", str);
git_object_free(rs.from);
}
else if ((rs.flags & GIT_REVPARSE_RANGE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.to));
printf("%s\n", str);
git_object_free(rs.to);
if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
git_oid base;
check(git_merge_base(&base, ps->repo,
git_object_id(rs.from), git_object_id(rs.to)),
"Could not find merge base", revstr);
git_oid_tostr(str, sizeof(str), &base);
printf("%s\n", str);
}
git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
printf("^%s\n", str);
git_object_free(rs.from);
}
else {
check(0, "Invalid results from git_revparse", revstr);
}
return 0;
}
int main(int argc, char *argv[])
{
int i;
char *a;
struct parse_state ps;
git_threads_init();
memset(&ps, 0, sizeof(ps));
for (i = 1; i < argc; ++i) {
a = argv[i];
if (a[0] != '-') {
if (parse_revision(&ps, a) != 0)
break;
} else if (!strcmp(a, "--not"))
ps.not = !ps.not;
else if (!strncmp(a, "--git-dir=", strlen("--git-dir=")))
ps.repodir = a + strlen("--git-dir=");
else
usage("Cannot handle argument", a);
}
git_repository_free(ps.repo);
git_threads_shutdown();
return 0;
}
...@@ -56,6 +56,7 @@ ...@@ -56,6 +56,7 @@
#include "git2/message.h" #include "git2/message.h"
#include "git2/pack.h" #include "git2/pack.h"
#include "git2/stash.h" #include "git2/stash.h"
#include "git2/pathspec.h"
#include "git2/blame.h" #include "git2/blame.h"
#endif #endif
...@@ -162,7 +162,7 @@ GIT_EXTERN(int) git_attr_get( ...@@ -162,7 +162,7 @@ GIT_EXTERN(int) git_attr_get(
* Then you could loop through the 3 values to get the settings for * Then you could loop through the 3 values to get the settings for
* the three attributes you asked about. * the three attributes you asked about.
* *
* @param values An array of num_attr entries that will have string * @param values_out An array of num_attr entries that will have string
* pointers written into it for the values of the attributes. * pointers written into it for the values of the attributes.
* You should not modify or free the values that are written * You should not modify or free the values that are written
* into this array (although of course, you should free the * into this array (although of course, you should free the
......
...@@ -183,6 +183,8 @@ typedef enum { ...@@ -183,6 +183,8 @@ typedef enum {
GIT_CHECKOUT_NOTIFY_UPDATED = (1u << 2), GIT_CHECKOUT_NOTIFY_UPDATED = (1u << 2),
GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3), GIT_CHECKOUT_NOTIFY_UNTRACKED = (1u << 3),
GIT_CHECKOUT_NOTIFY_IGNORED = (1u << 4), GIT_CHECKOUT_NOTIFY_IGNORED = (1u << 4),
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu
} git_checkout_notify_t; } git_checkout_notify_t;
/** Checkout notification callback function */ /** Checkout notification callback function */
...@@ -234,6 +236,8 @@ typedef struct git_checkout_opts { ...@@ -234,6 +236,8 @@ typedef struct git_checkout_opts {
git_strarray paths; git_strarray paths;
git_tree *baseline; /** expected content of workdir, defaults to HEAD */ git_tree *baseline; /** expected content of workdir, defaults to HEAD */
const char *target_directory; /** alternative checkout path to workdir */
} git_checkout_opts; } git_checkout_opts;
#define GIT_CHECKOUT_OPTS_VERSION 1 #define GIT_CHECKOUT_OPTS_VERSION 1
......
...@@ -67,6 +67,7 @@ typedef struct git_clone_options { ...@@ -67,6 +67,7 @@ typedef struct git_clone_options {
unsigned int version; unsigned int version;
git_checkout_opts checkout_opts; git_checkout_opts checkout_opts;
git_repository_init_options *init_options;
int bare; int bare;
git_transfer_progress_callback fetch_progress_cb; git_transfer_progress_callback fetch_progress_cb;
void *fetch_progress_payload; void *fetch_progress_payload;
......
...@@ -24,17 +24,24 @@ GIT_BEGIN_DECL ...@@ -24,17 +24,24 @@ GIT_BEGIN_DECL
/** /**
* Lookup a commit object from a repository. * Lookup a commit object from a repository.
* *
* The returned object should be released with `git_commit_free` when no
* longer needed.
*
* @param commit pointer to the looked up commit * @param commit pointer to the looked up commit
* @param repo the repo to use when locating the commit. * @param repo the repo to use when locating the commit.
* @param id identity of the commit to locate. If the object is * @param id identity of the commit to locate. If the object is
* an annotated tag it will be peeled back to the commit. * an annotated tag it will be peeled back to the commit.
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id); GIT_EXTERN(int) git_commit_lookup(
git_commit **commit, git_repository *repo, const git_oid *id);
/** /**
* Lookup a commit object from a repository, * Lookup a commit object from a repository, given a prefix of its
* given a prefix of its identifier (short id). * identifier (short id).
*
* The returned object should be released with `git_commit_free` when no
* longer needed.
* *
* @see git_object_lookup_prefix * @see git_object_lookup_prefix
* *
...@@ -45,7 +52,8 @@ GIT_EXTERN(int) git_commit_lookup(git_commit **commit, git_repository *repo, con ...@@ -45,7 +52,8 @@ GIT_EXTERN(int) git_commit_lookup(git_commit **commit, git_repository *repo, con
* @param len the length of the short identifier * @param len the length of the short identifier
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_commit_lookup_prefix(git_commit **commit, git_repository *repo, const git_oid *id, size_t len); GIT_EXTERN(int) git_commit_lookup_prefix(
git_commit **commit, git_repository *repo, const git_oid *id, size_t len);
/** /**
* Close an open commit * Close an open commit
...@@ -130,6 +138,14 @@ GIT_EXTERN(const git_signature *) git_commit_committer(const git_commit *commit) ...@@ -130,6 +138,14 @@ GIT_EXTERN(const git_signature *) git_commit_committer(const git_commit *commit)
GIT_EXTERN(const git_signature *) git_commit_author(const git_commit *commit); GIT_EXTERN(const git_signature *) git_commit_author(const git_commit *commit);
/** /**
* Get the full raw text of the commit header.
*
* @param commit a previously loaded commit
* @return the header text of the commit
*/
GIT_EXTERN(const char *) git_commit_raw_header(const git_commit *commit);
/**
* Get the tree pointed to by a commit. * Get the tree pointed to by a commit.
* *
* @param tree_out pointer where to store the tree object * @param tree_out pointer where to store the tree object
...@@ -235,7 +251,7 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor( ...@@ -235,7 +251,7 @@ GIT_EXTERN(int) git_commit_nth_gen_ancestor(
* *
* @param parent_count Number of parents for this commit * @param parent_count Number of parents for this commit
* *
* @param parents[] Array of `parent_count` pointers to `git_commit` * @param parents Array of `parent_count` pointers to `git_commit`
* objects that will be used as the parents for this commit. This * objects that will be used as the parents for this commit. This
* array may be NULL if `parent_count` is 0 (root commit). All the * array may be NULL if `parent_count` is 0 (root commit). All the
* given commits must be owned by the `repo`. * given commits must be owned by the `repo`.
......
...@@ -105,7 +105,8 @@ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev); ...@@ -105,7 +105,8 @@ GIT_EXTERN(void) git_libgit2_version(int *major, int *minor, int *rev);
*/ */
typedef enum { typedef enum {
GIT_CAP_THREADS = ( 1 << 0 ), GIT_CAP_THREADS = ( 1 << 0 ),
GIT_CAP_HTTPS = ( 1 << 1 ) GIT_CAP_HTTPS = ( 1 << 1 ),
GIT_CAP_SSH = ( 1 << 2 ),
} git_cap_t; } git_cap_t;
/** /**
......
...@@ -61,6 +61,7 @@ typedef struct { ...@@ -61,6 +61,7 @@ typedef struct {
} git_config_entry; } git_config_entry;
typedef int (*git_config_foreach_cb)(const git_config_entry *, void *); typedef int (*git_config_foreach_cb)(const git_config_entry *, void *);
typedef struct git_config_iterator git_config_iterator;
typedef enum { typedef enum {
GIT_CVAR_FALSE = 0, GIT_CVAR_FALSE = 0,
...@@ -119,7 +120,7 @@ GIT_EXTERN(int) git_config_find_xdg(char *out, size_t length); ...@@ -119,7 +120,7 @@ GIT_EXTERN(int) git_config_find_xdg(char *out, size_t length);
* If /etc/gitconfig doesn't exist, it will look for * If /etc/gitconfig doesn't exist, it will look for
* %PROGRAMFILES%\Git\etc\gitconfig. * %PROGRAMFILES%\Git\etc\gitconfig.
* @param global_config_path Buffer to store the path in * @param out Buffer to store the path in
* @param length size of the buffer in bytes * @param length size of the buffer in bytes
* @return 0 if a system configuration file has been * @return 0 if a system configuration file has been
* found. Its path will be stored in `buffer`. * found. Its path will be stored in `buffer`.
...@@ -327,7 +328,7 @@ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char ...@@ -327,7 +328,7 @@ GIT_EXTERN(int) git_config_get_bool(int *out, const git_config *cfg, const char
GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, const char *name); GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, const char *name);
/** /**
* Get each value of a multivar. * Get each value of a multivar in a foreach callback
* *
* The callback will be called on each variable found * The callback will be called on each variable found
* *
...@@ -335,10 +336,37 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c ...@@ -335,10 +336,37 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c
* @param name the variable's name * @param name the variable's name
* @param regexp regular expression to filter which variables we're * @param regexp regular expression to filter which variables we're
* interested in. Use NULL to indicate all * interested in. Use NULL to indicate all
* @param fn the function to be called on each value of the variable * @param callback the function to be called on each value of the variable
* @param data opaque pointer to pass to the callback * @param payload opaque pointer to pass to the callback
*/
GIT_EXTERN(int) git_config_get_multivar_foreach(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload);
/**
* Get each value of a multivar
*
* @param out pointer to store the iterator
* @param cfg where to look for the variable
* @param name the variable's name
* @param regexp regular expression to filter which variables we're
* interested in. Use NULL to indicate all
*/ */
GIT_EXTERN(int) git_config_get_multivar(const git_config *cfg, const char *name, const char *regexp, git_config_foreach_cb callback, void *payload); GIT_EXTERN(int) git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp);
/**
* Return the current entry and advance the iterator
*
* @param entry pointer to store the entry
* @param iter the iterator
* @return 0 or an error code. GIT_ITEROVER if the iteration has completed
*/
GIT_EXTERN(int) git_config_next(git_config_entry **entry, git_config_iterator *iter);
/**
* Free a config iterator
*
* @param iter the iterator to free
*/
GIT_EXTERN(void) git_config_iterator_free(git_config_iterator *iter);
/** /**
* Set the value of an integer config variable in the config file * Set the value of an integer config variable in the config file
...@@ -425,6 +453,29 @@ GIT_EXTERN(int) git_config_foreach( ...@@ -425,6 +453,29 @@ GIT_EXTERN(int) git_config_foreach(
void *payload); void *payload);
/** /**
* Iterate over all the config variables
*
* Use `git_config_next` to advance the iteration and
* `git_config_iterator_free` when done.
*
* @param out pointer to store the iterator
* @param cfg where to ge the variables from
*/
GIT_EXTERN(int) git_config_iterator_new(git_config_iterator **out, const git_config *cfg);
/**
* Iterate over all the config variables whose name matches a pattern
*
* Use `git_config_next` to advance the iteration and
* `git_config_iterator_free` when done.
*
* @param out pointer to store the iterator
* @param cfg where to ge the variables from
* @param regexp regular expression to match the names
*/
GIT_EXTERN(int) git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp);
/**
* Perform an operation on each config variable matching a regular expression. * Perform an operation on each config variable matching a regular expression.
* *
* This behaviors like `git_config_foreach` with an additional filter of a * This behaviors like `git_config_foreach` with an additional filter of a
...@@ -535,6 +586,25 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value); ...@@ -535,6 +586,25 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value);
GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value); GIT_EXTERN(int) git_config_parse_int64(int64_t *out, const char *value);
/**
* Perform an operation on each config variable in given config backend
* matching a regular expression.
*
* This behaviors like `git_config_foreach_match` except instead of all config
* entries it just enumerates through the given backend entry.
*
* @param backend where to get the variables from
* @param regexp regular expression to match against config names (can be NULL)
* @param callback the function to call on each variable
* @param payload the data to pass to the callback
*/
GIT_EXTERN(int) git_config_backend_foreach_match(
git_config_backend *backend,
const char *regexp,
int (*fn)(const git_config_entry *, void *),
void *data);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#ifndef INCLUDE_git_cred_helpers_h__ #ifndef INCLUDE_git_cred_helpers_h__
#define INCLUDE_git_cred_helpers_h__ #define INCLUDE_git_cred_helpers_h__
#include "git2/transport.h" #include "transport.h"
/** /**
* @file git2/cred_helpers.h * @file git2/cred_helpers.h
......
...@@ -78,7 +78,7 @@ typedef enum { ...@@ -78,7 +78,7 @@ typedef enum {
GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 3), GIT_DIFF_IGNORE_WHITESPACE_CHANGE = (1 << 3),
/** Ignore whitespace at end of line */ /** Ignore whitespace at end of line */
GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 4), GIT_DIFF_IGNORE_WHITESPACE_EOL = (1 << 4),
/** Exclude submodules from the diff completely */ /** Treat all submodules as unmodified */
GIT_DIFF_IGNORE_SUBMODULES = (1 << 5), GIT_DIFF_IGNORE_SUBMODULES = (1 << 5),
/** Use the "patience diff" algorithm (currently unimplemented) */ /** Use the "patience diff" algorithm (currently unimplemented) */
GIT_DIFF_PATIENCE = (1 << 6), GIT_DIFF_PATIENCE = (1 << 6),
...@@ -314,6 +314,8 @@ typedef int (*git_diff_notify_cb)( ...@@ -314,6 +314,8 @@ typedef int (*git_diff_notify_cb)(
* - `notify_cb` is an optional callback function, notifying the consumer of * - `notify_cb` is an optional callback function, notifying the consumer of
* which files are being examined as the diff is generated * which files are being examined as the diff is generated
* - `notify_payload` is the payload data to pass to the `notify_cb` function * - `notify_payload` is the payload data to pass to the `notify_cb` function
* - `ignore_submodules` overrides the submodule ignore setting for all
* submodules in the diff.
*/ */
typedef struct { typedef struct {
unsigned int version; /**< version for the struct */ unsigned int version; /**< version for the struct */
...@@ -326,6 +328,7 @@ typedef struct { ...@@ -326,6 +328,7 @@ typedef struct {
git_off_t max_size; /**< defaults to 512MB */ git_off_t max_size; /**< defaults to 512MB */
git_diff_notify_cb notify_cb; git_diff_notify_cb notify_cb;
void *notify_payload; void *notify_payload;
git_submodule_ignore_t ignore_submodules; /** << submodule ignore rule */
} git_diff_options; } git_diff_options;
#define GIT_DIFF_OPTIONS_VERSION 1 #define GIT_DIFF_OPTIONS_VERSION 1
...@@ -388,7 +391,7 @@ typedef enum { ...@@ -388,7 +391,7 @@ typedef enum {
*/ */
GIT_DIFF_LINE_FILE_HDR = 'F', GIT_DIFF_LINE_FILE_HDR = 'F',
GIT_DIFF_LINE_HUNK_HDR = 'H', GIT_DIFF_LINE_HUNK_HDR = 'H',
GIT_DIFF_LINE_BINARY = 'B' GIT_DIFF_LINE_BINARY = 'B' /**< For "Binary files x and y differ" */
} git_diff_line_t; } git_diff_line_t;
/** /**
...@@ -451,6 +454,9 @@ typedef enum { ...@@ -451,6 +454,9 @@ typedef enum {
GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1 << 13), GIT_DIFF_FIND_DONT_IGNORE_WHITESPACE = (1 << 13),
/** measure similarity only by comparing SHAs (fast and cheap) */ /** measure similarity only by comparing SHAs (fast and cheap) */
GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1 << 14), GIT_DIFF_FIND_EXACT_MATCH_ONLY = (1 << 14),
/** do not break rewrites unless they contribute to a rename */
GIT_DIFF_BREAK_REWRITES_FOR_RENAMES_ONLY = (1 << 15),
} git_diff_find_t; } git_diff_find_t;
/** /**
...@@ -747,7 +753,7 @@ GIT_EXTERN(int) git_diff_print_raw( ...@@ -747,7 +753,7 @@ GIT_EXTERN(int) git_diff_print_raw(
* letters for your own purposes. This function does just that. By the * letters for your own purposes. This function does just that. By the
* way, unmodified will return a space (i.e. ' '). * way, unmodified will return a space (i.e. ' ').
* *
* @param delta_t The git_delta_t value to look up * @param status The git_delta_t value to look up
* @return The single character label for that code * @return The single character label for that code
*/ */
GIT_EXTERN(char) git_diff_status_char(git_delta_t status); GIT_EXTERN(char) git_diff_status_char(git_delta_t status);
...@@ -798,6 +804,14 @@ GIT_EXTERN(size_t) git_diff_num_deltas_of_type( ...@@ -798,6 +804,14 @@ GIT_EXTERN(size_t) git_diff_num_deltas_of_type(
git_delta_t type); git_delta_t type);
/** /**
* Check if deltas are sorted case sensitively or insensitively.
*
* @param diff Diff list to check
* @return 0 if case sensitive, 1 if case is ignored
*/
GIT_EXTERN(int) git_diff_is_sorted_icase(const git_diff_list *diff);
/**
* Return the diff delta and patch for an entry in the diff list. * Return the diff delta and patch for an entry in the diff list.
* *
* The `git_diff_patch` is a newly created object contains the text diffs * The `git_diff_patch` is a newly created object contains the text diffs
...@@ -918,7 +932,7 @@ GIT_EXTERN(int) git_diff_patch_num_lines_in_hunk( ...@@ -918,7 +932,7 @@ GIT_EXTERN(int) git_diff_patch_num_lines_in_hunk(
* @param new_lineno Line number in new file or -1 if line is deleted * @param new_lineno Line number in new file or -1 if line is deleted
* @param patch The patch to look in * @param patch The patch to look in
* @param hunk_idx The index of the hunk * @param hunk_idx The index of the hunk
* @param line_of_index The index of the line in the hunk * @param line_of_hunk The index of the line in the hunk
* @return 0 on success, <0 on failure * @return 0 on success, <0 on failure
*/ */
GIT_EXTERN(int) git_diff_patch_get_line_in_hunk( GIT_EXTERN(int) git_diff_patch_get_line_in_hunk(
...@@ -932,6 +946,28 @@ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk( ...@@ -932,6 +946,28 @@ GIT_EXTERN(int) git_diff_patch_get_line_in_hunk(
size_t line_of_hunk); size_t line_of_hunk);
/** /**
* Look up size of patch diff data in bytes
*
* This returns the raw size of the patch data. This only includes the
* actual data from the lines of the diff, not the file or hunk headers.
*
* If you pass `include_context` as true (non-zero), this will be the size
* of all of the diff output; if you pass it as false (zero), this will
* only include the actual changed lines (as if `context_lines` was 0).
*
* @param patch A git_diff_patch representing changes to one file
* @param include_context Include context lines in size if non-zero
* @param include_hunk_headers Include hunk header lines if non-zero
* @param include_file_headers Include file header lines if non-zero
* @return The number of bytes of data
*/
GIT_EXTERN(size_t) git_diff_patch_size(
git_diff_patch *patch,
int include_context,
int include_hunk_headers,
int include_file_headers);
/**
* Serialize the patch to text via callback. * Serialize the patch to text via callback.
* *
* Returning a non-zero value from the callback will terminate the iteration * Returning a non-zero value from the callback will terminate the iteration
...@@ -983,7 +1019,9 @@ GIT_EXTERN(int) git_diff_patch_to_str( ...@@ -983,7 +1019,9 @@ GIT_EXTERN(int) git_diff_patch_to_str(
* `GIT_DIFF_FORCE_TEXT` of course). * `GIT_DIFF_FORCE_TEXT` of course).
* *
* @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_blob Blob for old side of diff, or NULL for empty blob
* @param old_as_path Treat old blob as if it had this filename; can be NULL
* @param new_blob Blob for new side of diff, or NULL for empty blob * @param new_blob Blob for new side of diff, or NULL for empty blob
* @param new_as_path Treat new blob as if it had this filename; can be NULL
* @param options Options for diff, or NULL for default options * @param options Options for diff, or NULL for default options
* @param file_cb Callback for "file"; made once if there is a diff; can be NULL * @param file_cb Callback for "file"; made once if there is a diff; can be NULL
* @param hunk_cb Callback for each hunk in diff; can be NULL * @param hunk_cb Callback for each hunk in diff; can be NULL
...@@ -993,7 +1031,9 @@ GIT_EXTERN(int) git_diff_patch_to_str( ...@@ -993,7 +1031,9 @@ GIT_EXTERN(int) git_diff_patch_to_str(
*/ */
GIT_EXTERN(int) git_diff_blobs( GIT_EXTERN(int) git_diff_blobs(
const git_blob *old_blob, const git_blob *old_blob,
const char *old_as_path,
const git_blob *new_blob, const git_blob *new_blob,
const char *new_as_path,
const git_diff_options *options, const git_diff_options *options,
git_diff_file_cb file_cb, git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb, git_diff_hunk_cb hunk_cb,
...@@ -1010,14 +1050,18 @@ GIT_EXTERN(int) git_diff_blobs( ...@@ -1010,14 +1050,18 @@ GIT_EXTERN(int) git_diff_blobs(
* *
* @param out The generated patch; NULL on error * @param out The generated patch; NULL on error
* @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_blob Blob for old side of diff, or NULL for empty blob
* @param old_as_path Treat old blob as if it had this filename; can be NULL
* @param new_blob Blob for new side of diff, or NULL for empty blob * @param new_blob Blob for new side of diff, or NULL for empty blob
* @param options Options for diff, or NULL for default options * @param new_as_path Treat new blob as if it had this filename; can be NULL
* @param opts Options for diff, or NULL for default options
* @return 0 on success or error code < 0 * @return 0 on success or error code < 0
*/ */
GIT_EXTERN(int) git_diff_patch_from_blobs( GIT_EXTERN(int) git_diff_patch_from_blobs(
git_diff_patch **out, git_diff_patch **out,
const git_blob *old_blob, const git_blob *old_blob,
const char *old_as_path,
const git_blob *new_blob, const git_blob *new_blob,
const char *new_as_path,
const git_diff_options *opts); const git_diff_options *opts);
/** /**
...@@ -1033,19 +1077,23 @@ GIT_EXTERN(int) git_diff_patch_from_blobs( ...@@ -1033,19 +1077,23 @@ GIT_EXTERN(int) git_diff_patch_from_blobs(
* the reverse, with GIT_DELTA_REMOVED and blob content removed. * the reverse, with GIT_DELTA_REMOVED and blob content removed.
* *
* @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_blob Blob for old side of diff, or NULL for empty blob
* @param old_as_path Treat old blob as if it had this filename; can be NULL
* @param buffer Raw data for new side of diff, or NULL for empty * @param buffer Raw data for new side of diff, or NULL for empty
* @param buffer_len Length of raw data for new side of diff * @param buffer_len Length of raw data for new side of diff
* @param buffer_as_path Treat buffer as if it had this filename; can be NULL
* @param options Options for diff, or NULL for default options * @param options Options for diff, or NULL for default options
* @param file_cb Callback for "file"; made once if there is a diff; can be NULL * @param file_cb Callback for "file"; made once if there is a diff; can be NULL
* @param hunk_cb Callback for each hunk in diff; can be NULL * @param hunk_cb Callback for each hunk in diff; can be NULL
* @param line_cb Callback for each line in diff; can be NULL * @param data_cb Callback for each line in diff; can be NULL
* @param payload Payload passed to each callback function * @param payload Payload passed to each callback function
* @return 0 on success, GIT_EUSER on non-zero callback return, or error code * @return 0 on success, GIT_EUSER on non-zero callback return, or error code
*/ */
GIT_EXTERN(int) git_diff_blob_to_buffer( GIT_EXTERN(int) git_diff_blob_to_buffer(
const git_blob *old_blob, const git_blob *old_blob,
const char *old_as_path,
const char *buffer, const char *buffer,
size_t buffer_len, size_t buffer_len,
const char *buffer_as_path,
const git_diff_options *options, const git_diff_options *options,
git_diff_file_cb file_cb, git_diff_file_cb file_cb,
git_diff_hunk_cb hunk_cb, git_diff_hunk_cb hunk_cb,
...@@ -1062,16 +1110,20 @@ GIT_EXTERN(int) git_diff_blob_to_buffer( ...@@ -1062,16 +1110,20 @@ GIT_EXTERN(int) git_diff_blob_to_buffer(
* *
* @param out The generated patch; NULL on error * @param out The generated patch; NULL on error
* @param old_blob Blob for old side of diff, or NULL for empty blob * @param old_blob Blob for old side of diff, or NULL for empty blob
* @param old_as_path Treat old blob as if it had this filename; can be NULL
* @param buffer Raw data for new side of diff, or NULL for empty * @param buffer Raw data for new side of diff, or NULL for empty
* @param buffer_len Length of raw data for new side of diff * @param buffer_len Length of raw data for new side of diff
* @param options Options for diff, or NULL for default options * @param buffer_as_path Treat buffer as if it had this filename; can be NULL
* @param opts Options for diff, or NULL for default options
* @return 0 on success or error code < 0 * @return 0 on success or error code < 0
*/ */
GIT_EXTERN(int) git_diff_patch_from_blob_and_buffer( GIT_EXTERN(int) git_diff_patch_from_blob_and_buffer(
git_diff_patch **out, git_diff_patch **out,
const git_blob *old_blob, const git_blob *old_blob,
const char *buf, const char *old_as_path,
size_t buflen, const char *buffer,
size_t buffer_len,
const char *buffer_as_path,
const git_diff_options *opts); const git_diff_options *opts);
......
...@@ -32,6 +32,7 @@ typedef enum { ...@@ -32,6 +32,7 @@ typedef enum {
GIT_ENONFASTFORWARD = -11, GIT_ENONFASTFORWARD = -11,
GIT_EINVALIDSPEC = -12, GIT_EINVALIDSPEC = -12,
GIT_EMERGECONFLICT = -13, GIT_EMERGECONFLICT = -13,
GIT_ELOCKED = -14,
GIT_PASSTHROUGH = -30, GIT_PASSTHROUGH = -30,
GIT_ITEROVER = -31, GIT_ITEROVER = -31,
...@@ -100,7 +101,7 @@ GIT_EXTERN(void) giterr_clear(void); ...@@ -100,7 +101,7 @@ GIT_EXTERN(void) giterr_clear(void);
* *
* @param error_class One of the `git_error_t` enum above describing the * @param error_class One of the `git_error_t` enum above describing the
* general subsystem that is responsible for the error. * general subsystem that is responsible for the error.
* @param message The formatted error message to keep * @param string The formatted error message to keep
*/ */
GIT_EXTERN(void) giterr_set_str(int error_class, const char *string); GIT_EXTERN(void) giterr_set_str(int error_class, const char *string);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "indexer.h" #include "indexer.h"
#include "types.h" #include "types.h"
#include "oid.h" #include "oid.h"
#include "strarray.h"
/** /**
* @file git2/index.h * @file git2/index.h
...@@ -125,6 +126,26 @@ typedef enum { ...@@ -125,6 +126,26 @@ typedef enum {
GIT_INDEXCAP_FROM_OWNER = ~0u GIT_INDEXCAP_FROM_OWNER = ~0u
} git_indexcap_t; } git_indexcap_t;
/** Callback for APIs that add/remove/update files matching pathspec */
typedef int (*git_index_matched_path_cb)(
const char *path, const char *matched_pathspec, void *payload);
/** Flags for APIs that add files matching pathspec */
typedef enum {
GIT_INDEX_ADD_DEFAULT = 0,
GIT_INDEX_ADD_FORCE = (1u << 0),
GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH = (1u << 1),
GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2),
} git_index_add_option_t;
/**
* Match any index stage.
*
* Some index APIs take a stage to match; pass this value to match
* any entry matching the path regardless of stage.
*/
#define GIT_INDEX_STAGE_ANY -1
/** @name Index File Functions /** @name Index File Functions
* *
* These functions work on the index file itself. * These functions work on the index file itself.
...@@ -219,6 +240,14 @@ GIT_EXTERN(int) git_index_read(git_index *index); ...@@ -219,6 +240,14 @@ GIT_EXTERN(int) git_index_read(git_index *index);
GIT_EXTERN(int) git_index_write(git_index *index); GIT_EXTERN(int) git_index_write(git_index *index);
/** /**
* Get the full path to the index file on disk.
*
* @param index an existing index object
* @return path to index file or NULL for in-memory index
*/
GIT_EXTERN(const char *) git_index_path(git_index *index);
/**
* Read a tree into the index file with stats * Read a tree into the index file with stats
* *
* The current index contents will be replaced by the specified tree. * The current index contents will be replaced by the specified tree.
...@@ -421,6 +450,108 @@ GIT_EXTERN(int) git_index_add_bypath(git_index *index, const char *path); ...@@ -421,6 +450,108 @@ GIT_EXTERN(int) git_index_add_bypath(git_index *index, const char *path);
GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path); GIT_EXTERN(int) git_index_remove_bypath(git_index *index, const char *path);
/** /**
* Add or update index entries matching files in the working directory.
*
* This method will fail in bare index instances.
*
* The `pathspec` is a list of file names or shell glob patterns that will
* matched against files in the repository's working directory. Each file
* that matches will be added to the index (either updating an existing
* entry or adding a new entry). You can disable glob expansion and force
* exact matching with the `GIT_INDEX_ADD_DISABLE_PATHSPEC_MATCH` flag.
*
* Files that are ignored will be skipped (unlike `git_index_add_bypath`).
* If a file is already tracked in the index, then it *will* be updated
* even if it is ignored. Pass the `GIT_INDEX_ADD_FORCE` flag to
* skip the checking of ignore rules.
*
* To emulate `git add -A` and generate an error if the pathspec contains
* the exact path of an ignored file (when not using FORCE), add the
* `GIT_INDEX_ADD_CHECK_PATHSPEC` flag. This checks that each entry
* in the `pathspec` that is an exact match to a filename on disk is
* either not ignored or already in the index. If this check fails, the
* function will return GIT_EINVALIDSPEC.
*
* To emulate `git add -A` with the "dry-run" option, just use a callback
* function that always returns a positive value. See below for details.
*
* If any files are currently the result of a merge conflict, those files
* will no longer be marked as conflicting. The data about the conflicts
* will be moved to the "resolve undo" (REUC) section.
*
* If you provide a callback function, it will be invoked on each matching
* item in the working directory immediately *before* it is added to /
* updated in the index. Returning zero will add the item to the index,
* greater than zero will skip the item, and less than zero will abort the
* scan and cause GIT_EUSER to be returned.
*
* @param index an existing index object
* @param pathspec array of path patterns
* @param flags combination of git_index_add_option_t flags
* @param callback notification callback for each added/updated path (also
* gets index of matching pathspec entry); can be NULL;
* return 0 to add, >0 to skip, <0 to abort scan.
* @param payload payload passed through to callback function
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_add_all(
git_index *index,
const git_strarray *pathspec,
unsigned int flags,
git_index_matched_path_cb callback,
void *payload);
/**
* Remove all matching index entries.
*
* If you provide a callback function, it will be invoked on each matching
* item in the index immediately *before* it is removed. Return 0 to
* remove the item, > 0 to skip the item, and < 0 to abort the scan.
*
* @param index An existing index object
* @param pathspec array of path patterns
* @param callback notification callback for each removed path (also
* gets index of matching pathspec entry); can be NULL;
* return 0 to add, >0 to skip, <0 to abort scan.
* @param payload payload passed through to callback function
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_remove_all(
git_index *index,
const git_strarray *pathspec,
git_index_matched_path_cb callback,
void *payload);
/**
* Update all index entries to match the working directory
*
* This method will fail in bare index instances.
*
* This scans the existing index entries and synchronizes them with the
* working directory, deleting them if the corresponding working directory
* file no longer exists otherwise updating the information (including
* adding the latest version of file to the ODB if needed).
*
* If you provide a callback function, it will be invoked on each matching
* item in the index immediately *before* it is updated (either refreshed
* or removed depending on working directory state). Return 0 to proceed
* with updating the item, > 0 to skip the item, and < 0 to abort the scan.
*
* @param index An existing index object
* @param pathspec array of path patterns
* @param callback notification callback for each updated path (also
* gets index of matching pathspec entry); can be NULL;
* return 0 to add, >0 to skip, <0 to abort scan.
* @param payload payload passed through to callback function
* @return 0 or an error code
*/
GIT_EXTERN(int) git_index_update_all(
git_index *index,
const git_strarray *pathspec,
git_index_matched_path_cb callback,
void *payload);
/**
* Find the first position of any entries which point to given * Find the first position of any entries which point to given
* path in the Git index. * path in the Git index.
* *
...@@ -531,7 +662,7 @@ GIT_EXTERN(int) git_index_conflict_next( ...@@ -531,7 +662,7 @@ GIT_EXTERN(int) git_index_conflict_next(
/** /**
* Frees a `git_index_conflict_iterator`. * Frees a `git_index_conflict_iterator`.
* *
* @param it pointer to the iterator * @param iterator pointer to the iterator
*/ */
GIT_EXTERN(void) git_index_conflict_iterator_free( GIT_EXTERN(void) git_index_conflict_iterator_free(
git_index_conflict_iterator *iterator); git_index_conflict_iterator *iterator);
......
...@@ -21,7 +21,7 @@ typedef struct git_indexer_stream git_indexer_stream; ...@@ -21,7 +21,7 @@ typedef struct git_indexer_stream git_indexer_stream;
* @param out where to store the indexer instance * @param out where to store the indexer instance
* @param path to the directory where the packfile should be stored * @param path to the directory where the packfile should be stored
* @param progress_cb function to call with progress information * @param progress_cb function to call with progress information
* @param progress_payload payload for the progress callback * @param progress_cb_payload payload for the progress callback
*/ */
GIT_EXTERN(int) git_indexer_stream_new( GIT_EXTERN(int) git_indexer_stream_new(
git_indexer_stream **out, git_indexer_stream **out,
......
...@@ -7,11 +7,11 @@ ...@@ -7,11 +7,11 @@
#ifndef INCLUDE_git_merge_h__ #ifndef INCLUDE_git_merge_h__
#define INCLUDE_git_merge_h__ #define INCLUDE_git_merge_h__
#include "git2/common.h" #include "common.h"
#include "git2/types.h" #include "types.h"
#include "git2/oid.h" #include "oid.h"
#include "git2/checkout.h" #include "checkout.h"
#include "git2/index.h" #include "index.h"
/** /**
* @file git2/merge.h * @file git2/merge.h
...@@ -141,7 +141,7 @@ GIT_EXTERN(int) git_merge_head_from_oid( ...@@ -141,7 +141,7 @@ GIT_EXTERN(int) git_merge_head_from_oid(
/** /**
* Frees a `git_merge_head` * Frees a `git_merge_head`
* *
* @param the merge head to free * @param head merge head to free
*/ */
GIT_EXTERN(void) git_merge_head_free( GIT_EXTERN(void) git_merge_head_free(
git_merge_head *head); git_merge_head *head);
......
...@@ -99,7 +99,7 @@ GIT_EXTERN(int) git_note_read( ...@@ -99,7 +99,7 @@ GIT_EXTERN(int) git_note_read(
/** /**
* Get the note message * Get the note message
* *
* @param note * @param note the note
* @return the note message * @return the note message
*/ */
GIT_EXTERN(const char *) git_note_message(const git_note *note); GIT_EXTERN(const char *) git_note_message(const git_note *note);
...@@ -108,7 +108,7 @@ GIT_EXTERN(const char *) git_note_message(const git_note *note); ...@@ -108,7 +108,7 @@ GIT_EXTERN(const char *) git_note_message(const git_note *note);
/** /**
* Get the note object OID * Get the note object OID
* *
* @param note * @param note the note
* @return the note object OID * @return the note object OID
*/ */
GIT_EXTERN(const git_oid *) git_note_oid(const git_note *note); GIT_EXTERN(const git_oid *) git_note_oid(const git_note *note);
......
...@@ -36,7 +36,7 @@ GIT_BEGIN_DECL ...@@ -36,7 +36,7 @@ GIT_BEGIN_DECL
* @param repo the repository to look up the object * @param repo the repository to look up the object
* @param id the unique identifier for the object * @param id the unique identifier for the object
* @param type the type of the object * @param type the type of the object
* @return a reference to the object * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_object_lookup( GIT_EXTERN(int) git_object_lookup(
git_object **object, git_object **object,
......
...@@ -120,7 +120,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i ...@@ -120,7 +120,7 @@ GIT_EXTERN(int) git_odb_read(git_odb_object **out, git_odb *db, const git_oid *i
* @param db database to search for the object in. * @param db database to search for the object in.
* @param short_id a prefix of the id of the object to read. * @param short_id a prefix of the id of the object to read.
* @param len the length of the prefix * @param len the length of the prefix
* @return * @return
* - 0 if the object was read; * - 0 if the object was read;
* - GIT_ENOTFOUND if the object is not in the database. * - GIT_ENOTFOUND if the object is not in the database.
* - GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix) * - GIT_EAMBIGUOUS if the prefix is ambiguous (several objects match the prefix)
...@@ -219,18 +219,12 @@ GIT_EXTERN(int) git_odb_write(git_oid *out, git_odb *odb, const void *data, size ...@@ -219,18 +219,12 @@ GIT_EXTERN(int) git_odb_write(git_oid *out, git_odb *odb, const void *data, size
* The type and final length of the object must be specified * The type and final length of the object must be specified
* when opening the stream. * when opening the stream.
* *
* The returned stream will be of type `GIT_STREAM_WRONLY` and * The returned stream will be of type `GIT_STREAM_WRONLY`, and it
* will have the following methods: * won't be effective until `git_odb_stream_finalize_write` is called
* * and returns without an error
* - stream->write: write `n` bytes into the stream
* - stream->finalize_write: close the stream and store the object in
* the odb
* - stream->free: free the stream
* *
* The streaming write won't be effective until `stream->finalize_write` * The stream must always be freed when done with `git_odb_stream_free` or
* is called and returns without an error * will leak memory.
*
* The stream must always be free'd or will leak memory.
* *
* @see git_odb_stream * @see git_odb_stream
* *
...@@ -243,6 +237,48 @@ GIT_EXTERN(int) git_odb_write(git_oid *out, git_odb *odb, const void *data, size ...@@ -243,6 +237,48 @@ GIT_EXTERN(int) git_odb_write(git_oid *out, git_odb *odb, const void *data, size
GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, size_t size, git_otype type); GIT_EXTERN(int) git_odb_open_wstream(git_odb_stream **out, git_odb *db, size_t size, git_otype type);
/** /**
* Write to an odb stream
*
* This method will fail if the total number of received bytes exceeds the
* size declared with `git_odb_open_wstream()`
*
* @param stream the stream
* @param buffer the data to write
* @param len the buffer's length
* @return 0 if the write succeeded; error code otherwise
*/
GIT_EXTERN(int) git_odb_stream_write(git_odb_stream *stream, const char *buffer, size_t len);
/**
* Finish writing to an odb stream
*
* The object will take its final name and will be available to the
* odb.
*
* This method will fail if the total number of received bytes
* differs from the size declared with `git_odb_open_wstream()`
*
* @param out pointer to store the resulting object's id
* @param stream the stream
* @return 0 on success; an error code otherwise
*/
GIT_EXTERN(int) git_odb_stream_finalize_write(git_oid *out, git_odb_stream *stream);
/**
* Read from an odb stream
*
* Most backends don't implement streaming reads
*/
GIT_EXTERN(int) git_odb_stream_read(git_odb_stream *stream, char *buffer, size_t len);
/**
* Free an odb stream
*
* @param stream the stream to free
*/
GIT_EXTERN(void) git_odb_stream_free(git_odb_stream *stream);
/**
* Open a stream to read an object from the ODB * Open a stream to read an object from the ODB
* *
* Note that most backends do *not* support streaming reads * Note that most backends do *not* support streaming reads
......
...@@ -7,8 +7,8 @@ ...@@ -7,8 +7,8 @@
#ifndef INCLUDE_git_odb_backend_h__ #ifndef INCLUDE_git_odb_backend_h__
#define INCLUDE_git_odb_backend_h__ #define INCLUDE_git_odb_backend_h__
#include "git2/common.h" #include "common.h"
#include "git2/types.h" #include "types.h"
/** /**
* @file git2/backend.h * @file git2/backend.h
...@@ -65,14 +65,50 @@ typedef enum { ...@@ -65,14 +65,50 @@ typedef enum {
GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY), GIT_STREAM_RW = (GIT_STREAM_RDONLY | GIT_STREAM_WRONLY),
} git_odb_stream_t; } git_odb_stream_t;
/** A stream to read/write from a backend */ /**
* A stream to read/write from a backend.
*
* This represents a stream of data being written to or read from a
* backend. When writing, the frontend functions take care of
* calculating the object's id and all `finalize_write` needs to do is
* store the object with the id it is passed.
*/
struct git_odb_stream { struct git_odb_stream {
git_odb_backend *backend; git_odb_backend *backend;
unsigned int mode; unsigned int mode;
void *hash_ctx;
size_t declared_size;
size_t received_bytes;
/**
* Write at most `len` bytes into `buffer` and advance the stream.
*/
int (*read)(git_odb_stream *stream, char *buffer, size_t len); int (*read)(git_odb_stream *stream, char *buffer, size_t len);
/**
* Write `len` bytes from `buffer` into the stream.
*/
int (*write)(git_odb_stream *stream, const char *buffer, size_t len); int (*write)(git_odb_stream *stream, const char *buffer, size_t len);
int (*finalize_write)(git_oid *oid_p, git_odb_stream *stream);
/**
* Store the contents of the stream as an object with the id
* specified in `oid`.
*
* This method might not be invoked if:
* - an error occurs earlier with the `write` callback,
* - the object referred to by `oid` already exists in any backend, or
* - the final number of received bytes differs from the size declared
* with `git_odb_open_wstream()`
*/
int (*finalize_write)(git_odb_stream *stream, const git_oid *oid);
/**
* Free the stream's memory.
*
* This method might be called without a call to `finalize_write` if
* an error occurs or if the object is already present in the ODB.
*/
void (*free)(git_odb_stream *stream); void (*free)(git_odb_stream *stream);
}; };
......
...@@ -85,7 +85,7 @@ GIT_EXTERN(void) git_oid_fromraw(git_oid *out, const unsigned char *raw); ...@@ -85,7 +85,7 @@ GIT_EXTERN(void) git_oid_fromraw(git_oid *out, const unsigned char *raw);
* needed for an oid encoded in hex (40 bytes). Only the * needed for an oid encoded in hex (40 bytes). Only the
* oid digits are written; a '\\0' terminator must be added * oid digits are written; a '\\0' terminator must be added
* by the caller if it is required. * by the caller if it is required.
* @param oid oid structure to format. * @param id oid structure to format.
*/ */
GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id); GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id);
...@@ -96,7 +96,7 @@ GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id); ...@@ -96,7 +96,7 @@ GIT_EXTERN(void) git_oid_fmt(char *out, const git_oid *id);
* If the number of bytes is > GIT_OID_HEXSZ, extra bytes * If the number of bytes is > GIT_OID_HEXSZ, extra bytes
* will be zeroed; if not, a '\0' terminator is NOT added. * will be zeroed; if not, a '\0' terminator is NOT added.
* @param n number of characters to write into out string * @param n number of characters to write into out string
* @param oid oid structure to format. * @param id oid structure to format.
*/ */
GIT_EXTERN(void) git_oid_nfmt(char *out, size_t n, const git_oid *id); GIT_EXTERN(void) git_oid_nfmt(char *out, size_t n, const git_oid *id);
...@@ -118,7 +118,7 @@ GIT_EXTERN(void) git_oid_pathfmt(char *out, const git_oid *id); ...@@ -118,7 +118,7 @@ GIT_EXTERN(void) git_oid_pathfmt(char *out, const git_oid *id);
/** /**
* Format a git_oid into a newly allocated c-string. * Format a git_oid into a newly allocated c-string.
* *
* @param oid the oid structure to format * @param id the oid structure to format
* @return the c-string; NULL if memory is exhausted. Caller must * @return the c-string; NULL if memory is exhausted. Caller must
* deallocate the string with git__free(). * deallocate the string with git__free().
*/ */
...@@ -188,8 +188,7 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len); ...@@ -188,8 +188,7 @@ GIT_EXTERN(int) git_oid_ncmp(const git_oid *a, const git_oid *b, size_t len);
* *
* @param id oid structure. * @param id oid structure.
* @param str input hex string of an object id. * @param str input hex string of an object id.
* @return GIT_ENOTOID if str is not a valid hex string, * @return 0 in case of a match, -1 otherwise.
* 0 in case of a match, GIT_ERROR otherwise.
*/ */
GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str); GIT_EXTERN(int) git_oid_streq(const git_oid *id, const char *str);
...@@ -241,13 +240,13 @@ GIT_EXTERN(git_oid_shorten *) git_oid_shorten_new(size_t min_length); ...@@ -241,13 +240,13 @@ GIT_EXTERN(git_oid_shorten *) git_oid_shorten_new(size_t min_length);
* or freed. * or freed.
* *
* For performance reasons, there is a hard-limit of how many * For performance reasons, there is a hard-limit of how many
* OIDs can be added to a single set (around ~22000, assuming * OIDs can be added to a single set (around ~32000, assuming
* a mostly randomized distribution), which should be enough * a mostly randomized distribution), which should be enough
* for any kind of program, and keeps the algorithm fast and * for any kind of program, and keeps the algorithm fast and
* memory-efficient. * memory-efficient.
* *
* Attempting to add more than those OIDs will result in a * Attempting to add more than those OIDs will result in a
* GIT_ENOMEM error * GITERR_INVALID error
* *
* @param os a `git_oid_shorten` instance * @param os a `git_oid_shorten` instance
* @param text_id an OID in text form * @param text_id an OID in text form
......
...@@ -112,7 +112,7 @@ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid ...@@ -112,7 +112,7 @@ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid
* @param pb The packbuilder * @param pb The packbuilder
* @param path to the directory where the packfile and index should be stored * @param path to the directory where the packfile and index should be stored
* @param progress_cb function to call with progress information from the indexer (optional) * @param progress_cb function to call with progress information from the indexer (optional)
* @param progress_payload payload for the progress callback (optional) * @param progress_cb_payload payload for the progress callback (optional)
* *
* @return 0 or an error code * @return 0 or an error code
*/ */
...@@ -137,7 +137,7 @@ GIT_EXTERN(int) git_packbuilder_foreach(git_packbuilder *pb, git_packbuilder_for ...@@ -137,7 +137,7 @@ GIT_EXTERN(int) git_packbuilder_foreach(git_packbuilder *pb, git_packbuilder_for
* Get the total number of objects the packbuilder will write out * Get the total number of objects the packbuilder will write out
* *
* @param pb the packbuilder * @param pb the packbuilder
* @return * @return the number of objects in the packfile
*/ */
GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb); GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb);
...@@ -145,7 +145,7 @@ GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb); ...@@ -145,7 +145,7 @@ GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb);
* Get the number of objects the packbuilder has already written out * Get the number of objects the packbuilder has already written out
* *
* @param pb the packbuilder * @param pb the packbuilder
* @return * @return the number of objects which have already been written
*/ */
GIT_EXTERN(uint32_t) git_packbuilder_written(git_packbuilder *pb); GIT_EXTERN(uint32_t) git_packbuilder_written(git_packbuilder *pb);
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_git_pathspec_h__
#define INCLUDE_git_pathspec_h__
#include "common.h"
#include "types.h"
#include "strarray.h"
#include "diff.h"
/**
* Compiled pathspec
*/
typedef struct git_pathspec git_pathspec;
/**
* List of filenames matching a pathspec
*/
typedef struct git_pathspec_match_list git_pathspec_match_list;
/**
* Options controlling how pathspec match should be executed
*
* - GIT_PATHSPEC_IGNORE_CASE forces match to ignore case; otherwise
* match will use native case sensitivity of platform filesystem
* - GIT_PATHSPEC_USE_CASE forces case sensitive match; otherwise
* match will use native case sensitivity of platform filesystem
* - GIT_PATHSPEC_NO_GLOB disables glob patterns and just uses simple
* string comparison for matching
* - GIT_PATHSPEC_NO_MATCH_ERROR means the match functions return error
* code GIT_ENOTFOUND if no matches are found; otherwise no matches is
* still success (return 0) but `git_pathspec_match_list_entrycount`
* will indicate 0 matches.
* - GIT_PATHSPEC_FIND_FAILURES means that the `git_pathspec_match_list`
* should track which patterns matched which files so that at the end of
* the match we can identify patterns that did not match any files.
* - GIT_PATHSPEC_FAILURES_ONLY means that the `git_pathspec_match_list`
* does not need to keep the actual matching filenames. Use this to
* just test if there were any matches at all or in combination with
* GIT_PATHSPEC_FIND_FAILURES to validate a pathspec.
*/
typedef enum {
GIT_PATHSPEC_DEFAULT = 0,
GIT_PATHSPEC_IGNORE_CASE = (1u << 0),
GIT_PATHSPEC_USE_CASE = (1u << 1),
GIT_PATHSPEC_NO_GLOB = (1u << 2),
GIT_PATHSPEC_NO_MATCH_ERROR = (1u << 3),
GIT_PATHSPEC_FIND_FAILURES = (1u << 4),
GIT_PATHSPEC_FAILURES_ONLY = (1u << 5),
} git_pathspec_flag_t;
/**
* Compile a pathspec
*
* @param out Output of the compiled pathspec
* @param pathspec A git_strarray of the paths to match
* @return 0 on success, <0 on failure
*/
GIT_EXTERN(int) git_pathspec_new(
git_pathspec **out, const git_strarray *pathspec);
/**
* Free a pathspec
*
* @param ps The compiled pathspec
*/
GIT_EXTERN(void) git_pathspec_free(git_pathspec *ps);
/**
* Try to match a path against a pathspec
*
* Unlike most of the other pathspec matching functions, this will not
* fall back on the native case-sensitivity for your platform. You must
* explicitly pass flags to control case sensitivity or else this will
* fall back on being case sensitive.
*
* @param ps The compiled pathspec
* @param flags Combination of git_pathspec_flag_t options to control match
* @param path The pathname to attempt to match
* @return 1 is path matches spec, 0 if it does not
*/
GIT_EXTERN(int) git_pathspec_matches_path(
const git_pathspec *ps, uint32_t flags, const char *path);
/**
* Match a pathspec against the working directory of a repository.
*
* This matches the pathspec against the current files in the working
* directory of the repository. It is an error to invoke this on a bare
* repo. This handles git ignores (i.e. ignored files will not be
* considered to match the `pathspec` unless the file is tracked in the
* index).
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param repo The repository in which to match; bare repo is an error
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag was given
*/
GIT_EXTERN(int) git_pathspec_match_workdir(
git_pathspec_match_list **out,
git_repository *repo,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against entries in an index.
*
* This matches the pathspec against the files in the repository index.
*
* NOTE: At the moment, the case sensitivity of this match is controlled
* by the current case-sensitivity of the index object itself and the
* USE_CASE and IGNORE_CASE flags will have no effect. This behavior will
* be corrected in a future release.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param index The index to match against
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_index(
git_pathspec_match_list **out,
git_index *index,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against files in a tree.
*
* This matches the pathspec against the files in the given tree.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param tree The root-level tree to match against
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_tree(
git_pathspec_match_list **out,
git_tree *tree,
uint32_t flags,
git_pathspec *ps);
/**
* Match a pathspec against files in a diff list.
*
* This matches the pathspec against the files in the given diff list.
*
* If `out` is not NULL, this returns a `git_patchspec_match_list`. That
* contains the list of all matched filenames (unless you pass the
* `GIT_PATHSPEC_FAILURES_ONLY` flag) and may also contain the list of
* pathspecs with no match (if you used the `GIT_PATHSPEC_FIND_FAILURES`
* flag). You must call `git_pathspec_match_list_free()` on this object.
*
* @param out Output list of matches; pass NULL to just get return value
* @param diff A generated diff list
* @param flags Combination of git_pathspec_flag_t options to control match
* @param ps Pathspec to be matched
* @return 0 on success, -1 on error, GIT_ENOTFOUND if no matches and
* the GIT_PATHSPEC_NO_MATCH_ERROR flag is used
*/
GIT_EXTERN(int) git_pathspec_match_diff(
git_pathspec_match_list **out,
git_diff_list *diff,
uint32_t flags,
git_pathspec *ps);
/**
* Free memory associates with a git_pathspec_match_list
*
* @param m The git_pathspec_match_list to be freed
*/
GIT_EXTERN(void) git_pathspec_match_list_free(git_pathspec_match_list *m);
/**
* Get the number of items in a match list.
*
* @param m The git_pathspec_match_list object
* @return Number of items in match list
*/
GIT_EXTERN(size_t) git_pathspec_match_list_entrycount(
const git_pathspec_match_list *m);
/**
* Get a matching filename by position.
*
* This routine cannot be used if the match list was generated by
* `git_pathspec_match_diff`. If so, it will always return NULL.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the list
* @return The filename of the match
*/
GIT_EXTERN(const char *) git_pathspec_match_list_entry(
const git_pathspec_match_list *m, size_t pos);
/**
* Get a matching diff delta by position.
*
* This routine can only be used if the match list was generated by
* `git_pathspec_match_diff`. Otherwise it will always return NULL.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the list
* @return The filename of the match
*/
GIT_EXTERN(const git_diff_delta *) git_pathspec_match_list_diff_entry(
const git_pathspec_match_list *m, size_t pos);
/**
* Get the number of pathspec items that did not match.
*
* This will be zero unless you passed GIT_PATHSPEC_FIND_FAILURES when
* generating the git_pathspec_match_list.
*
* @param m The git_pathspec_match_list object
* @return Number of items in original pathspec that had no matches
*/
GIT_EXTERN(size_t) git_pathspec_match_list_failed_entrycount(
const git_pathspec_match_list *m);
/**
* Get an original pathspec string that had no matches.
*
* This will be return NULL for positions out of range.
*
* @param m The git_pathspec_match_list object
* @param pos The index into the failed items
* @return The pathspec pattern that didn't match anything
*/
GIT_EXTERN(const char *) git_pathspec_match_list_failed_entry(
const git_pathspec_match_list *m, size_t pos);
#endif
...@@ -98,7 +98,7 @@ GIT_EXTERN(int) git_push_finish(git_push *push); ...@@ -98,7 +98,7 @@ GIT_EXTERN(int) git_push_finish(git_push *push);
* *
* @param push The push object * @param push The push object
* *
* @return true if equal, false otherwise * @return true if remote side successfully unpacked, false otherwise
*/ */
GIT_EXTERN(int) git_push_unpack_ok(git_push *push); GIT_EXTERN(int) git_push_unpack_ok(git_push *push);
......
...@@ -32,7 +32,7 @@ GIT_BEGIN_DECL ...@@ -32,7 +32,7 @@ GIT_BEGIN_DECL
* @param out pointer to the looked-up reference * @param out pointer to the looked-up reference
* @param repo the repository to look up the reference * @param repo the repository to look up the reference
* @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @param name the long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...)
* @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code. * @return 0 on success, GIT_ENOTFOUND, GIT_EINVALIDSPEC or an error code.
*/ */
GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, const char *name); GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, const char *name);
...@@ -49,7 +49,7 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo, ...@@ -49,7 +49,7 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **out, git_repository *repo,
* @param out Pointer to oid to be filled in * @param out Pointer to oid to be filled in
* @param repo The repository in which to look up the reference * @param repo The repository in which to look up the reference
* @param name The long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...) * @param name The long name for the reference (e.g. HEAD, refs/heads/master, refs/tags/v0.1.0, ...)
* @return 0 on success, ENOTFOUND, EINVALIDSPEC or an error code. * @return 0 on success, GIT_ENOTFOUND, GIT_EINVALIDSPEC or an error code.
*/ */
GIT_EXTERN(int) git_reference_name_to_id( GIT_EXTERN(int) git_reference_name_to_id(
git_oid *out, git_repository *repo, const char *name); git_oid *out, git_repository *repo, const char *name);
...@@ -62,7 +62,7 @@ GIT_EXTERN(int) git_reference_name_to_id( ...@@ -62,7 +62,7 @@ GIT_EXTERN(int) git_reference_name_to_id(
* *
* @param out pointer in which to store the reference * @param out pointer in which to store the reference
* @param repo the repository in which to look * @param repo the repository in which to look
* @param shrothand the short name for the reference * @param shorthand the short name for the reference
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, const char *shorthand); GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, const char *shorthand);
...@@ -94,7 +94,7 @@ GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, co ...@@ -94,7 +94,7 @@ GIT_EXTERN(int) git_reference_dwim(git_reference **out, git_repository *repo, co
* @param name The name of the reference * @param name The name of the reference
* @param target The target of the reference * @param target The target of the reference
* @param force Overwrite existing references * @param force Overwrite existing references
* @return 0 on success, EEXISTS, EINVALIDSPEC or an error code * @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force); GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repository *repo, const char *name, const char *target, int force);
...@@ -126,7 +126,7 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor ...@@ -126,7 +126,7 @@ GIT_EXTERN(int) git_reference_symbolic_create(git_reference **out, git_repositor
* @param name The name of the reference * @param name The name of the reference
* @param id The object id pointed to by the reference. * @param id The object id pointed to by the reference.
* @param force Overwrite existing references * @param force Overwrite existing references
* @return 0 on success, EEXISTS, EINVALIDSPEC or an error code * @return 0 on success, GIT_EEXISTS, GIT_EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force); GIT_EXTERN(int) git_reference_create(git_reference **out, git_repository *repo, const char *name, const git_oid *id, int force);
...@@ -198,7 +198,7 @@ GIT_EXTERN(const char *) git_reference_name(const git_reference *ref); ...@@ -198,7 +198,7 @@ GIT_EXTERN(const char *) git_reference_name(const git_reference *ref);
* If a direct reference is passed as an argument, a copy of that * If a direct reference is passed as an argument, a copy of that
* reference is returned. This copy must be manually freed too. * reference is returned. This copy must be manually freed too.
* *
* @param resolved_ref Pointer to the peeled reference * @param out Pointer to the peeled reference
* @param ref The reference * @param ref The reference
* @return 0 or an error code * @return 0 or an error code
*/ */
...@@ -225,7 +225,7 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref); ...@@ -225,7 +225,7 @@ GIT_EXTERN(git_repository *) git_reference_owner(const git_reference *ref);
* @param out Pointer to the newly created reference * @param out Pointer to the newly created reference
* @param ref The reference * @param ref The reference
* @param target The new target for the reference * @param target The new target for the reference
* @return 0 on success, EINVALIDSPEC or an error code * @return 0 on success, GIT_EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_reference_symbolic_set_target( GIT_EXTERN(int) git_reference_symbolic_set_target(
git_reference **out, git_reference **out,
...@@ -266,9 +266,9 @@ GIT_EXTERN(int) git_reference_set_target( ...@@ -266,9 +266,9 @@ GIT_EXTERN(int) git_reference_set_target(
* the reflog if it exists. * the reflog if it exists.
* *
* @param ref The reference to rename * @param ref The reference to rename
* @param name The new name for the reference * @param new_name The new name for the reference
* @param force Overwrite an existing reference * @param force Overwrite an existing reference
* @return 0 on success, EINVALIDSPEC, EEXISTS or an error code * @return 0 on success, GIT_EINVALIDSPEC, GIT_EEXISTS or an error code
* *
*/ */
GIT_EXTERN(int) git_reference_rename( GIT_EXTERN(int) git_reference_rename(
...@@ -375,7 +375,7 @@ GIT_EXTERN(int) git_reference_iterator_glob_new( ...@@ -375,7 +375,7 @@ GIT_EXTERN(int) git_reference_iterator_glob_new(
* *
* @param out pointer in which to store the reference * @param out pointer in which to store the reference
* @param iter the iterator * @param iter the iterator
* @param 0, GIT_ITEROVER if there are no more; or an error code * @return 0, GIT_ITEROVER if there are no more; or an error code
*/ */
GIT_EXTERN(int) git_reference_next(git_reference **out, git_reference_iterator *iter); GIT_EXTERN(int) git_reference_next(git_reference **out, git_reference_iterator *iter);
...@@ -442,6 +442,15 @@ GIT_EXTERN(int) git_reference_is_branch(git_reference *ref); ...@@ -442,6 +442,15 @@ GIT_EXTERN(int) git_reference_is_branch(git_reference *ref);
*/ */
GIT_EXTERN(int) git_reference_is_remote(git_reference *ref); GIT_EXTERN(int) git_reference_is_remote(git_reference *ref);
/**
* Check if a reference is a tag
*
* @param ref A git reference
*
* @return 1 when the reference lives in the refs/tags
* namespace; 0 otherwise.
*/
GIT_EXTERN(int) git_reference_is_tag(git_reference *ref);
typedef enum { typedef enum {
GIT_REF_FORMAT_NORMAL = 0, GIT_REF_FORMAT_NORMAL = 0,
...@@ -488,7 +497,7 @@ typedef enum { ...@@ -488,7 +497,7 @@ typedef enum {
* @param name Reference name to be checked. * @param name Reference name to be checked.
* @param flags Flags to constrain name validation rules - see the * @param flags Flags to constrain name validation rules - see the
* GIT_REF_FORMAT constants above. * GIT_REF_FORMAT constants above.
* @return 0 on success, GIT_EBUFS if buffer is too small, EINVALIDSPEC * @return 0 on success, GIT_EBUFS if buffer is too small, GIT_EINVALIDSPEC
* or an error code. * or an error code.
*/ */
GIT_EXTERN(int) git_reference_normalize_name( GIT_EXTERN(int) git_reference_normalize_name(
...@@ -506,9 +515,9 @@ GIT_EXTERN(int) git_reference_normalize_name( ...@@ -506,9 +515,9 @@ GIT_EXTERN(int) git_reference_normalize_name(
* If you pass `GIT_OBJ_ANY` as the target type, then the object * If you pass `GIT_OBJ_ANY` as the target type, then the object
* will be peeled until a non-tag object is met. * will be peeled until a non-tag object is met.
* *
* @param peeled Pointer to the peeled git_object * @param out Pointer to the peeled git_object
* @param ref The reference to be processed * @param ref The reference to be processed
* @param target_type The type of the requested object (GIT_OBJ_COMMIT, * @param type The type of the requested object (GIT_OBJ_COMMIT,
* GIT_OBJ_TAG, GIT_OBJ_TREE, GIT_OBJ_BLOB or GIT_OBJ_ANY). * GIT_OBJ_TAG, GIT_OBJ_TREE, GIT_OBJ_BLOB or GIT_OBJ_ANY).
* @return 0 on success, GIT_EAMBIGUOUS, GIT_ENOTFOUND or an error code * @return 0 on success, GIT_EAMBIGUOUS, GIT_ENOTFOUND or an error code
*/ */
......
...@@ -55,7 +55,7 @@ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec); ...@@ -55,7 +55,7 @@ GIT_EXTERN(int) git_refspec_force(const git_refspec *refspec);
/** /**
* Get the refspec's direction. * Get the refspec's direction.
* *
* @param the refspec * @param spec refspec
* @return GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH * @return GIT_DIRECTION_FETCH or GIT_DIRECTION_PUSH
*/ */
GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec); GIT_EXTERN(git_direction) git_refspec_direction(const git_refspec *spec);
......
...@@ -25,13 +25,6 @@ ...@@ -25,13 +25,6 @@
GIT_BEGIN_DECL GIT_BEGIN_DECL
typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload); typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload);
/*
* TODO: This functions still need to be implemented:
* - _listcb/_foreach
* - _add
* - _rename
* - _del (needs support from config)
*/
/** /**
* Add a remote with the default fetch refspec to the repository's configuration. This * Add a remote with the default fetch refspec to the repository's configuration. This
...@@ -96,6 +89,14 @@ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const ch ...@@ -96,6 +89,14 @@ GIT_EXTERN(int) git_remote_load(git_remote **out, git_repository *repo, const ch
GIT_EXTERN(int) git_remote_save(const git_remote *remote); GIT_EXTERN(int) git_remote_save(const git_remote *remote);
/** /**
* Get the remote's repository
*
* @param remote the remote
* @return a pointer to the repository
*/
GIT_EXTERN(git_repository *) git_remote_owner(const git_remote *remote);
/**
* Get the remote's name * Get the remote's name
* *
* @param remote the remote * @param remote the remote
...@@ -247,19 +248,20 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction); ...@@ -247,19 +248,20 @@ GIT_EXTERN(int) git_remote_connect(git_remote *remote, git_direction direction);
GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload); GIT_EXTERN(int) git_remote_ls(git_remote *remote, git_headlist_cb list_cb, void *payload);
/** /**
* Download the packfile * Download and index the packfile
*
* Connect to the remote if it hasn't been done yet, negotiate with
* the remote git which objects are missing, download and index the
* packfile.
* *
* Negotiate what objects should be downloaded and download the * The .idx file will be created and both it and the packfile with be
* packfile with those objects. The packfile is downloaded with a * renamed to their final name.
* temporary filename, as it's final name is not known yet. If there
* was no packfile needed (all the objects were available locally),
* filename will be NULL and the function will return success.
* *
* @param remote the remote to download from * @param remote the remote to download from
* @param progress_cb function to call with progress information. Be aware that * @param progress_cb function to call with progress information. Be aware that
* this is called inline with network and indexing operations, so performance * this is called inline with network and indexing operations, so performance
* may be affected. * may be affected.
* @param progress_payload payload for the progress callback * @param payload payload for the progress callback
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_remote_download( GIT_EXTERN(int) git_remote_download(
...@@ -320,7 +322,7 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote); ...@@ -320,7 +322,7 @@ GIT_EXTERN(int) git_remote_update_tips(git_remote *remote);
* Return whether a string is a valid remote URL * Return whether a string is a valid remote URL
* *
* @param url the url to check * @param url the url to check
* @param 1 if the url is valid, 0 otherwise * @return 1 if the url is valid, 0 otherwise
*/ */
GIT_EXTERN(int) git_remote_valid_url(const char *url); GIT_EXTERN(int) git_remote_valid_url(const char *url);
......
...@@ -94,10 +94,14 @@ GIT_EXTERN(int) git_repository_discover( ...@@ -94,10 +94,14 @@ GIT_EXTERN(int) git_repository_discover(
* changes from the `stat` system call). (E.g. Searching in a user's home * changes from the `stat` system call). (E.g. Searching in a user's home
* directory "/home/user/source/" will not return "/.git/" as the found * directory "/home/user/source/" will not return "/.git/" as the found
* repo if "/" is a different filesystem than "/home".) * repo if "/" is a different filesystem than "/home".)
* * GIT_REPOSITORY_OPEN_BARE - Open repository as a bare repo regardless
* of core.bare config, and defer loading config file for faster setup.
* Unlike `git_repository_open_bare`, this can follow gitlinks.
*/ */
typedef enum { typedef enum {
GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0), GIT_REPOSITORY_OPEN_NO_SEARCH = (1 << 0),
GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1), GIT_REPOSITORY_OPEN_CROSS_FS = (1 << 1),
GIT_REPOSITORY_OPEN_BARE = (1 << 2),
} git_repository_open_flag_t; } git_repository_open_flag_t;
/** /**
...@@ -178,7 +182,7 @@ GIT_EXTERN(int) git_repository_init( ...@@ -178,7 +182,7 @@ GIT_EXTERN(int) git_repository_init(
* when initializing a new repo. Details of individual values are: * when initializing a new repo. Details of individual values are:
* *
* * BARE - Create a bare repository with no working directory. * * BARE - Create a bare repository with no working directory.
* * NO_REINIT - Return an EEXISTS error if the repo_path appears to * * NO_REINIT - Return an GIT_EEXISTS error if the repo_path appears to
* already be an git repository. * already be an git repository.
* * NO_DOTGIT_DIR - Normally a "/.git/" will be appended to the repo * * NO_DOTGIT_DIR - Normally a "/.git/" will be appended to the repo
* path for non-bare repos (if it is not already there), but * path for non-bare repos (if it is not already there), but
...@@ -471,7 +475,7 @@ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo); ...@@ -471,7 +475,7 @@ GIT_EXTERN(int) git_repository_index(git_index **out, git_repository *repo);
* @param out Buffer to write data into or NULL to just read required size * @param out Buffer to write data into or NULL to just read required size
* @param len Length of `out` buffer in bytes * @param len Length of `out` buffer in bytes
* @param repo Repository to read prepared message from * @param repo Repository to read prepared message from
* @return GIT_ENOUTFOUND if no message exists, other value < 0 for other * @return GIT_ENOTFOUND if no message exists, other value < 0 for other
* errors, or total bytes in message (may be > `len`) on success * errors, or total bytes in message (may be > `len`) on success
*/ */
GIT_EXTERN(int) git_repository_message(char *out, size_t len, git_repository *repo); GIT_EXTERN(int) git_repository_message(char *out, size_t len, git_repository *repo);
...@@ -519,7 +523,7 @@ typedef int (*git_repository_mergehead_foreach_cb)(const git_oid *oid, ...@@ -519,7 +523,7 @@ typedef int (*git_repository_mergehead_foreach_cb)(const git_oid *oid,
* *
* @param repo A repository object * @param repo A repository object
* @param callback Callback function * @param callback Callback function
* @param apyload Pointer to callback data (optional) * @param payload Pointer to callback data (optional)
* @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error * @return 0 on success, GIT_ENOTFOUND, GIT_EUSER or error
*/ */
GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo, GIT_EXTERN(int) git_repository_mergehead_foreach(git_repository *repo,
...@@ -601,7 +605,7 @@ GIT_EXTERN(int) git_repository_set_head_detached( ...@@ -601,7 +605,7 @@ GIT_EXTERN(int) git_repository_set_head_detached(
* If the HEAD is already detached and points to a Tag, the HEAD is * If the HEAD is already detached and points to a Tag, the HEAD is
* updated into making it point to the peeled Commit, and 0 is returned. * updated into making it point to the peeled Commit, and 0 is returned.
* *
* If the HEAD is already detached and points to a non commitish, the HEAD is * If the HEAD is already detached and points to a non commitish, the HEAD is
* unaltered, and -1 is returned. * unaltered, and -1 is returned.
* *
* Otherwise, the HEAD will be detached and point to the peeled Commit. * Otherwise, the HEAD will be detached and point to the peeled Commit.
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include "common.h" #include "common.h"
#include "types.h" #include "types.h"
/** /**
* @file git2/revparse.h * @file git2/revparse.h
* @brief Git revision parsing routines * @brief Git revision parsing routines
...@@ -21,27 +20,37 @@ ...@@ -21,27 +20,37 @@
GIT_BEGIN_DECL GIT_BEGIN_DECL
/** /**
* Find a single object, as specified by a revision string. See `man gitrevisions`, * Find a single object, as specified by a revision string.
* or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for *
* See `man gitrevisions`, or
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for
* information on the syntax accepted. * information on the syntax accepted.
* *
* The returned object should be released with `git_object_free` when no
* longer needed.
*
* @param out pointer to output object * @param out pointer to output object
* @param repo the repository to search in * @param repo the repository to search in
* @param spec the textual specification for an object * @param spec the textual specification for an object
* @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code * @return 0 on success, GIT_ENOTFOUND, GIT_EAMBIGUOUS, GIT_EINVALIDSPEC or an error code
*/ */
GIT_EXTERN(int) git_revparse_single(git_object **out, git_repository *repo, const char *spec); GIT_EXTERN(int) git_revparse_single(
git_object **out, git_repository *repo, const char *spec);
/** /**
* Find a single object, as specified by a revision string. * Find a single object and intermediate reference by a revision string.
* See `man gitrevisions`, *
* or http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for * See `man gitrevisions`, or
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for
* information on the syntax accepted. * information on the syntax accepted.
* *
* In some cases (`@{<-n>}` or `<branchname>@{upstream}`), the expression may * In some cases (`@{<-n>}` or `<branchname>@{upstream}`), the expression may
* point to an intermediate reference. When such expressions are being passed * point to an intermediate reference. When such expressions are being passed
* in, `reference_out` will be valued as well. * in, `reference_out` will be valued as well.
* *
* The returned object should be released with `git_object_free` and the
* returned reference with `git_reference_free` when no longer needed.
*
* @param object_out pointer to output object * @param object_out pointer to output object
* @param reference_out pointer to output reference or NULL * @param reference_out pointer to output reference or NULL
* @param repo the repository to search in * @param repo the repository to search in
...@@ -76,25 +85,27 @@ typedef struct { ...@@ -76,25 +85,27 @@ typedef struct {
git_object *from; git_object *from;
/** The right element of the revspec; must be freed by the user */ /** The right element of the revspec; must be freed by the user */
git_object *to; git_object *to;
/** The intent of the revspec */ /** The intent of the revspec (i.e. `git_revparse_mode_t` flags) */
unsigned int flags; unsigned int flags;
} git_revspec; } git_revspec;
/** /**
* Parse a revision string for `from`, `to`, and intent. See `man gitrevisions` or * Parse a revision string for `from`, `to`, and intent.
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for information *
* on the syntax accepted. * See `man gitrevisions` or
* http://git-scm.com/docs/git-rev-parse.html#_specifying_revisions for
* information on the syntax accepted.
* *
* @param revspec Pointer to an user-allocated git_revspec struct where the result * @param revspec Pointer to an user-allocated git_revspec struct where
* of the rev-parse will be stored * the result of the rev-parse will be stored
* @param repo the repository to search in * @param repo the repository to search in
* @param spec the rev-parse spec to parse * @param spec the rev-parse spec to parse
* @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code * @return 0 on success, GIT_INVALIDSPEC, GIT_ENOTFOUND, GIT_EAMBIGUOUS or an error code
*/ */
GIT_EXTERN(int) git_revparse( GIT_EXTERN(int) git_revparse(
git_revspec *revspec, git_revspec *revspec,
git_repository *repo, git_repository *repo,
const char *spec); const char *spec);
/** @} */ /** @} */
......
...@@ -232,6 +232,14 @@ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode); ...@@ -232,6 +232,14 @@ GIT_EXTERN(void) git_revwalk_sorting(git_revwalk *walk, unsigned int sort_mode);
GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range); GIT_EXTERN(int) git_revwalk_push_range(git_revwalk *walk, const char *range);
/** /**
* Simplify the history by first-parent
*
* No parents other than the first for each commit will be enqueued.
*/
GIT_EXTERN(void) git_revwalk_simplify_first_parent(git_revwalk *walk);
/**
* Free a revision walker previously allocated. * Free a revision walker previously allocated.
* *
* @param walk traversal handle to close. If NULL nothing occurs. * @param walk traversal handle to close. If NULL nothing occurs.
......
...@@ -48,6 +48,19 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c ...@@ -48,6 +48,19 @@ GIT_EXTERN(int) git_signature_new(git_signature **out, const char *name, const c
*/ */
GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email); GIT_EXTERN(int) git_signature_now(git_signature **out, const char *name, const char *email);
/**
* Create a new action signature with default user and now timestamp.
*
* This looks up the user.name and user.email from the configuration and
* uses the current time as the timestamp, and creates a new signature
* based on that information. It will return GIT_ENOTFOUND if either the
* user.name or user.email are not set.
*
* @param out new signature
* @param repo repository pointer
* @return 0 on success, GIT_ENOTFOUND if config is missing, or error code
*/
GIT_EXTERN(int) git_signature_default(git_signature **out, git_repository *repo);
/** /**
* Create a copy of an existing signature. All internal strings are also * Create a copy of an existing signature. All internal strings are also
......
...@@ -57,7 +57,7 @@ typedef enum { ...@@ -57,7 +57,7 @@ typedef enum {
GIT_EXTERN(int) git_stash_save( GIT_EXTERN(int) git_stash_save(
git_oid *out, git_oid *out,
git_repository *repo, git_repository *repo,
git_signature *stasher, const git_signature *stasher,
const char *message, const char *message,
unsigned int flags); unsigned int flags);
...@@ -89,7 +89,7 @@ typedef int (*git_stash_cb)( ...@@ -89,7 +89,7 @@ typedef int (*git_stash_cb)(
* *
* @param repo Repository where to find the stash. * @param repo Repository where to find the stash.
* *
* @param callabck Callback to invoke per found stashed state. The most recent * @param callback Callback to invoke per found stashed state. The most recent
* stash state will be enumerated first. * stash state will be enumerated first.
* *
* @param payload Extra parameter to callback function. * @param payload Extra parameter to callback function.
......
...@@ -14,51 +14,18 @@ ...@@ -14,51 +14,18 @@
/** /**
* @file git2/submodule.h * @file git2/submodule.h
* @brief Git submodule management utilities * @brief Git submodule management utilities
* @defgroup git_submodule Git submodule management routines
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Opaque structure representing a submodule.
* *
* Submodule support in libgit2 builds a list of known submodules and keeps * Submodule support in libgit2 builds a list of known submodules and keeps
* it in the repository. The list is built from the .gitmodules file, the * it in the repository. The list is built from the .gitmodules file, the
* .git/config file, the index, and the HEAD tree. Items in the working * .git/config file, the index, and the HEAD tree. Items in the working
* directory that look like submodules (i.e. a git repo) but are not * directory that look like submodules (i.e. a git repo) but are not
* mentioned in those places won't be tracked. * mentioned in those places won't be tracked.
*/
typedef struct git_submodule git_submodule;
/**
* Values that could be specified for the update rule of a submodule.
* *
* Use the DEFAULT value if you have altered the update value via * @defgroup git_submodule Git submodule management routines
* `git_submodule_set_update()` and wish to reset to the original default. * @ingroup Git
*/ * @{
typedef enum {
GIT_SUBMODULE_UPDATE_DEFAULT = -1,
GIT_SUBMODULE_UPDATE_CHECKOUT = 0,
GIT_SUBMODULE_UPDATE_REBASE = 1,
GIT_SUBMODULE_UPDATE_MERGE = 2,
GIT_SUBMODULE_UPDATE_NONE = 3
} git_submodule_update_t;
/**
* Values that could be specified for how closely to examine the
* working directory when getting submodule status.
*
* Use the DEFUALT value if you have altered the ignore value via
* `git_submodule_set_ignore()` and wish to reset to the original value.
*/ */
typedef enum { GIT_BEGIN_DECL
GIT_SUBMODULE_IGNORE_DEFAULT = -1, /* reset to default */
GIT_SUBMODULE_IGNORE_NONE = 0, /* any change or untracked == dirty */
GIT_SUBMODULE_IGNORE_UNTRACKED = 1, /* dirty if tracked files change */
GIT_SUBMODULE_IGNORE_DIRTY = 2, /* only dirty if HEAD moved */
GIT_SUBMODULE_IGNORE_ALL = 3 /* never dirty */
} git_submodule_ignore_t;
/** /**
* Return codes for submodule status. * Return codes for submodule status.
...@@ -119,19 +86,9 @@ typedef enum { ...@@ -119,19 +86,9 @@ typedef enum {
GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13), GIT_SUBMODULE_STATUS_WD_UNTRACKED = (1u << 13),
} git_submodule_status_t; } git_submodule_status_t;
#define GIT_SUBMODULE_STATUS__IN_FLAGS \ #define GIT_SUBMODULE_STATUS__IN_FLAGS 0x000Fu
(GIT_SUBMODULE_STATUS_IN_HEAD | \ #define GIT_SUBMODULE_STATUS__INDEX_FLAGS 0x0070u
GIT_SUBMODULE_STATUS_IN_INDEX | \ #define GIT_SUBMODULE_STATUS__WD_FLAGS 0x3F80u
GIT_SUBMODULE_STATUS_IN_CONFIG | \
GIT_SUBMODULE_STATUS_IN_WD)
#define GIT_SUBMODULE_STATUS__INDEX_FLAGS \
(GIT_SUBMODULE_STATUS_INDEX_ADDED | \
GIT_SUBMODULE_STATUS_INDEX_DELETED | \
GIT_SUBMODULE_STATUS_INDEX_MODIFIED)
#define GIT_SUBMODULE_STATUS__WD_FLAGS \
~(GIT_SUBMODULE_STATUS__IN_FLAGS | GIT_SUBMODULE_STATUS__INDEX_FLAGS)
#define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \ #define GIT_SUBMODULE_STATUS_IS_UNMODIFIED(S) \
(((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0) (((S) & ~GIT_SUBMODULE_STATUS__IN_FLAGS) == 0)
...@@ -359,9 +316,10 @@ GIT_EXTERN(const git_oid *) git_submodule_head_id(git_submodule *submodule); ...@@ -359,9 +316,10 @@ GIT_EXTERN(const git_oid *) git_submodule_head_id(git_submodule *submodule);
GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule); GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule);
/** /**
* Get the ignore rule for the submodule. * Get the ignore rule that will be used for the submodule.
* *
* There are four ignore values: * These values control the behavior of `git_submodule_status()` for this
* submodule. There are four ignore values:
* *
* - **GIT_SUBMODULE_IGNORE_NONE** will consider any change to the contents * - **GIT_SUBMODULE_IGNORE_NONE** will consider any change to the contents
* of the submodule from a clean checkout to be dirty, including the * of the submodule from a clean checkout to be dirty, including the
...@@ -375,6 +333,13 @@ GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule); ...@@ -375,6 +333,13 @@ GIT_EXTERN(const git_oid *) git_submodule_wd_id(git_submodule *submodule);
* - **GIT_SUBMODULE_IGNORE_ALL** means not to open the submodule repo. * - **GIT_SUBMODULE_IGNORE_ALL** means not to open the submodule repo.
* The working directory will be consider clean so long as there is a * The working directory will be consider clean so long as there is a
* checked out version present. * checked out version present.
*
* plus the special **GIT_SUBMODULE_IGNORE_RESET** which can be used with
* `git_submodule_set_ignore()` to revert to the on-disk setting.
*
* @param submodule The submodule to check
* @return The current git_submodule_ignore_t valyue what will be used for
* this submodule.
*/ */
GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore( GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore(
git_submodule *submodule); git_submodule *submodule);
...@@ -382,15 +347,17 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore( ...@@ -382,15 +347,17 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_ignore(
/** /**
* Set the ignore rule for the submodule. * Set the ignore rule for the submodule.
* *
* This sets the ignore rule in memory for the submodule. This will be used * This sets the in-memory ignore rule for the submodule which will
* for any following actions (such as `git_submodule_status()`) while the * control the behavior of `git_submodule_status()`.
* submodule is in memory. You should call `git_submodule_save()` if you
* want to persist the new ignore role.
* *
* Calling this again with GIT_SUBMODULE_IGNORE_DEFAULT or calling * To make changes persistent, call `git_submodule_save()` to write the
* `git_submodule_reload()` will revert the rule to the value that was in the * value to disk (in the ".gitmodules" and ".git/config" files).
* original config.
* *
* Call with `GIT_SUBMODULE_IGNORE_RESET` or call `git_submodule_reload()`
* to revert the in-memory rule to the value that is on disk.
*
* @param submodule The submodule to update
* @param ignore The new value for the ignore rule
* @return old value for ignore * @return old value for ignore
*/ */
GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore( GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore(
...@@ -398,7 +365,16 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore( ...@@ -398,7 +365,16 @@ GIT_EXTERN(git_submodule_ignore_t) git_submodule_set_ignore(
git_submodule_ignore_t ignore); git_submodule_ignore_t ignore);
/** /**
* Get the update rule for the submodule. * Get the update rule that will be used for the submodule.
*
* This value controls the behavior of the `git submodule update` command.
* There are four useful values documented with `git_submodule_update_t`
* plus the `GIT_SUBMODULE_UPDATE_RESET` which can be used to revert to
* the on-disk setting.
*
* @param submodule The submodule to check
* @return The current git_submodule_update_t value that will be used
* for this submodule.
*/ */
GIT_EXTERN(git_submodule_update_t) git_submodule_update( GIT_EXTERN(git_submodule_update_t) git_submodule_update(
git_submodule *submodule); git_submodule *submodule);
...@@ -406,13 +382,17 @@ GIT_EXTERN(git_submodule_update_t) git_submodule_update( ...@@ -406,13 +382,17 @@ GIT_EXTERN(git_submodule_update_t) git_submodule_update(
/** /**
* Set the update rule for the submodule. * Set the update rule for the submodule.
* *
* This sets the update rule in memory for the submodule. You should call * The initial value comes from the ".git/config" setting of
* `git_submodule_save()` if you want to persist the new update rule. * `submodule.$name.update` for this submodule (which is initialized from
* the ".gitmodules" file). Using this function sets the update rule in
* memory for the submodule. Call `git_submodule_save()` to write out the
* new update rule.
* *
* Calling this again with GIT_SUBMODULE_UPDATE_DEFAULT or calling * Calling this again with GIT_SUBMODULE_UPDATE_RESET or calling
* `git_submodule_reload()` will revert the rule to the value that was in the * `git_submodule_reload()` will revert the rule to the on disk value.
* original config.
* *
* @param submodule The submodule to update
* @param update The new value to use
* @return old value for update * @return old value for update
*/ */
GIT_EXTERN(git_submodule_update_t) git_submodule_set_update( GIT_EXTERN(git_submodule_update_t) git_submodule_set_update(
...@@ -481,7 +461,7 @@ GIT_EXTERN(int) git_submodule_sync(git_submodule *submodule); ...@@ -481,7 +461,7 @@ GIT_EXTERN(int) git_submodule_sync(git_submodule *submodule);
* function will return distinct `git_repository` objects. This will only * function will return distinct `git_repository` objects. This will only
* work if the submodule is checked out into the working directory. * work if the submodule is checked out into the working directory.
* *
* @param subrepo Pointer to the submodule repo which was opened * @param repo Pointer to the submodule repo which was opened
* @param submodule Submodule to be opened * @param submodule Submodule to be opened
* @return 0 on success, <0 if submodule repo could not be opened. * @return 0 on success, <0 if submodule repo could not be opened.
*/ */
...@@ -531,7 +511,7 @@ GIT_EXTERN(int) git_submodule_status( ...@@ -531,7 +511,7 @@ GIT_EXTERN(int) git_submodule_status(
* This can be useful if you want to know if the submodule is present in the * This can be useful if you want to know if the submodule is present in the
* working directory at this point in time, etc. * working directory at this point in time, etc.
* *
* @param status Combination of first four `GIT_SUBMODULE_STATUS` flags * @param location_status Combination of first four `GIT_SUBMODULE_STATUS` flags
* @param submodule Submodule for which to get status * @param submodule Submodule for which to get status
* @return 0 on success, <0 on error * @return 0 on success, <0 on error
*/ */
......
...@@ -21,6 +21,33 @@ ...@@ -21,6 +21,33 @@
GIT_BEGIN_DECL GIT_BEGIN_DECL
/** /**
* Every iterator must have this struct as its first element, so the
* API can talk to it. You'd define your iterator as
*
* struct my_iterator {
* git_config_iterator parent;
* ...
* }
*
* and assign `iter->parent.backend` to your `git_config_backend`.
*/
struct git_config_iterator {
git_config_backend *backend;
unsigned int flags;
/**
* Return the current entry and advance the iterator. The
* memory belongs to the library.
*/
int (*next)(git_config_entry **entry, git_config_iterator *iter);
/**
* Free the iterator
*/
void (*free)(git_config_iterator *iter);
};
/**
* Generic backend that implements the interface to * Generic backend that implements the interface to
* access a configuration file * access a configuration file
*/ */
...@@ -31,11 +58,10 @@ struct git_config_backend { ...@@ -31,11 +58,10 @@ struct git_config_backend {
/* Open means open the file/database and parse if necessary */ /* Open means open the file/database and parse if necessary */
int (*open)(struct git_config_backend *, git_config_level_t level); int (*open)(struct git_config_backend *, git_config_level_t level);
int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry); int (*get)(const struct git_config_backend *, const char *key, const git_config_entry **entry);
int (*get_multivar)(struct git_config_backend *, const char *key, const char *regexp, git_config_foreach_cb callback, void *payload);
int (*set)(struct git_config_backend *, const char *key, const char *value); int (*set)(struct git_config_backend *, const char *key, const char *value);
int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value); int (*set_multivar)(git_config_backend *cfg, const char *name, const char *regexp, const char *value);
int (*del)(struct git_config_backend *, const char *key); int (*del)(struct git_config_backend *, const char *key);
int (*foreach)(struct git_config_backend *, const char *, git_config_foreach_cb callback, void *payload); int (*iterator)(git_config_iterator **, struct git_config_backend *);
int (*refresh)(struct git_config_backend *); int (*refresh)(struct git_config_backend *);
void (*free)(struct git_config_backend *); void (*free)(struct git_config_backend *);
}; };
......
...@@ -72,7 +72,6 @@ GIT_EXTERN(int) git_index_name_add(git_index *index, ...@@ -72,7 +72,6 @@ GIT_EXTERN(int) git_index_name_add(git_index *index,
* Remove all filename conflict entries. * Remove all filename conflict entries.
* *
* @param index an existing index object * @param index an existing index object
* @return 0 or an error code
*/ */
GIT_EXTERN(void) git_index_name_clear(git_index *index); GIT_EXTERN(void) git_index_name_clear(git_index *index);
...@@ -168,7 +167,6 @@ GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n); ...@@ -168,7 +167,6 @@ GIT_EXTERN(int) git_index_reuc_remove(git_index *index, size_t n);
* Remove all resolve undo entries from the index * Remove all resolve undo entries from the index
* *
* @param index an existing index object * @param index an existing index object
* @return 0 or an error code
*/ */
GIT_EXTERN(void) git_index_reuc_clear(git_index *index); GIT_EXTERN(void) git_index_reuc_clear(git_index *index);
......
...@@ -48,12 +48,12 @@ struct git_odb_backend { ...@@ -48,12 +48,12 @@ struct git_odb_backend {
int (* read_header)( int (* read_header)(
size_t *, git_otype *, git_odb_backend *, const git_oid *); size_t *, git_otype *, git_odb_backend *, const git_oid *);
/* The writer may assume that the object /**
* has already been hashed and is passed * Write an object into the backend. The id of the object has
* in the first parameter. * already been calculated and is passed in.
*/ */
int (* write)( int (* write)(
git_oid *, git_odb_backend *, const void *, size_t, git_otype); git_odb_backend *, const git_oid *, const void *, size_t, git_otype);
int (* writestream)( int (* writestream)(
git_odb_stream **, git_odb_backend *, size_t, git_otype); git_odb_stream **, git_odb_backend *, size_t, git_otype);
...@@ -64,6 +64,16 @@ struct git_odb_backend { ...@@ -64,6 +64,16 @@ struct git_odb_backend {
int (* exists)( int (* exists)(
git_odb_backend *, const git_oid *); git_odb_backend *, const git_oid *);
/**
* If the backend implements a refreshing mechanism, it should be exposed
* through this endpoint. Each call to `git_odb_refresh()` will invoke it.
*
* However, the backend implementation should try to stay up-to-date as much
* as possible by itself as libgit2 will not automatically invoke
* `git_odb_refresh()`. For instance, a potential strategy for the backend
* implementation to achieve this could be to internally invoke this
* endpoint on failed lookups (ie. `exists()`, `read()`, `read_header()`).
*/
int (* refresh)(git_odb_backend *); int (* refresh)(git_odb_backend *);
int (* foreach)( int (* foreach)(
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* *
* @param name the reference name * @param name the reference name
* @param oid the object id for a direct reference * @param oid the object id for a direct reference
* @param symbolic the target for a symbolic reference * @param peel the first non-tag object's OID, or NULL
* @return the created git_reference or NULL on error * @return the created git_reference or NULL on error
*/ */
GIT_EXTERN(git_reference *) git_reference__alloc( GIT_EXTERN(git_reference *) git_reference__alloc(
...@@ -28,7 +28,7 @@ GIT_EXTERN(git_reference *) git_reference__alloc( ...@@ -28,7 +28,7 @@ GIT_EXTERN(git_reference *) git_reference__alloc(
* Create a new symbolic reference. * Create a new symbolic reference.
* *
* @param name the reference name * @param name the reference name
* @param symbolic the target for a symbolic reference * @param target the target for a symbolic reference
* @return the created git_reference or NULL on error * @return the created git_reference or NULL on error
*/ */
GIT_EXTERN(git_reference *) git_reference__alloc_symbolic( GIT_EXTERN(git_reference *) git_reference__alloc_symbolic(
......
...@@ -36,14 +36,15 @@ typedef enum { ...@@ -36,14 +36,15 @@ typedef enum {
} git_credtype_t; } git_credtype_t;
/* The base structure for all credential types */ /* The base structure for all credential types */
typedef struct git_cred { typedef struct git_cred git_cred;
struct git_cred {
git_credtype_t credtype; git_credtype_t credtype;
void (*free)( void (*free)(git_cred *cred);
struct git_cred *cred); };
} git_cred;
/* A plaintext username and password */ /* A plaintext username and password */
typedef struct git_cred_userpass_plaintext { typedef struct {
git_cred parent; git_cred parent;
char *username; char *username;
char *password; char *password;
...@@ -51,10 +52,14 @@ typedef struct git_cred_userpass_plaintext { ...@@ -51,10 +52,14 @@ typedef struct git_cred_userpass_plaintext {
#ifdef GIT_SSH #ifdef GIT_SSH
typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback)); typedef LIBSSH2_USERAUTH_PUBLICKEY_SIGN_FUNC((*git_cred_sign_callback));
#else
typedef int (*git_cred_sign_callback)(void *, ...);
#endif
/* A ssh key file and passphrase */ /* A ssh key file and passphrase */
typedef struct git_cred_ssh_keyfile_passphrase { typedef struct git_cred_ssh_keyfile_passphrase {
git_cred parent; git_cred parent;
char *username;
char *publickey; char *publickey;
char *privatekey; char *privatekey;
char *passphrase; char *passphrase;
...@@ -63,12 +68,20 @@ typedef struct git_cred_ssh_keyfile_passphrase { ...@@ -63,12 +68,20 @@ typedef struct git_cred_ssh_keyfile_passphrase {
/* A ssh public key and authentication callback */ /* A ssh public key and authentication callback */
typedef struct git_cred_ssh_publickey { typedef struct git_cred_ssh_publickey {
git_cred parent; git_cred parent;
char *username;
char *publickey; char *publickey;
size_t publickey_len; size_t publickey_len;
void *sign_callback; void *sign_callback;
void *sign_data; void *sign_data;
} git_cred_ssh_publickey; } git_cred_ssh_publickey;
#endif
/**
* Check whether a credential object contains username information.
*
* @param cred object to check
* @return 1 if the credential object has non-NULL username, 0 otherwise
*/
GIT_EXTERN(int) git_cred_has_username(git_cred *cred);
/** /**
* Creates a new plain-text username and password credential object. * Creates a new plain-text username and password credential object.
...@@ -84,12 +97,12 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( ...@@ -84,12 +97,12 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new(
const char *username, const char *username,
const char *password); const char *password);
#ifdef GIT_SSH
/** /**
* Creates a new ssh key file and passphrase credential object. * Creates a new ssh key file and passphrase credential object.
* The supplied credential parameter will be internally duplicated. * The supplied credential parameter will be internally duplicated.
* *
* @param out The newly created credential object. * @param out The newly created credential object.
* @param username username to use to authenticate
* @param publickey The path to the public key of the credential. * @param publickey The path to the public key of the credential.
* @param privatekey The path to the private key of the credential. * @param privatekey The path to the private key of the credential.
* @param passphrase The passphrase of the credential. * @param passphrase The passphrase of the credential.
...@@ -97,6 +110,7 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new( ...@@ -97,6 +110,7 @@ GIT_EXTERN(int) git_cred_userpass_plaintext_new(
*/ */
GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new(
git_cred **out, git_cred **out,
const char *username,
const char *publickey, const char *publickey,
const char *privatekey, const char *privatekey,
const char *passphrase); const char *passphrase);
...@@ -106,19 +120,20 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new( ...@@ -106,19 +120,20 @@ GIT_EXTERN(int) git_cred_ssh_keyfile_passphrase_new(
* The supplied credential parameter will be internally duplicated. * The supplied credential parameter will be internally duplicated.
* *
* @param out The newly created credential object. * @param out The newly created credential object.
* @param username username to use to authenticate
* @param publickey The bytes of the public key. * @param publickey The bytes of the public key.
* @param publickey_len The length of the public key in bytes. * @param publickey_len The length of the public key in bytes.
* @param sign_callback The callback method for authenticating. * @param sign_fn The callback method for authenticating.
* @param sign_data The abstract data sent to the sign_callback method. * @param sign_data The abstract data sent to the sign_callback method.
* @return 0 for success or an error code for failure * @return 0 for success or an error code for failure
*/ */
GIT_EXTERN(int) git_cred_ssh_publickey_new( GIT_EXTERN(int) git_cred_ssh_publickey_new(
git_cred **out, git_cred **out,
const char *username,
const char *publickey, const char *publickey,
size_t publickey_len, size_t publickey_len,
git_cred_sign_callback, git_cred_sign_callback sign_fn,
void *sign_data); void *sign_data);
#endif
/** /**
* Signature of a function which acquires a credential object. * Signature of a function which acquires a credential object.
...@@ -152,17 +167,21 @@ typedef enum { ...@@ -152,17 +167,21 @@ typedef enum {
typedef void (*git_transport_message_cb)(const char *str, int len, void *data); typedef void (*git_transport_message_cb)(const char *str, int len, void *data);
typedef struct git_transport { typedef struct git_transport git_transport;
struct git_transport {
unsigned int version; unsigned int version;
/* Set progress and error callbacks */ /* Set progress and error callbacks */
int (*set_callbacks)(struct git_transport *transport, int (*set_callbacks)(
git_transport *transport,
git_transport_message_cb progress_cb, git_transport_message_cb progress_cb,
git_transport_message_cb error_cb, git_transport_message_cb error_cb,
void *payload); void *payload);
/* Connect the transport to the remote repository, using the given /* Connect the transport to the remote repository, using the given
* direction. */ * direction. */
int (*connect)(struct git_transport *transport, int (*connect)(
git_transport *transport,
const char *url, const char *url,
git_cred_acquire_cb cred_acquire_cb, git_cred_acquire_cb cred_acquire_cb,
void *cred_acquire_payload, void *cred_acquire_payload,
...@@ -172,17 +191,19 @@ typedef struct git_transport { ...@@ -172,17 +191,19 @@ typedef struct git_transport {
/* This function may be called after a successful call to connect(). The /* This function may be called after a successful call to connect(). The
* provided callback is invoked for each ref discovered on the remote * provided callback is invoked for each ref discovered on the remote
* end. */ * end. */
int (*ls)(struct git_transport *transport, int (*ls)(
git_transport *transport,
git_headlist_cb list_cb, git_headlist_cb list_cb,
void *payload); void *payload);
/* Executes the push whose context is in the git_push object. */ /* Executes the push whose context is in the git_push object. */
int (*push)(struct git_transport *transport, git_push *push); int (*push)(git_transport *transport, git_push *push);
/* This function may be called after a successful call to connect(), when /* This function may be called after a successful call to connect(), when
* the direction is FETCH. The function performs a negotiation to calculate * the direction is FETCH. The function performs a negotiation to calculate
* the wants list for the fetch. */ * the wants list for the fetch. */
int (*negotiate_fetch)(struct git_transport *transport, int (*negotiate_fetch)(
git_transport *transport,
git_repository *repo, git_repository *repo,
const git_remote_head * const *refs, const git_remote_head * const *refs,
size_t count); size_t count);
...@@ -190,28 +211,29 @@ typedef struct git_transport { ...@@ -190,28 +211,29 @@ typedef struct git_transport {
/* This function may be called after a successful call to negotiate_fetch(), /* This function may be called after a successful call to negotiate_fetch(),
* when the direction is FETCH. This function retrieves the pack file for * when the direction is FETCH. This function retrieves the pack file for
* the fetch from the remote end. */ * the fetch from the remote end. */
int (*download_pack)(struct git_transport *transport, int (*download_pack)(
git_transport *transport,
git_repository *repo, git_repository *repo,
git_transfer_progress *stats, git_transfer_progress *stats,
git_transfer_progress_callback progress_cb, git_transfer_progress_callback progress_cb,
void *progress_payload); void *progress_payload);
/* Checks to see if the transport is connected */ /* Checks to see if the transport is connected */
int (*is_connected)(struct git_transport *transport); int (*is_connected)(git_transport *transport);
/* Reads the flags value previously passed into connect() */ /* Reads the flags value previously passed into connect() */
int (*read_flags)(struct git_transport *transport, int *flags); int (*read_flags)(git_transport *transport, int *flags);
/* Cancels any outstanding transport operation */ /* Cancels any outstanding transport operation */
void (*cancel)(struct git_transport *transport); void (*cancel)(git_transport *transport);
/* This function is the reverse of connect() -- it terminates the /* This function is the reverse of connect() -- it terminates the
* connection to the remote end. */ * connection to the remote end. */
int (*close)(struct git_transport *transport); int (*close)(git_transport *transport);
/* Frees/destructs the git_transport object. */ /* Frees/destructs the git_transport object. */
void (*free)(struct git_transport *transport); void (*free)(git_transport *transport);
} git_transport; };
#define GIT_TRANSPORT_VERSION 1 #define GIT_TRANSPORT_VERSION 1
#define GIT_TRANSPORT_INIT {GIT_TRANSPORT_VERSION} #define GIT_TRANSPORT_INIT {GIT_TRANSPORT_VERSION}
...@@ -299,35 +321,36 @@ typedef enum { ...@@ -299,35 +321,36 @@ typedef enum {
GIT_SERVICE_RECEIVEPACK = 4, GIT_SERVICE_RECEIVEPACK = 4,
} git_smart_service_t; } git_smart_service_t;
struct git_smart_subtransport; typedef struct git_smart_subtransport git_smart_subtransport;
typedef struct git_smart_subtransport_stream git_smart_subtransport_stream;
/* A stream used by the smart transport to read and write data /* A stream used by the smart transport to read and write data
* from a subtransport */ * from a subtransport */
typedef struct git_smart_subtransport_stream { struct git_smart_subtransport_stream {
/* The owning subtransport */ /* The owning subtransport */
struct git_smart_subtransport *subtransport; git_smart_subtransport *subtransport;
int (*read)( int (*read)(
struct git_smart_subtransport_stream *stream, git_smart_subtransport_stream *stream,
char *buffer, char *buffer,
size_t buf_size, size_t buf_size,
size_t *bytes_read); size_t *bytes_read);
int (*write)( int (*write)(
struct git_smart_subtransport_stream *stream, git_smart_subtransport_stream *stream,
const char *buffer, const char *buffer,
size_t len); size_t len);
void (*free)( void (*free)(
struct git_smart_subtransport_stream *stream); git_smart_subtransport_stream *stream);
} git_smart_subtransport_stream; };
/* An implementation of a subtransport which carries data for the /* An implementation of a subtransport which carries data for the
* smart transport */ * smart transport */
typedef struct git_smart_subtransport { struct git_smart_subtransport {
int (* action)( int (* action)(
git_smart_subtransport_stream **out, git_smart_subtransport_stream **out,
struct git_smart_subtransport *transport, git_smart_subtransport *transport,
const char *url, const char *url,
git_smart_service_t action); git_smart_service_t action);
...@@ -337,10 +360,10 @@ typedef struct git_smart_subtransport { ...@@ -337,10 +360,10 @@ typedef struct git_smart_subtransport {
* *
* 1. UPLOADPACK_LS -> UPLOADPACK * 1. UPLOADPACK_LS -> UPLOADPACK
* 2. RECEIVEPACK_LS -> RECEIVEPACK */ * 2. RECEIVEPACK_LS -> RECEIVEPACK */
int (* close)(struct git_smart_subtransport *transport); int (*close)(git_smart_subtransport *transport);
void (* free)(struct git_smart_subtransport *transport); void (*free)(git_smart_subtransport *transport);
} git_smart_subtransport; };
/* A function which creates a new subtransport for the smart transport */ /* A function which creates a new subtransport for the smart transport */
typedef int (*git_smart_subtransport_cb)( typedef int (*git_smart_subtransport_cb)(
......
...@@ -38,7 +38,7 @@ GIT_EXTERN(int) git_tree_lookup( ...@@ -38,7 +38,7 @@ GIT_EXTERN(int) git_tree_lookup(
* *
* @see git_object_lookup_prefix * @see git_object_lookup_prefix
* *
* @param tree pointer to the looked up tree * @param out pointer to the looked up tree
* @param repo the repo to use when locating the tree. * @param repo the repo to use when locating the tree.
* @param id identity of the tree to locate. * @param id identity of the tree to locate.
* @param len the length of the short identifier * @param len the length of the short identifier
...@@ -136,7 +136,7 @@ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byoid( ...@@ -136,7 +136,7 @@ GIT_EXTERN(const git_tree_entry *) git_tree_entry_byoid(
* *
* @param out Pointer where to store the tree entry * @param out Pointer where to store the tree entry
* @param root Previously loaded tree which is the root of the relative path * @param root Previously loaded tree which is the root of the relative path
* @param subtree_path Path to the contained entry * @param path Path to the contained entry
* @return 0 on success; GIT_ENOTFOUND if the path does not exist * @return 0 on success; GIT_ENOTFOUND if the path does not exist
*/ */
GIT_EXTERN(int) git_tree_entry_bypath( GIT_EXTERN(int) git_tree_entry_bypath(
...@@ -208,11 +208,11 @@ GIT_EXTERN(git_filemode_t) git_tree_entry_filemode(const git_tree_entry *entry); ...@@ -208,11 +208,11 @@ GIT_EXTERN(git_filemode_t) git_tree_entry_filemode(const git_tree_entry *entry);
GIT_EXTERN(int) git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2); GIT_EXTERN(int) git_tree_entry_cmp(const git_tree_entry *e1, const git_tree_entry *e2);
/** /**
* Convert a tree entry to the git_object it points too. * Convert a tree entry to the git_object it points to.
* *
* You must call `git_object_free()` on the object when you are done with it. * You must call `git_object_free()` on the object when you are done with it.
* *
* @param object pointer to the converted object * @param object_out pointer to the converted object
* @param repo repository where to lookup the pointed object * @param repo repository where to lookup the pointed object
* @param entry a tree entry * @param entry a tree entry
* @return 0 or an error code * @return 0 or an error code
...@@ -251,7 +251,7 @@ GIT_EXTERN(void) git_treebuilder_clear(git_treebuilder *bld); ...@@ -251,7 +251,7 @@ GIT_EXTERN(void) git_treebuilder_clear(git_treebuilder *bld);
/** /**
* Get the number of entries listed in a treebuilder * Get the number of entries listed in a treebuilder
* *
* @param tree a previously loaded treebuilder. * @param bld a previously loaded treebuilder.
* @return the number of entries in the treebuilder * @return the number of entries in the treebuilder
*/ */
GIT_EXTERN(unsigned int) git_treebuilder_entrycount(git_treebuilder *bld); GIT_EXTERN(unsigned int) git_treebuilder_entrycount(git_treebuilder *bld);
......
...@@ -174,6 +174,9 @@ typedef struct git_reference_iterator git_reference_iterator; ...@@ -174,6 +174,9 @@ typedef struct git_reference_iterator git_reference_iterator;
/** Merge heads, the input to merge */ /** Merge heads, the input to merge */
typedef struct git_merge_head git_merge_head; typedef struct git_merge_head git_merge_head;
/** Representation of a status collection */
typedef struct git_status_list git_status_list;
/** Basic type of any Git reference. */ /** Basic type of any Git reference. */
typedef enum { typedef enum {
...@@ -226,6 +229,77 @@ typedef struct git_transfer_progress { ...@@ -226,6 +229,77 @@ typedef struct git_transfer_progress {
*/ */
typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload); typedef int (*git_transfer_progress_callback)(const git_transfer_progress *stats, void *payload);
/**
* Opaque structure representing a submodule.
*/
typedef struct git_submodule git_submodule;
/**
* Submodule update values
*
* These values represent settings for the `submodule.$name.update`
* configuration value which says how to handle `git submodule update` for
* this submodule. The value is usually set in the ".gitmodules" file and
* copied to ".git/config" when the submodule is initialized.
*
* You can override this setting on a per-submodule basis with
* `git_submodule_set_update()` and write the changed value to disk using
* `git_submodule_save()`. If you have overwritten the value, you can
* revert it by passing `GIT_SUBMODULE_UPDATE_RESET` to the set function.
*
* The values are:
*
* - GIT_SUBMODULE_UPDATE_RESET: reset to the on-disk value.
* - GIT_SUBMODULE_UPDATE_CHECKOUT: the default; when a submodule is
* updated, checkout the new detached HEAD to the submodule directory.
* - GIT_SUBMODULE_UPDATE_REBASE: update by rebasing the current checked
* out branch onto the commit from the superproject.
* - GIT_SUBMODULE_UPDATE_MERGE: update by merging the commit in the
* superproject into the current checkout out branch of the submodule.
* - GIT_SUBMODULE_UPDATE_NONE: do not update this submodule even when
* the commit in the superproject is updated.
*/
typedef enum {
GIT_SUBMODULE_UPDATE_RESET = -1,
GIT_SUBMODULE_UPDATE_CHECKOUT = 1,
GIT_SUBMODULE_UPDATE_REBASE = 2,
GIT_SUBMODULE_UPDATE_MERGE = 3,
GIT_SUBMODULE_UPDATE_NONE = 4
} git_submodule_update_t;
/**
* Submodule ignore values
*
* These values represent settings for the `submodule.$name.ignore`
* configuration value which says how deeply to look at the working
* directory when getting submodule status.
*
* You can override this value in memory on a per-submodule basis with
* `git_submodule_set_ignore()` and can write the changed value to disk
* with `git_submodule_save()`. If you have overwritten the value, you
* can revert to the on disk value by using `GIT_SUBMODULE_IGNORE_RESET`.
*
* The values are:
*
* - GIT_SUBMODULE_IGNORE_RESET: reset to the on-disk value.
* - GIT_SUBMODULE_IGNORE_NONE: don't ignore any change - i.e. even an
* untracked file, will mark the submodule as dirty. Ignored files are
* still ignored, of course.
* - GIT_SUBMODULE_IGNORE_UNTRACKED: ignore untracked files; only changes
* to tracked files, or the index or the HEAD commit will matter.
* - GIT_SUBMODULE_IGNORE_DIRTY: ignore changes in the working directory,
* only considering changes if the HEAD of submodule has moved from the
* value in the superproject.
* - GIT_SUBMODULE_IGNORE_ALL: never check if the submodule is dirty
*/
typedef enum {
GIT_SUBMODULE_IGNORE_RESET = -1, /* reset to on-disk value */
GIT_SUBMODULE_IGNORE_NONE = 1, /* any change or untracked == dirty */
GIT_SUBMODULE_IGNORE_UNTRACKED = 2, /* dirty if tracked files change */
GIT_SUBMODULE_IGNORE_DIRTY = 3, /* only dirty if HEAD moved */
GIT_SUBMODULE_IGNORE_ALL = 4 /* never dirty */
} git_submodule_ignore_t;
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -7,9 +7,9 @@ ...@@ -7,9 +7,9 @@
#ifndef INCLUDE_git_version_h__ #ifndef INCLUDE_git_version_h__
#define INCLUDE_git_version_h__ #define INCLUDE_git_version_h__
#define LIBGIT2_VERSION "0.18.0" #define LIBGIT2_VERSION "0.19.0"
#define LIBGIT2_VER_MAJOR 0 #define LIBGIT2_VER_MAJOR 0
#define LIBGIT2_VER_MINOR 18 #define LIBGIT2_VER_MINOR 19
#define LIBGIT2_VER_REVISION 0 #define LIBGIT2_VER_REVISION 0
#endif #endif
#!/bin/sh
# Create a test repo which we can use for the online::push tests
mkdir $HOME/_temp
git init --bare $HOME/_temp/test.git
git daemon --listen=localhost --export-all --enable=receive-pack --base-path=$HOME/_temp $HOME/_temp 2>/dev/null &
export GITTEST_REMOTE_URL="git://localhost/test.git"
mkdir _build
cd _build
cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $?
cmake --build . --target install || exit $?
ctest -V . || exit $?
# Now that we've tested the raw git protocol, let's set up ssh to we
# can do the push tests over it
killall git-daemon
sudo start ssh
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -q
cat ~/.ssh/id_rsa.pub >>~/.ssh/authorized_keys
ssh-keyscan -t rsa localhost >>~/.ssh/known_hosts
export GITTEST_REMOTE_URL="ssh://localhost/$HOME/_temp/test.git"
export GITTEST_REMOTE_USER=$USER
export GITTEST_REMOTE_SSH_KEY="$HOME/.ssh/id_rsa"
export GITTEST_REMOTE_SSH_PUBKEY="$HOME/.ssh/id_rsa.pub"
export GITTEST_REMOTE_SSH_PASSPHRASE=""
if [ -e ./libgit2_clar ]; then
./libgit2_clar -sonline::push
fi
...@@ -30,37 +30,45 @@ ...@@ -30,37 +30,45 @@
#define git_array_init(a) \ #define git_array_init(a) \
do { (a).size = (a).asize = 0; (a).ptr = NULL; } while (0) do { (a).size = (a).asize = 0; (a).ptr = NULL; } while (0)
#define git_array_init_to_size(a, desired) \
do { (a).size = 0; (a).asize = desired; (a).ptr = git__calloc(desired, sizeof(*(a).ptr)); } while (0)
#define git_array_clear(a) \ #define git_array_clear(a) \
do { git__free((a).ptr); git_array_init(a); } while (0) do { git__free((a).ptr); git_array_init(a); } while (0)
#define GITERR_CHECK_ARRAY(a) GITERR_CHECK_ALLOC((a).ptr) #define GITERR_CHECK_ARRAY(a) GITERR_CHECK_ALLOC((a).ptr)
typedef git_array_t(void) git_array_generic_t; typedef git_array_t(char) git_array_generic_t;
/* use a generic array for growth so this can return the new item */ /* use a generic array for growth so this can return the new item */
GIT_INLINE(void *) git_array_grow(git_array_generic_t *a, size_t item_size) GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
{ {
git_array_generic_t *a = _a;
uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2; uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2;
void *new_array = git__realloc(a->ptr, new_size * item_size); char *new_array = git__realloc(a->ptr, new_size * item_size);
if (!new_array) { if (!new_array) {
git_array_clear(*a); git_array_clear(*a);
return NULL; return NULL;
} else { } else {
a->ptr = new_array; a->asize = new_size; a->size++; a->ptr = new_array; a->asize = new_size; a->size++;
return (((char *)a->ptr) + (a->size - 1) * item_size); return a->ptr + (a->size - 1) * item_size;
} }
} }
#define git_array_alloc(a) \ #define git_array_alloc(a) \
((a).size >= (a).asize) ? \ ((a).size >= (a).asize) ? \
git_array_grow((git_array_generic_t *)&(a), sizeof(*(a).ptr)) : \ git_array_grow(&(a), sizeof(*(a).ptr)) : \
(a).ptr ? &(a).ptr[(a).size++] : NULL (a).ptr ? &(a).ptr[(a).size++] : NULL
#define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL) #define git_array_last(a) ((a).size ? &(a).ptr[(a).size - 1] : NULL)
#define git_array_pop(a) ((a).size ? &(a).ptr[--(a).size] : NULL)
#define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL) #define git_array_get(a, i) (((i) < (a).size) ? &(a).ptr[(i)] : NULL)
#define git_array_size(a) (a).size #define git_array_size(a) (a).size
#define git_array_valid_index(a, i) ((i) < (a).size)
#endif #endif
...@@ -79,9 +79,13 @@ int git_attr_file__parse_buffer( ...@@ -79,9 +79,13 @@ int git_attr_file__parse_buffer(
while (!error && *scan) { while (!error && *scan) {
/* allocate rule if needed */ /* allocate rule if needed */
if (!rule && !(rule = git__calloc(1, sizeof(git_attr_rule)))) { if (!rule) {
error = -1; if (!(rule = git__calloc(1, sizeof(git_attr_rule)))) {
break; error = -1;
break;
}
rule->match.flags = GIT_ATTR_FNMATCH_ALLOWNEG |
GIT_ATTR_FNMATCH_ALLOWMACRO;
} }
/* parse the next "pattern attr attr attr" line */ /* parse the next "pattern attr attr attr" line */
...@@ -351,8 +355,8 @@ int git_attr_fnmatch__parse( ...@@ -351,8 +355,8 @@ int git_attr_fnmatch__parse(
if (parse_optimized_patterns(spec, pool, *base)) if (parse_optimized_patterns(spec, pool, *base))
return 0; return 0;
spec->flags = (spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE); spec->flags = (spec->flags & GIT_ATTR_FNMATCH__INCOMING);
allow_space = (spec->flags != 0); allow_space = ((spec->flags & GIT_ATTR_FNMATCH_ALLOWSPACE) != 0);
pattern = *base; pattern = *base;
...@@ -362,7 +366,7 @@ int git_attr_fnmatch__parse( ...@@ -362,7 +366,7 @@ int git_attr_fnmatch__parse(
return GIT_ENOTFOUND; return GIT_ENOTFOUND;
} }
if (*pattern == '[') { if (*pattern == '[' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWMACRO) != 0) {
if (strncmp(pattern, "[attr]", 6) == 0) { if (strncmp(pattern, "[attr]", 6) == 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO; spec->flags = spec->flags | GIT_ATTR_FNMATCH_MACRO;
pattern += 6; pattern += 6;
...@@ -370,7 +374,7 @@ int git_attr_fnmatch__parse( ...@@ -370,7 +374,7 @@ int git_attr_fnmatch__parse(
/* else a character range like [a-e]* which is accepted */ /* else a character range like [a-e]* which is accepted */
} }
if (*pattern == '!') { if (*pattern == '!' && (spec->flags & GIT_ATTR_FNMATCH_ALLOWNEG) != 0) {
spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE; spec->flags = spec->flags | GIT_ATTR_FNMATCH_NEGATIVE;
pattern++; pattern++;
} }
...@@ -498,7 +502,7 @@ int git_attr_assignment__parse( ...@@ -498,7 +502,7 @@ int git_attr_assignment__parse(
assert(assigns && !assigns->length); assert(assigns && !assigns->length);
assigns->_cmp = sort_by_hash_and_name; git_vector_set_cmp(assigns, sort_by_hash_and_name);
while (*scan && *scan != '\n') { while (*scan && *scan != '\n') {
const char *name_start, *value_start; const char *name_start, *value_start;
......
...@@ -28,6 +28,12 @@ ...@@ -28,6 +28,12 @@
#define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6) #define GIT_ATTR_FNMATCH_ALLOWSPACE (1U << 6)
#define GIT_ATTR_FNMATCH_ICASE (1U << 7) #define GIT_ATTR_FNMATCH_ICASE (1U << 7)
#define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8) #define GIT_ATTR_FNMATCH_MATCH_ALL (1U << 8)
#define GIT_ATTR_FNMATCH_ALLOWNEG (1U << 9)
#define GIT_ATTR_FNMATCH_ALLOWMACRO (1U << 10)
#define GIT_ATTR_FNMATCH__INCOMING \
(GIT_ATTR_FNMATCH_ALLOWSPACE | \
GIT_ATTR_FNMATCH_ALLOWNEG | GIT_ATTR_FNMATCH_ALLOWMACRO)
extern const char *git_attr__true; extern const char *git_attr__true;
extern const char *git_attr__false; extern const char *git_attr__false;
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_bitvec_h__
#define INCLUDE_bitvec_h__
#include "util.h"
/*
* This is a silly little fixed length bit vector type that will store
* vectors of 64 bits or less directly in the structure and allocate
* memory for vectors longer than 64 bits. You can use the two versions
* transparently through the API and avoid heap allocation completely when
* using a short bit vector as a result.
*/
typedef struct {
size_t length;
union {
uint64_t *words;
uint64_t bits;
} u;
} git_bitvec;
GIT_INLINE(int) git_bitvec_init(git_bitvec *bv, size_t capacity)
{
memset(bv, 0x0, sizeof(*bv));
if (capacity >= 64) {
bv->length = (capacity / 64) + 1;
bv->u.words = git__calloc(bv->length, sizeof(uint64_t));
if (!bv->u.words)
return -1;
}
return 0;
}
#define GIT_BITVEC_MASK(BIT) ((uint64_t)1 << (BIT % 64))
#define GIT_BITVEC_WORD(BV, BIT) (BV->length ? &BV->u.words[BIT / 64] : &BV->u.bits)
GIT_INLINE(void) git_bitvec_set(git_bitvec *bv, size_t bit, bool on)
{
uint64_t *word = GIT_BITVEC_WORD(bv, bit);
uint64_t mask = GIT_BITVEC_MASK(bit);
if (on)
*word |= mask;
else
*word &= ~mask;
}
GIT_INLINE(bool) git_bitvec_get(git_bitvec *bv, size_t bit)
{
uint64_t *word = GIT_BITVEC_WORD(bv, bit);
return (*word & GIT_BITVEC_MASK(bit)) != 0;
}
GIT_INLINE(void) git_bitvec_clear(git_bitvec *bv)
{
if (!bv->length)
bv->u.bits = 0;
else
memset(bv->u.words, 0x0, bv->length * sizeof(uint64_t));
}
GIT_INLINE(void) git_bitvec_free(git_bitvec *bv)
{
if (bv->length)
git__free(bv->u.words);
}
#endif
...@@ -60,10 +60,10 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b ...@@ -60,10 +60,10 @@ int git_blob_create_frombuffer(git_oid *oid, git_repository *repo, const void *b
(error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0) (error = git_odb_open_wstream(&stream, odb, len, GIT_OBJ_BLOB)) < 0)
return error; return error;
if ((error = stream->write(stream, buffer, len)) == 0) if ((error = git_odb_stream_write(stream, buffer, len)) == 0)
error = stream->finalize_write(oid, stream); error = git_odb_stream_finalize_write(oid, stream);
stream->free(stream); git_odb_stream_free(stream);
return error; return error;
} }
...@@ -80,12 +80,12 @@ static int write_file_stream( ...@@ -80,12 +80,12 @@ static int write_file_stream(
return error; return error;
if ((fd = git_futils_open_ro(path)) < 0) { if ((fd = git_futils_open_ro(path)) < 0) {
stream->free(stream); git_odb_stream_free(stream);
return -1; return -1;
} }
while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) { while (!error && (read_len = p_read(fd, buffer, sizeof(buffer))) > 0) {
error = stream->write(stream, buffer, read_len); error = git_odb_stream_write(stream, buffer, read_len);
written += read_len; written += read_len;
} }
...@@ -97,14 +97,15 @@ static int write_file_stream( ...@@ -97,14 +97,15 @@ static int write_file_stream(
} }
if (!error) if (!error)
error = stream->finalize_write(oid, stream); error = git_odb_stream_finalize_write(oid, stream);
stream->free(stream); git_odb_stream_free(stream);
return error; return error;
} }
static int write_file_filtered( static int write_file_filtered(
git_oid *oid, git_oid *oid,
git_off_t *size,
git_odb *odb, git_odb *odb,
const char *full_path, const char *full_path,
git_vector *filters) git_vector *filters)
...@@ -123,8 +124,11 @@ static int write_file_filtered( ...@@ -123,8 +124,11 @@ static int write_file_filtered(
git_buf_free(&source); git_buf_free(&source);
/* Write the file to disk if it was properly filtered */ /* Write the file to disk if it was properly filtered */
if (!error) if (!error) {
*size = dest.size;
error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB); error = git_odb_write(oid, odb, dest.ptr, dest.size, GIT_OBJ_BLOB);
}
git_buf_free(&dest); git_buf_free(&dest);
return error; return error;
...@@ -152,21 +156,46 @@ static int write_symlink( ...@@ -152,21 +156,46 @@ static int write_symlink(
return error; return error;
} }
static int blob_create_internal(git_oid *oid, git_repository *repo, const char *content_path, const char *hint_path, bool try_load_filters) int git_blob__create_from_paths(
git_oid *oid,
struct stat *out_st,
git_repository *repo,
const char *content_path,
const char *hint_path,
mode_t hint_mode,
bool try_load_filters)
{ {
int error; int error;
struct stat st; struct stat st;
git_odb *odb = NULL; git_odb *odb = NULL;
git_off_t size; git_off_t size;
mode_t mode;
git_buf path = GIT_BUF_INIT;
assert(hint_path || !try_load_filters); assert(hint_path || !try_load_filters);
if ((error = git_path_lstat(content_path, &st)) < 0 || (error = git_repository_odb__weakptr(&odb, repo)) < 0) if (!content_path) {
return error; if (git_repository__ensure_not_bare(repo, "create blob from file") < 0)
return GIT_EBAREREPO;
if (git_buf_joinpath(
&path, git_repository_workdir(repo), hint_path) < 0)
return -1;
content_path = path.ptr;
}
if ((error = git_path_lstat(content_path, &st)) < 0 ||
(error = git_repository_odb(&odb, repo)) < 0)
goto done;
if (out_st)
memcpy(out_st, &st, sizeof(st));
size = st.st_size; size = st.st_size;
mode = hint_mode ? hint_mode : st.st_mode;
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(mode)) {
error = write_symlink(oid, odb, content_path, (size_t)size); error = write_symlink(oid, odb, content_path, (size_t)size);
} else { } else {
git_vector write_filters = GIT_VECTOR_INIT; git_vector write_filters = GIT_VECTOR_INIT;
...@@ -187,7 +216,8 @@ static int blob_create_internal(git_oid *oid, git_repository *repo, const char * ...@@ -187,7 +216,8 @@ static int blob_create_internal(git_oid *oid, git_repository *repo, const char *
error = write_file_stream(oid, odb, content_path, size); error = write_file_stream(oid, odb, content_path, size);
} else { } else {
/* We need to apply one or more filters */ /* We need to apply one or more filters */
error = write_file_filtered(oid, odb, content_path, &write_filters); error = write_file_filtered(
oid, &size, odb, content_path, &write_filters);
} }
git_filters_free(&write_filters); git_filters_free(&write_filters);
...@@ -207,34 +237,21 @@ static int blob_create_internal(git_oid *oid, git_repository *repo, const char * ...@@ -207,34 +237,21 @@ static int blob_create_internal(git_oid *oid, git_repository *repo, const char *
*/ */
} }
done:
git_odb_free(odb);
git_buf_free(&path);
return error; return error;
} }
int git_blob_create_fromworkdir(git_oid *oid, git_repository *repo, const char *path) int git_blob_create_fromworkdir(
git_oid *oid, git_repository *repo, const char *path)
{ {
git_buf full_path = GIT_BUF_INIT; return git_blob__create_from_paths(oid, NULL, repo, NULL, path, 0, true);
const char *workdir;
int error;
if ((error = git_repository__ensure_not_bare(repo, "create blob from file")) < 0)
return error;
workdir = git_repository_workdir(repo);
if (git_buf_joinpath(&full_path, workdir, path) < 0) {
git_buf_free(&full_path);
return -1;
}
error = blob_create_internal(
oid, repo, git_buf_cstr(&full_path),
git_buf_cstr(&full_path) + strlen(workdir), true);
git_buf_free(&full_path);
return error;
} }
int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *path) int git_blob_create_fromdisk(
git_oid *oid, git_repository *repo, const char *path)
{ {
int error; int error;
git_buf full_path = GIT_BUF_INIT; git_buf full_path = GIT_BUF_INIT;
...@@ -251,8 +268,8 @@ int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *pat ...@@ -251,8 +268,8 @@ int git_blob_create_fromdisk(git_oid *oid, git_repository *repo, const char *pat
if (workdir && !git__prefixcmp(hintpath, workdir)) if (workdir && !git__prefixcmp(hintpath, workdir))
hintpath += strlen(workdir); hintpath += strlen(workdir);
error = blob_create_internal( error = git_blob__create_from_paths(
oid, repo, git_buf_cstr(&full_path), hintpath, true); oid, NULL, repo, git_buf_cstr(&full_path), hintpath, 0, true);
git_buf_free(&full_path); git_buf_free(&full_path);
return error; return error;
...@@ -272,12 +289,9 @@ int git_blob_create_fromchunks( ...@@ -272,12 +289,9 @@ int git_blob_create_fromchunks(
git_filebuf file = GIT_FILEBUF_INIT; git_filebuf file = GIT_FILEBUF_INIT;
git_buf path = GIT_BUF_INIT; git_buf path = GIT_BUF_INIT;
if (git_buf_join_n( if (git_buf_joinpath(
&path, '/', 3, &path, git_repository_path(repo), GIT_OBJECTS_DIR "streamed") < 0)
git_repository_path(repo), goto cleanup;
GIT_OBJECTS_DIR,
"streamed") < 0)
goto cleanup;
content = git__malloc(BUFFER_SIZE); content = git__malloc(BUFFER_SIZE);
GITERR_CHECK_ALLOC(content); GITERR_CHECK_ALLOC(content);
...@@ -303,7 +317,8 @@ int git_blob_create_fromchunks( ...@@ -303,7 +317,8 @@ int git_blob_create_fromchunks(
if (git_filebuf_flush(&file) < 0) if (git_filebuf_flush(&file) < 0)
goto cleanup; goto cleanup;
error = blob_create_internal(oid, repo, file.path_lock, hintpath, hintpath != NULL); error = git_blob__create_from_paths(
oid, NULL, repo, file.path_lock, hintpath, 0, hintpath != NULL);
cleanup: cleanup:
git_buf_free(&path); git_buf_free(&path);
......
...@@ -21,4 +21,13 @@ void git_blob__free(void *blob); ...@@ -21,4 +21,13 @@ void git_blob__free(void *blob);
int git_blob__parse(void *blob, git_odb_object *obj); int git_blob__parse(void *blob, git_odb_object *obj);
int git_blob__getbuf(git_buf *buffer, git_blob *blob); int git_blob__getbuf(git_buf *buffer, git_blob *blob);
extern int git_blob__create_from_paths(
git_oid *out_oid,
struct stat *out_st,
git_repository *repo,
const char *full_path,
const char *hint_path,
mode_t hint_mode,
bool apply_filters);
#endif #endif
...@@ -132,7 +132,7 @@ int git_branch_foreach( ...@@ -132,7 +132,7 @@ int git_branch_foreach(
{ {
git_reference_iterator *iter; git_reference_iterator *iter;
git_reference *ref; git_reference *ref;
int error; int error = 0;
if (git_reference_iterator_new(&iter, repo) < 0) if (git_reference_iterator_new(&iter, repo) < 0)
return -1; return -1;
...@@ -143,7 +143,6 @@ int git_branch_foreach( ...@@ -143,7 +143,6 @@ int git_branch_foreach(
if (callback(ref->name + strlen(GIT_REFS_HEADS_DIR), if (callback(ref->name + strlen(GIT_REFS_HEADS_DIR),
GIT_BRANCH_LOCAL, payload)) { GIT_BRANCH_LOCAL, payload)) {
error = GIT_EUSER; error = GIT_EUSER;
break;
} }
} }
...@@ -152,11 +151,14 @@ int git_branch_foreach( ...@@ -152,11 +151,14 @@ int git_branch_foreach(
if (callback(ref->name + strlen(GIT_REFS_REMOTES_DIR), if (callback(ref->name + strlen(GIT_REFS_REMOTES_DIR),
GIT_BRANCH_REMOTE, payload)) { GIT_BRANCH_REMOTE, payload)) {
error = GIT_EUSER; error = GIT_EUSER;
break;
} }
} }
git_reference_free(ref); git_reference_free(ref);
/* check if the callback has cancelled iteration */
if (error == GIT_EUSER)
break;
} }
if (error == GIT_ITEROVER) if (error == GIT_ITEROVER)
......
...@@ -170,8 +170,14 @@ int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strings) ...@@ -170,8 +170,14 @@ int git_buf_text_common_prefix(git_buf *buf, const git_strarray *strings)
bool git_buf_text_is_binary(const git_buf *buf) bool git_buf_text_is_binary(const git_buf *buf)
{ {
const char *scan = buf->ptr, *end = buf->ptr + buf->size; const char *scan = buf->ptr, *end = buf->ptr + buf->size;
git_bom_t bom;
int printable = 0, nonprintable = 0; int printable = 0, nonprintable = 0;
scan += git_buf_text_detect_bom(&bom, buf, 0);
if (bom > GIT_BOM_UTF8)
return 1;
while (scan < end) { while (scan < end) {
unsigned char c = *scan++; unsigned char c = *scan++;
...@@ -262,7 +268,7 @@ bool git_buf_text_gather_stats( ...@@ -262,7 +268,7 @@ bool git_buf_text_gather_stats(
while (scan < end) { while (scan < end) {
unsigned char c = *scan++; unsigned char c = *scan++;
if ((c > 0x1F && c < 0x7F) || c > 0x9f) if (c > 0x1F && c != 0x7F)
stats->printable++; stats->printable++;
else switch (c) { else switch (c) {
case '\0': case '\0':
......
...@@ -259,6 +259,15 @@ void git_buf_truncate(git_buf *buf, size_t len) ...@@ -259,6 +259,15 @@ void git_buf_truncate(git_buf *buf, size_t len)
} }
} }
void git_buf_shorten(git_buf *buf, size_t amount)
{
if (amount > buf->size)
amount = buf->size;
buf->size = buf->size - amount;
buf->ptr[buf->size] = '\0';
}
void git_buf_rtruncate_at_char(git_buf *buf, char separator) void git_buf_rtruncate_at_char(git_buf *buf, char separator)
{ {
ssize_t idx = git_buf_rfind_next(buf, separator); ssize_t idx = git_buf_rfind_next(buf, separator);
......
...@@ -91,6 +91,7 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap); ...@@ -91,6 +91,7 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap);
void git_buf_clear(git_buf *buf); void git_buf_clear(git_buf *buf);
void git_buf_consume(git_buf *buf, const char *end); void git_buf_consume(git_buf *buf, const char *end);
void git_buf_truncate(git_buf *buf, size_t len); void git_buf_truncate(git_buf *buf, size_t len);
void git_buf_shorten(git_buf *buf, size_t amount);
void git_buf_rtruncate_at_char(git_buf *path, char separator); 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_n(git_buf *buf, char separator, int nbuf, ...);
......
...@@ -54,8 +54,12 @@ ...@@ -54,8 +54,12 @@
#if defined (_MSC_VER) #if defined (_MSC_VER)
typedef unsigned char bool; typedef unsigned char bool;
# define true 1 # ifndef true
# define false 0 # define true 1
# endif
# ifndef false
# define false 0
# endif
#else #else
# include <stdbool.h> # include <stdbool.h>
#endif #endif
......
...@@ -220,9 +220,11 @@ static int checkout_action_no_wd( ...@@ -220,9 +220,11 @@ static int checkout_action_no_wd(
action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE); action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, NONE);
break; break;
case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */ case GIT_DELTA_ADDED: /* case 2 or 28 (and 5 but not really) */
case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
break; break;
case GIT_DELTA_MODIFIED: /* case 13 (and 35 but not really) */
action = CHECKOUT_ACTION_IF(SAFE_CREATE, UPDATE_BLOB, CONFLICT);
break;
case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/ case GIT_DELTA_TYPECHANGE: /* case 21 (B->T) and 28 (T->B)*/
if (delta->new_file.mode == GIT_FILEMODE_TREE) if (delta->new_file.mode == GIT_FILEMODE_TREE)
action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE); action = CHECKOUT_ACTION_IF(SAFE, UPDATE_BLOB, NONE);
...@@ -244,10 +246,10 @@ static int checkout_action_wd_only( ...@@ -244,10 +246,10 @@ static int checkout_action_wd_only(
bool remove = false; bool remove = false;
git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE; git_checkout_notify_t notify = GIT_CHECKOUT_NOTIFY_NONE;
if (!git_pathspec_match_path( if (!git_pathspec__match(
pathspec, wd->path, pathspec, wd->path,
(data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0, (data->strategy & GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH) != 0,
git_iterator_ignore_case(workdir), NULL)) git_iterator_ignore_case(workdir), NULL, NULL))
return 0; return 0;
/* check if item is tracked in the index but not in the checkout diff */ /* check if item is tracked in the index but not in the checkout diff */
...@@ -605,7 +607,7 @@ static int checkout_get_actions( ...@@ -605,7 +607,7 @@ static int checkout_get_actions(
uint32_t *actions = NULL; uint32_t *actions = NULL;
if (data->opts.paths.count > 0 && if (data->opts.paths.count > 0 &&
git_pathspec_init(&pathspec, &data->opts.paths, &pathpool) < 0) git_pathspec__vinit(&pathspec, &data->opts.paths, &pathpool) < 0)
return -1; return -1;
if ((error = git_iterator_current(&wditem, workdir)) < 0 && if ((error = git_iterator_current(&wditem, workdir)) < 0 &&
...@@ -657,7 +659,7 @@ static int checkout_get_actions( ...@@ -657,7 +659,7 @@ static int checkout_get_actions(
goto fail; goto fail;
} }
git_pathspec_free(&pathspec); git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool); git_pool_clear(&pathpool);
return 0; return 0;
...@@ -668,7 +670,7 @@ fail: ...@@ -668,7 +670,7 @@ fail:
*actions_ptr = NULL; *actions_ptr = NULL;
git__free(actions); git__free(actions);
git_pathspec_free(&pathspec); git_pathspec__vfree(&pathspec);
git_pool_clear(&pathpool); git_pool_clear(&pathpool);
return error; return error;
...@@ -691,17 +693,14 @@ static int buffer_to_file( ...@@ -691,17 +693,14 @@ static int buffer_to_file(
buffer, path, file_open_flags, file_mode)) < 0) buffer, path, file_open_flags, file_mode)) < 0)
return error; return error;
if (st != NULL && (error = p_stat(path, st)) < 0) { if (st != NULL && (error = p_stat(path, st)) < 0)
giterr_set(GITERR_OS, "Error while statting '%s'", path); giterr_set(GITERR_OS, "Error statting '%s'", path);
return error;
}
if ((file_mode & 0100) != 0 && (error = p_chmod(path, file_mode)) < 0) { else if (GIT_PERMS_IS_EXEC(file_mode) &&
(error = p_chmod(path, file_mode)) < 0)
giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path); giterr_set(GITERR_OS, "Failed to set permissions on '%s'", path);
return error;
}
return 0; return error;
} }
static int blob_content_to_file( static int blob_content_to_file(
...@@ -856,7 +855,7 @@ static int checkout_submodule( ...@@ -856,7 +855,7 @@ static int checkout_submodule(
return 0; return 0;
if ((error = git_futils_mkdir( if ((error = git_futils_mkdir(
file->path, git_repository_workdir(data->repo), file->path, data->opts.target_directory,
data->opts.dir_mode, GIT_MKDIR_PATH)) < 0) data->opts.dir_mode, GIT_MKDIR_PATH)) < 0)
return error; return error;
...@@ -1028,7 +1027,7 @@ static int checkout_deferred_remove(git_repository *repo, const char *path) ...@@ -1028,7 +1027,7 @@ static int checkout_deferred_remove(git_repository *repo, const char *path)
{ {
#if 0 #if 0
int error = git_futils_rmdir_r( int error = git_futils_rmdir_r(
path, git_repository_workdir(repo), GIT_RMDIR_EMPTY_PARENTS); path, data->opts.target_directory, GIT_RMDIR_EMPTY_PARENTS);
if (error == GIT_ENOTFOUND) { if (error == GIT_ENOTFOUND) {
error = 0; error = 0;
...@@ -1161,7 +1160,8 @@ static int checkout_data_init( ...@@ -1161,7 +1160,8 @@ static int checkout_data_init(
return -1; return -1;
} }
if ((error = git_repository__ensure_not_bare(repo, "checkout")) < 0) if ((!proposed || !proposed->target_directory) &&
(error = git_repository__ensure_not_bare(repo, "checkout")) < 0)
return error; return error;
data->repo = repo; data->repo = repo;
...@@ -1174,6 +1174,13 @@ static int checkout_data_init( ...@@ -1174,6 +1174,13 @@ static int checkout_data_init(
else else
memmove(&data->opts, proposed, sizeof(git_checkout_opts)); memmove(&data->opts, proposed, sizeof(git_checkout_opts));
if (!data->opts.target_directory)
data->opts.target_directory = git_repository_workdir(repo);
else if (!git_path_isdir(data->opts.target_directory) &&
(error = git_futils_mkdir(data->opts.target_directory, NULL,
GIT_DIR_MODE, GIT_MKDIR_VERIFY_DIR)) < 0)
goto cleanup;
/* refresh config and index content unless NO_REFRESH is given */ /* refresh config and index content unless NO_REFRESH is given */
if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) { if ((data->opts.checkout_strategy & GIT_CHECKOUT_NO_REFRESH) == 0) {
git_config *cfg; git_config *cfg;
...@@ -1236,7 +1243,8 @@ static int checkout_data_init( ...@@ -1236,7 +1243,8 @@ static int checkout_data_init(
if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 || if ((error = git_vector_init(&data->removes, 0, git__strcmp_cb)) < 0 ||
(error = git_pool_init(&data->pool, 1, 0)) < 0 || (error = git_pool_init(&data->pool, 1, 0)) < 0 ||
(error = git_buf_puts(&data->path, git_repository_workdir(repo))) < 0) (error = git_buf_puts(&data->path, data->opts.target_directory)) < 0 ||
(error = git_path_to_dir(&data->path)) < 0)
goto cleanup; goto cleanup;
data->workdir_len = git_buf_len(&data->path); data->workdir_len = git_buf_len(&data->path);
...@@ -1284,11 +1292,13 @@ int git_checkout_iterator( ...@@ -1284,11 +1292,13 @@ int git_checkout_iterator(
GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE; GIT_ITERATOR_IGNORE_CASE : GIT_ITERATOR_DONT_IGNORE_CASE;
if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 || if ((error = git_iterator_reset(target, data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_workdir( (error = git_iterator_for_workdir_ext(
&workdir, data.repo, iterflags | GIT_ITERATOR_DONT_AUTOEXPAND, &workdir, data.repo, data.opts.target_directory,
iterflags | GIT_ITERATOR_DONT_AUTOEXPAND,
data.pfx, data.pfx)) < 0 || data.pfx, data.pfx)) < 0 ||
(error = git_iterator_for_tree( (error = git_iterator_for_tree(
&baseline, data.opts.baseline, iterflags, data.pfx, data.pfx)) < 0) &baseline, data.opts.baseline,
iterflags, data.pfx, data.pfx)) < 0)
goto cleanup; goto cleanup;
/* Should not have case insensitivity mismatch */ /* Should not have case insensitivity mismatch */
...@@ -1356,8 +1366,19 @@ int git_checkout_index( ...@@ -1356,8 +1366,19 @@ int git_checkout_index(
int error; int error;
git_iterator *index_i; git_iterator *index_i;
if ((error = git_repository__ensure_not_bare(repo, "checkout index")) < 0) if (!index && !repo) {
return error; giterr_set(GITERR_CHECKOUT,
"Must provide either repository or index to checkout");
return -1;
}
if (index && repo && git_index_owner(index) != repo) {
giterr_set(GITERR_CHECKOUT,
"Index to checkout does not match repository");
return -1;
}
if (!repo)
repo = git_index_owner(index);
if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0) if (!index && (error = git_repository_index__weakptr(&index, repo)) < 0)
return error; return error;
...@@ -1381,8 +1402,19 @@ int git_checkout_tree( ...@@ -1381,8 +1402,19 @@ int git_checkout_tree(
git_tree *tree = NULL; git_tree *tree = NULL;
git_iterator *tree_i = NULL; git_iterator *tree_i = NULL;
if ((error = git_repository__ensure_not_bare(repo, "checkout tree")) < 0) if (!treeish && !repo) {
return error; giterr_set(GITERR_CHECKOUT,
"Must provide either repository or tree to checkout");
return -1;
}
if (treeish && repo && git_object_owner(treeish) != repo) {
giterr_set(GITERR_CHECKOUT,
"Object to checkout does not match repository");
return -1;
}
if (!repo)
repo = git_object_owner(treeish);
if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) { if (git_object_peel((git_object **)&tree, treeish, GIT_OBJ_TREE) < 0) {
giterr_set( giterr_set(
...@@ -1407,8 +1439,7 @@ int git_checkout_head( ...@@ -1407,8 +1439,7 @@ int git_checkout_head(
git_tree *head = NULL; git_tree *head = NULL;
git_iterator *head_i = NULL; git_iterator *head_i = NULL;
if ((error = git_repository__ensure_not_bare(repo, "checkout head")) < 0) assert(repo);
return error;
if (!(error = checkout_lookup_head_tree(&head, repo)) && if (!(error = checkout_lookup_head_tree(&head, repo)) &&
!(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL))) !(error = git_iterator_for_tree(&head_i, head, 0, NULL, NULL)))
......
...@@ -204,7 +204,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) ...@@ -204,7 +204,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
/* Get the remote's HEAD. This is always the first ref in remote->refs. */ /* Get the remote's HEAD. This is always the first ref in remote->refs. */
remote_head = NULL; remote_head = NULL;
if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head)) if (!remote->transport->ls(remote->transport, get_head_callback, &remote_head))
return -1; return -1;
...@@ -220,7 +220,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote) ...@@ -220,7 +220,7 @@ static int update_head_to_remote(git_repository *repo, git_remote *remote)
memset(&dummy_spec, 0, sizeof(git_refspec)); memset(&dummy_spec, 0, sizeof(git_refspec));
head_info.refspec = &dummy_spec; head_info.refspec = &dummy_spec;
} }
/* Determine the remote tracking reference name from the local master */ /* Determine the remote tracking reference name from the local master */
if (git_refspec_transform_r( if (git_refspec_transform_r(
&remote_master_name, &remote_master_name,
...@@ -418,7 +418,7 @@ static bool should_checkout( ...@@ -418,7 +418,7 @@ static bool should_checkout(
return !git_repository_head_orphan(repo); return !git_repository_head_orphan(repo);
} }
static void normalize_options(git_clone_options *dst, const git_clone_options *src) static void normalize_options(git_clone_options *dst, const git_clone_options *src, git_repository_init_options *initOptions)
{ {
git_clone_options default_options = GIT_CLONE_OPTIONS_INIT; git_clone_options default_options = GIT_CLONE_OPTIONS_INIT;
if (!src) src = &default_options; if (!src) src = &default_options;
...@@ -427,6 +427,13 @@ static void normalize_options(git_clone_options *dst, const git_clone_options *s ...@@ -427,6 +427,13 @@ static void normalize_options(git_clone_options *dst, const git_clone_options *s
/* Provide defaults for null pointers */ /* Provide defaults for null pointers */
if (!dst->remote_name) dst->remote_name = "origin"; if (!dst->remote_name) dst->remote_name = "origin";
if (!dst->init_options)
{
dst->init_options = initOptions;
initOptions->flags = GIT_REPOSITORY_INIT_MKPATH;
if (dst->bare)
initOptions->flags |= GIT_REPOSITORY_INIT_BARE;
}
} }
int git_clone( int git_clone(
...@@ -439,10 +446,11 @@ int git_clone( ...@@ -439,10 +446,11 @@ int git_clone(
git_repository *repo = NULL; git_repository *repo = NULL;
git_clone_options normOptions; git_clone_options normOptions;
int remove_directory_on_failure = 0; int remove_directory_on_failure = 0;
git_repository_init_options initOptions = GIT_REPOSITORY_INIT_OPTIONS_INIT;
assert(out && url && local_path); assert(out && url && local_path);
normalize_options(&normOptions, options); normalize_options(&normOptions, options, &initOptions);
GITERR_CHECK_VERSION(&normOptions, GIT_CLONE_OPTIONS_VERSION, "git_clone_options"); GITERR_CHECK_VERSION(&normOptions, GIT_CLONE_OPTIONS_VERSION, "git_clone_options");
/* Only clone to a new directory or an empty directory */ /* Only clone to a new directory or an empty directory */
...@@ -455,7 +463,7 @@ int git_clone( ...@@ -455,7 +463,7 @@ int git_clone(
/* Only remove the directory on failure if we create it */ /* Only remove the directory on failure if we create it */
remove_directory_on_failure = !git_path_exists(local_path); remove_directory_on_failure = !git_path_exists(local_path);
if (!(retcode = git_repository_init(&repo, local_path, normOptions.bare))) { if (!(retcode = git_repository_init_ext(&repo, local_path, normOptions.init_options))) {
if ((retcode = setup_remotes_and_fetch(repo, url, &normOptions)) < 0) { if ((retcode = setup_remotes_and_fetch(repo, url, &normOptions)) < 0) {
/* Failed to fetch; clean up */ /* Failed to fetch; clean up */
git_repository_free(repo); git_repository_free(repo);
......
...@@ -19,30 +19,19 @@ ...@@ -19,30 +19,19 @@
#include <stdarg.h> #include <stdarg.h>
static void clear_parents(git_commit *commit)
{
size_t i;
for (i = 0; i < commit->parent_ids.length; ++i) {
git_oid *parent = git_vector_get(&commit->parent_ids, i);
git__free(parent);
}
git_vector_clear(&commit->parent_ids);
}
void git_commit__free(void *_commit) void git_commit__free(void *_commit)
{ {
git_commit *commit = _commit; git_commit *commit = _commit;
clear_parents(commit); git_array_clear(commit->parent_ids);
git_vector_free(&commit->parent_ids);
git_signature_free(commit->author); git_signature_free(commit->author);
git_signature_free(commit->committer); git_signature_free(commit->committer);
git__free(commit->raw_header);
git__free(commit->message); git__free(commit->message);
git__free(commit->message_encoding); git__free(commit->message_encoding);
git__free(commit); git__free(commit);
} }
...@@ -171,12 +160,35 @@ int git_commit_create( ...@@ -171,12 +160,35 @@ int git_commit_create(
int git_commit__parse(void *_commit, git_odb_object *odb_obj) int git_commit__parse(void *_commit, git_odb_object *odb_obj)
{ {
git_commit *commit = _commit; git_commit *commit = _commit;
const char *buffer = git_odb_object_data(odb_obj); const char *buffer_start = git_odb_object_data(odb_obj), *buffer;
const char *buffer_end = buffer + git_odb_object_size(odb_obj); const char *buffer_end = buffer_start + git_odb_object_size(odb_obj);
git_oid parent_id; git_oid parent_id;
uint32_t parent_count = 0;
size_t header_len;
/* find end-of-header (counting parents as we go) */
for (buffer = buffer_start; buffer < buffer_end; ++buffer) {
if (!strncmp("\n\n", buffer, 2)) {
++buffer;
break;
}
if (!strncmp("\nparent ", buffer, strlen("\nparent ")))
++parent_count;
}
if (git_vector_init(&commit->parent_ids, 4, NULL) < 0) header_len = buffer - buffer_start;
return -1; commit->raw_header = git__strndup(buffer_start, header_len);
GITERR_CHECK_ALLOC(commit->raw_header);
/* point "buffer" to header data */
buffer = commit->raw_header;
buffer_end = commit->raw_header + header_len;
if (parent_count < 1)
parent_count = 1;
git_array_init_to_size(commit->parent_ids, parent_count);
GITERR_CHECK_ARRAY(commit->parent_ids);
if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0) if (git_oid__parse(&commit->tree_id, &buffer, buffer_end, "tree ") < 0)
goto bad_buffer; goto bad_buffer;
...@@ -186,13 +198,10 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) ...@@ -186,13 +198,10 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
*/ */
while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) { while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
git_oid *new_id = git__malloc(sizeof(git_oid)); git_oid *new_id = git_array_alloc(commit->parent_ids);
GITERR_CHECK_ALLOC(new_id); GITERR_CHECK_ALLOC(new_id);
git_oid_cpy(new_id, &parent_id); git_oid_cpy(new_id, &parent_id);
if (git_vector_insert(&commit->parent_ids, new_id) < 0)
return -1;
} }
commit->author = git__malloc(sizeof(git_signature)); commit->author = git__malloc(sizeof(git_signature));
...@@ -208,8 +217,8 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) ...@@ -208,8 +217,8 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0) if (git_signature__parse(commit->committer, &buffer, buffer_end, "committer ", '\n') < 0)
return -1; return -1;
/* Parse add'l header entries until blank line found */ /* Parse add'l header entries */
while (buffer < buffer_end && *buffer != '\n') { while (buffer < buffer_end) {
const char *eoln = buffer; const char *eoln = buffer;
while (eoln < buffer_end && *eoln != '\n') while (eoln < buffer_end && *eoln != '\n')
++eoln; ++eoln;
...@@ -223,15 +232,18 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj) ...@@ -223,15 +232,18 @@ int git_commit__parse(void *_commit, git_odb_object *odb_obj)
if (eoln < buffer_end && *eoln == '\n') if (eoln < buffer_end && *eoln == '\n')
++eoln; ++eoln;
buffer = eoln; buffer = eoln;
} }
/* buffer is now at the end of the header, double-check and move forward into the message */ /* point "buffer" to data after header */
if (buffer < buffer_end && *buffer == '\n') buffer = git_odb_object_data(odb_obj);
buffer++; buffer_end = buffer + git_odb_object_size(odb_obj);
buffer += header_len;
if (*buffer == '\n')
++buffer;
/* parse commit message */ /* extract commit message */
if (buffer <= buffer_end) { if (buffer <= buffer_end) {
commit->message = git__strndup(buffer, buffer_end - buffer); commit->message = git__strndup(buffer, buffer_end - buffer);
GITERR_CHECK_ALLOC(commit->message); GITERR_CHECK_ALLOC(commit->message);
...@@ -255,9 +267,10 @@ GIT_COMMIT_GETTER(const git_signature *, author, commit->author) ...@@ -255,9 +267,10 @@ GIT_COMMIT_GETTER(const git_signature *, author, commit->author)
GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer) GIT_COMMIT_GETTER(const git_signature *, committer, commit->committer)
GIT_COMMIT_GETTER(const char *, message, commit->message) GIT_COMMIT_GETTER(const char *, message, commit->message)
GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding) GIT_COMMIT_GETTER(const char *, message_encoding, commit->message_encoding)
GIT_COMMIT_GETTER(const char *, raw_header, commit->raw_header)
GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time)
GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset)
GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)commit->parent_ids.length) GIT_COMMIT_GETTER(unsigned int, parentcount, (unsigned int)git_array_size(commit->parent_ids))
GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id); GIT_COMMIT_GETTER(const git_oid *, tree_id, &commit->tree_id);
int git_commit_tree(git_tree **tree_out, const git_commit *commit) int git_commit_tree(git_tree **tree_out, const git_commit *commit)
...@@ -271,7 +284,7 @@ const git_oid *git_commit_parent_id( ...@@ -271,7 +284,7 @@ const git_oid *git_commit_parent_id(
{ {
assert(commit); assert(commit);
return git_vector_get(&commit->parent_ids, n); return git_array_get(commit->parent_ids, n);
} }
int git_commit_parent( int git_commit_parent(
......
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
#include "git2/commit.h" #include "git2/commit.h"
#include "tree.h" #include "tree.h"
#include "repository.h" #include "repository.h"
#include "vector.h" #include "array.h"
#include <time.h> #include <time.h>
struct git_commit { struct git_commit {
git_object object; git_object object;
git_vector parent_ids; git_array_t(git_oid) parent_ids;
git_oid tree_id; git_oid tree_id;
git_signature *author; git_signature *author;
...@@ -25,6 +25,7 @@ struct git_commit { ...@@ -25,6 +25,7 @@ struct git_commit {
char *message_encoding; char *message_encoding;
char *message; char *message;
char *raw_header;
}; };
void git_commit__free(void *commit); void git_commit__free(void *commit);
......
...@@ -36,7 +36,7 @@ git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_ ...@@ -36,7 +36,7 @@ git_commit_list *git_commit_list_insert_by_date(git_commit_list_node *item, git_
git_commit_list *p; git_commit_list *p;
while ((p = *pp) != NULL) { while ((p = *pp) != NULL) {
if (git_commit_list_time_cmp(p->item, item) < 0) if (git_commit_list_time_cmp(p->item, item) > 0)
break; break;
pp = &p->next; pp = &p->next;
......
...@@ -315,30 +315,241 @@ int git_config_refresh(git_config *cfg) ...@@ -315,30 +315,241 @@ int git_config_refresh(git_config *cfg)
* Loop over all the variables * Loop over all the variables
*/ */
typedef struct {
git_config_iterator parent;
git_config_iterator *current;
const git_config *cfg;
regex_t regex;
int has_regex;
size_t i;
} all_iter;
static int find_next_backend(size_t *out, const git_config *cfg, size_t i)
{
file_internal *internal;
for (; i > 0; --i) {
internal = git_vector_get(&cfg->files, i - 1);
if (!internal || !internal->file)
continue;
*out = i;
return 0;
}
return -1;
}
static int all_iter_next(git_config_entry **entry, git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
file_internal *internal;
git_config_backend *backend;
size_t i;
int error = 0;
if (iter->current != NULL &&
(error = iter->current->next(entry, iter->current)) == 0) {
return 0;
}
if (error < 0 && error != GIT_ITEROVER)
return error;
do {
if (find_next_backend(&i, iter->cfg, iter->i) < 0)
return GIT_ITEROVER;
internal = git_vector_get(&iter->cfg->files, i - 1);
backend = internal->file;
iter->i = i - 1;
if (iter->current)
iter->current->free(iter->current);
iter->current = NULL;
error = backend->iterator(&iter->current, backend);
if (error == GIT_ENOTFOUND)
continue;
if (error < 0)
return error;
error = iter->current->next(entry, iter->current);
/* If this backend is empty, then keep going */
if (error == GIT_ITEROVER)
continue;
return error;
} while(1);
return GIT_ITEROVER;
}
static int all_iter_glob_next(git_config_entry **entry, git_config_iterator *_iter)
{
int error;
all_iter *iter = (all_iter *) _iter;
/*
* We use the "normal" function to grab the next one across
* backends and then apply the regex
*/
while ((error = all_iter_next(entry, _iter)) == 0) {
/* skip non-matching keys if regexp was provided */
if (regexec(&iter->regex, (*entry)->name, 0, NULL, 0) != 0)
continue;
/* and simply return if we like the entry's name */
return 0;
}
return error;
}
static void all_iter_free(git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
if (iter->current)
iter->current->free(iter->current);
git__free(iter);
}
static void all_iter_glob_free(git_config_iterator *_iter)
{
all_iter *iter = (all_iter *) _iter;
regfree(&iter->regex);
all_iter_free(_iter);
}
int git_config_iterator_new(git_config_iterator **out, const git_config *cfg)
{
all_iter *iter;
iter = git__calloc(1, sizeof(all_iter));
GITERR_CHECK_ALLOC(iter);
iter->parent.free = all_iter_free;
iter->parent.next = all_iter_next;
iter->i = cfg->files.length;
iter->cfg = cfg;
*out = (git_config_iterator *) iter;
return 0;
}
int git_config_iterator_glob_new(git_config_iterator **out, const git_config *cfg, const char *regexp)
{
all_iter *iter;
int result;
if (regexp == NULL)
return git_config_iterator_new(out, cfg);
iter = git__calloc(1, sizeof(all_iter));
GITERR_CHECK_ALLOC(iter);
if ((result = regcomp(&iter->regex, regexp, REG_EXTENDED)) < 0) {
giterr_set_regex(&iter->regex, result);
regfree(&iter->regex);
return -1;
}
iter->parent.next = all_iter_glob_next;
iter->parent.free = all_iter_glob_free;
iter->i = cfg->files.length;
iter->cfg = cfg;
*out = (git_config_iterator *) iter;
return 0;
}
int git_config_foreach( int git_config_foreach(
const git_config *cfg, git_config_foreach_cb cb, void *payload) const git_config *cfg, git_config_foreach_cb cb, void *payload)
{ {
return git_config_foreach_match(cfg, NULL, cb, payload); return git_config_foreach_match(cfg, NULL, cb, payload);
} }
int git_config_backend_foreach_match(
git_config_backend *backend,
const char *regexp,
int (*fn)(const git_config_entry *, void *),
void *data)
{
git_config_entry *entry;
git_config_iterator* iter;
regex_t regex;
int result = 0;
if (regexp != NULL) {
if ((result = regcomp(&regex, regexp, REG_EXTENDED)) < 0) {
giterr_set_regex(&regex, result);
regfree(&regex);
return -1;
}
}
if ((result = backend->iterator(&iter, backend)) < 0) {
iter = NULL;
return -1;
}
while(!(iter->next(&entry, iter) < 0)) {
/* skip non-matching keys if regexp was provided */
if (regexp && regexec(&regex, entry->name, 0, NULL, 0) != 0)
continue;
/* abort iterator on non-zero return value */
if (fn(entry, data)) {
giterr_clear();
result = GIT_EUSER;
goto cleanup;
}
}
cleanup:
if (regexp != NULL)
regfree(&regex);
iter->free(iter);
return result;
}
int git_config_foreach_match( int git_config_foreach_match(
const git_config *cfg, const git_config *cfg,
const char *regexp, const char *regexp,
git_config_foreach_cb cb, git_config_foreach_cb cb,
void *payload) void *payload)
{ {
int ret = 0; int error;
size_t i; git_config_iterator *iter;
file_internal *internal; git_config_entry *entry;
git_config_backend *file;
for (i = 0; i < cfg->files.length && ret == 0; ++i) { if ((error = git_config_iterator_glob_new(&iter, cfg, regexp)) < 0)
internal = git_vector_get(&cfg->files, i); return error;
file = internal->file;
ret = file->foreach(file, regexp, cb, payload); while ((error = git_config_next(&entry, iter)) == 0) {
if(cb(entry, payload)) {
giterr_clear();
error = GIT_EUSER;
break;
}
} }
return ret; git_config_iterator_free(iter);
if (error == GIT_ITEROVER)
error = 0;
return error;
} }
/************** /**************
...@@ -528,31 +739,114 @@ int git_config_get_entry(const git_config_entry **out, const git_config *cfg, co ...@@ -528,31 +739,114 @@ int git_config_get_entry(const git_config_entry **out, const git_config *cfg, co
return config_error_notfound(name); return config_error_notfound(name);
} }
int git_config_get_multivar( int git_config_get_multivar_foreach(
const git_config *cfg, const char *name, const char *regexp, const git_config *cfg, const char *name, const char *regexp,
git_config_foreach_cb cb, void *payload) git_config_foreach_cb cb, void *payload)
{ {
file_internal *internal; int err, found;
git_config_backend *file; git_config_iterator *iter;
int ret = GIT_ENOTFOUND; git_config_entry *entry;
size_t i;
if ((err = git_config_multivar_iterator_new(&iter, cfg, name, regexp)) < 0)
return err;
found = 0;
while ((err = iter->next(&entry, iter)) == 0) {
found = 1;
if(cb(entry, payload)) {
iter->free(iter);
return GIT_EUSER;
}
}
/* iter->free(iter);
* This loop runs the "wrong" way 'round because we need to if (err == GIT_ITEROVER)
* look at every value from the most general to most specific err = 0;
*/
for (i = cfg->files.length; i > 0; --i) { if (found == 0 && err == 0)
internal = git_vector_get(&cfg->files, i - 1); err = config_error_notfound(name);
if (!internal || !internal->file)
return err;
}
typedef struct {
git_config_iterator parent;
git_config_iterator *iter;
char *name;
regex_t regex;
int have_regex;
} multivar_iter;
static int multivar_iter_next(git_config_entry **entry, git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
int error = 0;
while ((error = iter->iter->next(entry, iter->iter)) == 0) {
if (git__strcmp(iter->name, (*entry)->name))
continue; continue;
file = internal->file;
ret = file->get_multivar(file, name, regexp, cb, payload); if (!iter->have_regex)
if (ret < 0 && ret != GIT_ENOTFOUND) return 0;
return ret;
if (regexec(&iter->regex, (*entry)->value, 0, NULL, 0) == 0)
return 0;
}
return error;
}
void multivar_iter_free(git_config_iterator *_iter)
{
multivar_iter *iter = (multivar_iter *) _iter;
iter->iter->free(iter->iter);
git__free(iter->name);
regfree(&iter->regex);
git__free(iter);
}
int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp)
{
multivar_iter *iter = NULL;
git_config_iterator *inner = NULL;
int error;
if ((error = git_config_iterator_new(&inner, cfg)) < 0)
return error;
iter = git__calloc(1, sizeof(multivar_iter));
GITERR_CHECK_ALLOC(iter);
if ((error = git_config__normalize_name(name, &iter->name)) < 0)
goto on_error;
if (regexp != NULL) {
error = regcomp(&iter->regex, regexp, REG_EXTENDED);
if (error < 0) {
giterr_set_regex(&iter->regex, error);
error = -1;
regfree(&iter->regex);
goto on_error;
}
iter->have_regex = 1;
} }
return (ret == GIT_ENOTFOUND) ? config_error_notfound(name) : 0; iter->iter = inner;
iter->parent.free = multivar_iter_free;
iter->parent.next = multivar_iter_next;
*out = (git_config_iterator *) iter;
return 0;
on_error:
inner->free(inner);
git__free(iter);
return error;
} }
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value) int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value)
...@@ -568,6 +862,16 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex ...@@ -568,6 +862,16 @@ int git_config_set_multivar(git_config *cfg, const char *name, const char *regex
return file->set_multivar(file, name, regexp, value); return file->set_multivar(file, name, regexp, value);
} }
int git_config_next(git_config_entry **entry, git_config_iterator *iter)
{
return iter->next(entry, iter);
}
void git_config_iterator_free(git_config_iterator *iter)
{
iter->free(iter);
}
static int git_config__find_file_to_path( static int git_config__find_file_to_path(
char *out, size_t outlen, int (*find)(git_buf *buf)) char *out, size_t outlen, int (*find)(git_buf *buf))
{ {
...@@ -811,6 +1115,41 @@ fail_parse: ...@@ -811,6 +1115,41 @@ fail_parse:
return -1; return -1;
} }
/* Take something the user gave us and make it nice for our hash function */
int git_config__normalize_name(const char *in, char **out)
{
char *name, *fdot, *ldot;
assert(in && out);
name = git__strdup(in);
GITERR_CHECK_ALLOC(name);
fdot = strchr(name, '.');
ldot = strrchr(name, '.');
if (fdot == NULL || fdot == name || ldot == NULL || !ldot[1])
goto invalid;
/* Validate and downcase up to first dot and after last dot */
if (git_config_file_normalize_section(name, fdot) < 0 ||
git_config_file_normalize_section(ldot + 1, NULL) < 0)
goto invalid;
/* If there is a middle range, make sure it doesn't have newlines */
while (fdot < ldot)
if (*fdot++ == '\n')
goto invalid;
*out = name;
return 0;
invalid:
git__free(name);
giterr_set(GITERR_CONFIG, "Invalid config item name '%s'", in);
return GIT_EINVALIDSPEC;
}
struct rename_data { struct rename_data {
git_config *config; git_config *config;
git_buf *name; git_buf *name;
......
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment