Commit 4b0a36e8 by Vicent Marti

Merge branch 'development'

parents 29d7242b 43cb8b32

Too many changes to show.

To preserve performance only 1000 of 1000+ files are displayed.

/tests-clar/clar.suite /tests/clar.suite
/tests-clar/clar.suite.rule /tests/clar.suite.rule
/tests-clar/.clarcache /tests/.clarcache
/apidocs /apidocs
/trash-*.exe /trash-*.exe
/libgit2.pc /libgit2.pc
......
...@@ -16,3 +16,6 @@ Xavier L. <xavier.l@afrosoft.tk> <xavier.l@afrosoft.tk> ...@@ -16,3 +16,6 @@ Xavier L. <xavier.l@afrosoft.tk> <xavier.l@afrosoft.tk>
Sascha Cunz <sascha@babbelbox.org> <Sascha@BabbelBox.org> Sascha Cunz <sascha@babbelbox.org> <Sascha@BabbelBox.org>
Authmillenon <authmillenon@googlemail.com> <martin@ucsmail.de> Authmillenon <authmillenon@googlemail.com> <martin@ucsmail.de>
Authmillenon <authmillenon@googlemail.com> <authmillenon@googlemail.com> Authmillenon <authmillenon@googlemail.com> <authmillenon@googlemail.com>
Edward Thomson <ethomson@microsoft.com> <ethomson@edwardthomson.com>
J. David Ibáñez <jdavid.ibp@gmail.com> <jdavid@itaapy.com>
Russell Belfer <rb@github.com> <arrbee@arrbee.com>
# 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:
......
...@@ -68,5 +68,6 @@ Sven Strickroth ...@@ -68,5 +68,6 @@ Sven Strickroth
Tim Branyen Tim Branyen
Tim Clem Tim Clem
Tim Harder Tim Harder
Torsten Bögershausen
Trent Mick Trent Mick
Vicent Marti Vicent Marti
...@@ -27,25 +27,44 @@ OPTION( BUILD_EXAMPLES "Build library usage example apps" OFF ) ...@@ -27,25 +27,44 @@ OPTION( BUILD_EXAMPLES "Build library usage example apps" OFF )
OPTION( TAGS "Generate tags" OFF ) OPTION( TAGS "Generate tags" OFF )
OPTION( PROFILE "Generate profiling information" OFF ) 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 )
OPTION( USE_ICONV "Link with and use iconv library" OFF )
OPTION( USE_SSH "Link with libssh to enable SSH support" ON )
IF(APPLE)
SET( USE_ICONV ON )
ENDIF()
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
OPTION( STATIC_CRT "Link the static CRT libraries" ON ) OPTION( STATIC_CRT "Link the static CRT libraries" ON )
# By default, libgit2 is built with WinHTTP. To use the built-in
# HTTP transport, invoke CMake with the "-DWINHTTP=OFF" argument.
OPTION( WINHTTP "Use Win32 WinHTTP routines" ON )
ENDIF() ENDIF()
# This variable will contain the libraries we need to put into
# libgit2.pc's Requires.private. That is, what we're linking to or
# what someone who's statically linking us needs to link to.
SET(LIBGIT2_PC_REQUIRES "")
# This will be set later if we use the system's http-parser library or
# use iconv (OSX) and will be written to the Libs.private field in the
# pc file.
SET(LIBGIT2_PC_LIBS "")
# Installation paths # Installation paths
# #
SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.") SET(BIN_INSTALL_DIR bin CACHE PATH "Where to install binaries to.")
...@@ -57,7 +76,18 @@ FUNCTION(TARGET_OS_LIBRARIES target) ...@@ -57,7 +76,18 @@ FUNCTION(TARGET_OS_LIBRARIES target)
TARGET_LINK_LIBRARIES(${target} ws2_32) TARGET_LINK_LIBRARIES(${target} ws2_32)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)") ELSEIF(CMAKE_SYSTEM_NAME MATCHES "(Solaris|SunOS)")
TARGET_LINK_LIBRARIES(${target} socket nsl) TARGET_LINK_LIBRARIES(${target} socket nsl)
ENDIF () SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lsocket -lnsl" PARENT_SCOPE)
ELSEIF(CMAKE_SYSTEM_NAME MATCHES "Linux")
TARGET_LINK_LIBRARIES(${target} rt)
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lrt" PARENT_SCOPE)
ENDIF()
IF(USE_ICONV)
TARGET_LINK_LIBRARIES(${target} iconv)
ADD_DEFINITIONS(-DGIT_USE_ICONV)
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -liconv" PARENT_SCOPE)
ENDIF()
IF(THREADSAFE) IF(THREADSAFE)
TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT}) TARGET_LINK_LIBRARIES(${target} ${CMAKE_THREAD_LIBS_INIT})
ENDIF() ENDIF()
...@@ -67,7 +97,7 @@ ENDFUNCTION() ...@@ -67,7 +97,7 @@ ENDFUNCTION()
# explorer does. This is esp. useful with the libgit2_clar project, were # explorer does. This is esp. useful with the libgit2_clar project, were
# usually 2 or more files share the same name. Sadly, this file grouping # usually 2 or more files share the same name. Sadly, this file grouping
# is a per-directory option in cmake and not per-target, resulting in # is a per-directory option in cmake and not per-target, resulting in
# empty virtual folders "tests-clar" for the git2.dll # empty virtual folders "tests" for the git2.dll
FUNCTION(MSVC_SPLIT_SOURCES target) FUNCTION(MSVC_SPLIT_SOURCES target)
IF(MSVC_IDE) IF(MSVC_IDE)
GET_TARGET_PROPERTY(sources ${target} SOURCES) GET_TARGET_PROPERTY(sources ${target} SOURCES)
...@@ -96,8 +126,10 @@ SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${ ...@@ -96,8 +126,10 @@ SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${
# Find required dependencies # Find required dependencies
INCLUDE_DIRECTORIES(src include) INCLUDE_DIRECTORIES(src include)
IF (WIN32 AND NOT MINGW) IF (WIN32 AND WINHTTP AND NOT MINGW)
ADD_DEFINITIONS(-DGIT_WINHTTP) ADD_DEFINITIONS(-DGIT_WINHTTP)
INCLUDE_DIRECTORIES(deps/http-parser)
FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
ELSE () ELSE ()
IF (NOT AMIGA) IF (NOT AMIGA)
FIND_PACKAGE(OpenSSL) FIND_PACKAGE(OpenSSL)
...@@ -107,10 +139,11 @@ ELSE () ...@@ -107,10 +139,11 @@ ELSE ()
IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2) IF (HTTP_PARSER_FOUND AND HTTP_PARSER_VERSION_MAJOR EQUAL 2)
INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${HTTP_PARSER_INCLUDE_DIRS})
LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES}) LINK_LIBRARIES(${HTTP_PARSER_LIBRARIES})
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lhttp_parser")
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()
...@@ -120,6 +153,7 @@ IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin") ...@@ -120,6 +153,7 @@ IF (WIN32 AND NOT MINGW AND NOT SHA1_TYPE STREQUAL "builtin")
FILE(GLOB SRC_SHA1 src/hash/hash_win32.c) FILE(GLOB SRC_SHA1 src/hash/hash_win32.c)
ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin") ELSEIF (OPENSSL_FOUND AND NOT SHA1_TYPE STREQUAL "builtin")
ADD_DEFINITIONS(-DOPENSSL_SHA1) ADD_DEFINITIONS(-DOPENSSL_SHA1)
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} openssl")
ELSE() ELSE()
FILE(GLOB SRC_SHA1 src/hash/hash_generic.c) FILE(GLOB SRC_SHA1 src/hash/hash_generic.c)
ENDIF() ENDIF()
...@@ -130,7 +164,7 @@ IF (ENABLE_TRACE STREQUAL "ON") ...@@ -130,7 +164,7 @@ 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()
...@@ -142,24 +176,31 @@ FIND_PACKAGE(ZLIB QUIET) ...@@ -142,24 +176,31 @@ FIND_PACKAGE(ZLIB QUIET)
IF (ZLIB_FOUND) IF (ZLIB_FOUND)
INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS})
LINK_LIBRARIES(${ZLIB_LIBRARIES}) LINK_LIBRARIES(${ZLIB_LIBRARIES})
IF(APPLE)
SET(LIBGIT2_PC_LIBS "${LIBGIT2_PC_LIBS} -lz")
ELSE()
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} zlib")
ENDIF()
# Fake the message CMake would have shown # Fake the message CMake would have shown
MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}") MESSAGE("-- Found zlib: ${ZLIB_LIBRARY}")
ELSE() 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 (USE_SSH AND NOT MINGW)
FIND_PACKAGE(LIBSSH2 QUIET) FIND_PACKAGE(LIBSSH2 QUIET)
ENDIF() ENDIF()
IF (LIBSSH2_FOUND) IF (LIBSSH2_FOUND)
ADD_DEFINITIONS(-DGIT_SSH) ADD_DEFINITIONS(-DGIT_SSH)
INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${LIBSSH2_INCLUDE_DIR})
SET(LIBGIT2_PC_REQUIRES "${LIBGIT2_PC_REQUIRES} libssh2")
SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES}) SET(SSH_LIBRARIES ${LIBSSH2_LIBRARIES})
ENDIF() ENDIF()
# Platform specific compilation flags # Platform specific compilation flags
IF (MSVC) IF (MSVC)
...@@ -285,19 +326,19 @@ ENDIF() ...@@ -285,19 +326,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)
...@@ -309,7 +350,7 @@ ELSE() ...@@ -309,7 +350,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)
...@@ -352,19 +393,19 @@ INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} ) ...@@ -352,19 +393,19 @@ INSTALL(FILES include/git2.h DESTINATION ${INCLUDE_INSTALL_DIR} )
IF (BUILD_CLAR) IF (BUILD_CLAR)
FIND_PACKAGE(PythonInterp REQUIRED) FIND_PACKAGE(PythonInterp REQUIRED)
SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar/resources/") SET(CLAR_FIXTURES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources/")
SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar") SET(CLAR_PATH "${CMAKE_CURRENT_SOURCE_DIR}/tests")
SET(CLAR_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests-clar/resources" CACHE PATH "Path to test resources.") SET(CLAR_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/tests/resources" CACHE PATH "Path to test resources.")
ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\") ADD_DEFINITIONS(-DCLAR_FIXTURE_PATH=\"${CLAR_FIXTURES}\")
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}
) )
...@@ -373,7 +414,7 @@ IF (BUILD_CLAR) ...@@ -373,7 +414,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})
...@@ -409,23 +450,5 @@ IF (TAGS) ...@@ -409,23 +450,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 ()
...@@ -3,6 +3,12 @@ ...@@ -3,6 +3,12 @@
We're making it easy to do interesting things with git, and we'd love to have We're making it easy to do interesting things with git, and we'd love to have
your help. your help.
## Licensing
By contributing to libgit2, you agree to release your contribution under the terms of the license.
For code under `examples`, this is governed by the [CC0 Public Domain Dedication](examples/COPYING).
All other code is released under the [GPL v2 with linking exception](COPYING).
## Discussion & Chat ## Discussion & Chat
We hang out in the #libgit2 channel on irc.freenode.net. We hang out in the #libgit2 channel on irc.freenode.net.
...@@ -48,6 +54,12 @@ Please include a nice description of your changes with your PR; if we have ...@@ -48,6 +54,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 +69,17 @@ The most common case is porting code from core Git. Git is a pure GPL ...@@ -57,14 +69,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)
CFLAGS= -g $(DEFINES) -Wall -Wextra -O2 $(EXTRA_CFLAGS) CFLAGS= -g $(DEFINES) -Wall -Wextra -Wno-missing-field-initializers -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
......
libgit2 - the Git linkable library libgit2 - the Git linkable library
====================== ==================================
[![Build Status](https://secure.travis-ci.org/libgit2/libgit2.png?branch=development)](http://travis-ci.org/libgit2/libgit2) [![Build Status](https://secure.travis-ci.org/libgit2/libgit2.png?branch=development)](http://travis-ci.org/libgit2/libgit2)
libgit2 is a portable, pure C implementation of the Git core methods provided as a `libgit2` is a portable, pure C implementation of the Git core methods provided as a
re-entrant linkable library with a solid API, allowing you to write native re-entrant linkable library with a solid API, allowing you to write native
speed custom Git applications in any language with bindings. speed custom Git applications in any language with bindings.
libgit2 is licensed under a **very permissive license** (GPLv2 with a special Linking Exception). `libgit2` is licensed under a **very permissive license** (GPLv2 with a special
This basically means that you can link it (unmodified) with any kind of software without having to Linking Exception). This basically means that you can link it (unmodified)
release its source code. with any kind of software without having to release its source code.
Additionally, the example code has been released to the public domain (see the
* Mailing list: ~~<libgit2@librelist.org>~~ [separate license](examples/COPYING) for more information).
The libgit2 mailing list has
traditionally been hosted in Librelist, but Librelist is and has always * Website: [libgit2.github.com](http://libgit2.github.com)
been a shitshow. We encourage you to [open an issue](https://github.com/libgit2/libgit2/issues) * StackOverflow Tag: [libgit2](http://stackoverflow.com/questions/tagged/libgit2)
on GitHub instead for any questions regarding the library. * Issues: [GitHub Issues](https://github.com/libgit2/libgit2/issues) (Right here!)
* Archives: <http://librelist.com/browser/libgit2/>
* Website: <http://libgit2.github.com>
* API documentation: <http://libgit2.github.com/libgit2> * API documentation: <http://libgit2.github.com/libgit2>
* IRC: #libgit2 on irc.freenode.net. * IRC: [#libgit2](irc://irc.freenode.net/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
...@@ -39,15 +45,26 @@ libgit2 is already very usable. ...@@ -39,15 +45,26 @@ libgit2 is already very usable.
* descriptive and detailed error messages * descriptive and detailed error messages
* ...and more (over 175 different API calls) * ...and more (over 175 different API calls)
Optional dependencies
=====================
While the library provides git functionality without the need for
dependencies, it can make use of a few libraries to add to it:
- pthreads (non-Windows) to enable threadsafe access as well as multi-threaded pack generation
- OpenSSL (non-Windows) to talk over HTTPS and provide the SHA-1 functions
- LibSSH2 to enable the ssh transport
- iconv (OSX) to handle the HFS+ path encoding peculiarities
Building libgit2 - Using CMake Building libgit2 - Using CMake
============================== ==============================
libgit2 builds cleanly on most platforms without any external dependencies. `libgit2` builds cleanly on most platforms without any external dependencies.
Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthreads` to be available; Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthreads` to be available;
they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
for threading. for threading.
The libgit2 library is built using CMake 2.6+ (<http://www.cmake.org>) on all platforms. The `libgit2` library is built using `CMake 2.6+` (<http://www.cmake.org>) on all platforms.
On most systems you can build the library using the following commands On most systems you can build the library using the following commands
...@@ -104,6 +121,28 @@ See [the wiki] ...@@ -104,6 +121,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.
Optionally, crosscompile and install OpenSSL inside of it. Then create CMake
toolchain file that configures paths to your crosscompiler (substitute `{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 +157,9 @@ Here are the bindings to libgit2 that are currently available: ...@@ -118,9 +157,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 +167,8 @@ Here are the bindings to libgit2 that are currently available: ...@@ -128,8 +167,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 superseded 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>
...@@ -161,9 +200,9 @@ Check the [contribution guidelines](CONTRIBUTING.md). ...@@ -161,9 +200,9 @@ Check the [contribution guidelines](CONTRIBUTING.md).
License License
================================== ==================================
libgit2 is under GPL2 **with linking exemption**. This means you `libgit2` is under GPL2 **with linking exemption**. This means you
can link to the library with any program, commercial, open source or can link to and use the library from any program, proprietary or open source; paid
other. However, you cannot modify libgit2 and distribute it without or gratis. However, you cannot modify libgit2 and distribute it without
supplying the source. supplying the source.
See the COPYING file for the full license text. See the COPYING file for the full license text.
...@@ -45,44 +45,48 @@ Internal Objects ...@@ -45,44 +45,48 @@ Internal Objects
* `git_diff_file_content` is an internal structure that represents the * `git_diff_file_content` is an internal structure that represents the
data on one side of an item to be diffed; it is an augmented data on one side of an item to be diffed; it is an augmented
`git_diff_file` with more flags and the actual file data. `git_diff_file` with more flags and the actual file data.
** it is created from a repository plus a) a git_diff_file, b) a git_blob,
* it is created from a repository plus a) a git_diff_file, b) a git_blob,
or c) raw data and size or c) raw data and size
** there are three main operations on git_diff_file_content: * there are three main operations on git_diff_file_content:
*** _initialization_ sets up the data structure and does what it can up to,
but not including loading and looking at the actual data * _initialization_ sets up the data structure and does what it can up to,
*** _loading_ loads the data, preprocesses it (i.e. applies filters) and but not including loading and looking at the actual data
potentially analyzes it (to decide if binary) * _loading_ loads the data, preprocesses it (i.e. applies filters) and
*** _free_ releases loaded data and frees any allocated memory potentially analyzes it (to decide if binary)
* _free_ releases loaded data and frees any allocated memory
* The internal structure of a `git_diff_patch` stores the actual diff * The internal structure of a `git_diff_patch` stores the actual diff
between a pair of `git_diff_file_content` items between a pair of `git_diff_file_content` items
** it may be "unset" if the items are not diffable
** "empty" if the items are the same * it may be "unset" if the items are not diffable
** otherwise it will consist of a set of hunks each of which covers some * "empty" if the items are the same
number of lines of context, additions and deletions * otherwise it will consist of a set of hunks each of which covers some
** a patch is created from two git_diff_file_content items number of lines of context, additions and deletions
** a patch is fully instantiated in three phases: * a patch is created from two git_diff_file_content items
*** initial creation and initialization * a patch is fully instantiated in three phases:
*** loading of data and preliminary data examination
*** diffing of data and optional storage of diffs * initial creation and initialization
** (TBD) if a patch is asked to store the diffs and the size of the diff * loading of data and preliminary data examination
is significantly smaller than the raw data of the two sides, then the * diffing of data and optional storage of diffs
patch may be flattened using a pool of string data * (TBD) if a patch is asked to store the diffs and the size of the diff
is significantly smaller than the raw data of the two sides, then the
patch may be flattened using a pool of string data
* `git_diff_output` is an internal structure that represents an output * `git_diff_output` is an internal structure that represents an output
target for a `git_diff_patch` target for a `git_diff_patch`
** It consists of file, hunk, and line callbacks, plus a payload * It consists of file, hunk, and line callbacks, plus a payload
** There is a standard flattened output that can be used for plain text output * There is a standard flattened output that can be used for plain text output
** Typically we use a `git_xdiff_output` which drives the callbacks via the * Typically we use a `git_xdiff_output` which drives the callbacks via the
xdiff code taken from core Git. xdiff code taken from core Git.
* `git_diff_driver` is an internal structure that encapsulates the logic * `git_diff_driver` is an internal structure that encapsulates the logic
for a given type of file for a given type of file
** a driver is looked up based on the name and mode of a file. * a driver is looked up based on the name and mode of a file.
** the driver can then be used to: * the driver can then be used to:
*** determine if a file is binary (by attributes, by git_diff_options * determine if a file is binary (by attributes, by git_diff_options
settings, or by examining the content) settings, or by examining the content)
*** give you a function pointer that is used to evaluate function context * give you a function pointer that is used to evaluate function context
for hunk headers for hunk headers
** At some point, the logic for getting a filtered version of file content * At some point, the logic for getting a filtered version of file content
or calculating the OID of a file may be moved into the driver. or calculating the OID of a file may be moved into the driver.
...@@ -2,4 +2,10 @@ general ...@@ -2,4 +2,10 @@ general
showindex showindex
diff diff
rev-list rev-list
blame
cat-file
init
log
rev-parse
status
*.dSYM *.dSYM
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})
IF(NOT ${app_name} STREQUAL "common")
ADD_EXECUTABLE(${app_name} ${src_app} "common.c")
TARGET_LINK_LIBRARIES(${app_name} git2)
ENDIF()
ENDFOREACH()
Creative Commons Legal Code
CC0 1.0 Universal
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED
HEREUNDER.
Statement of Purpose
The laws of most jurisdictions throughout the world automatically confer
exclusive Copyright and Related Rights (defined below) upon the creator
and subsequent owner(s) (each and all, an "owner") of an original work of
authorship and/or a database (each, a "Work").
Certain owners wish to permanently relinquish those rights to a Work for
the purpose of contributing to a commons of creative, cultural and
scientific works ("Commons") that the public can reliably and without fear
of later claims of infringement build upon, modify, incorporate in other
works, reuse and redistribute as freely as possible in any form whatsoever
and for any purposes, including without limitation commercial purposes.
These owners may contribute to the Commons to promote the ideal of a free
culture and the further production of creative, cultural and scientific
works, or to gain reputation or greater distribution for their Work in
part through the use and efforts of others.
For these and/or other purposes and motivations, and without any
expectation of additional consideration or compensation, the person
associating CC0 with a Work (the "Affirmer"), to the extent that he or she
is an owner of Copyright and Related Rights in the Work, voluntarily
elects to apply CC0 to the Work and publicly distribute the Work under its
terms, with knowledge of his or her Copyright and Related Rights in the
Work and the meaning and intended legal effect of CC0 on those rights.
1. Copyright and Related Rights. A Work made available under CC0 may be
protected by copyright and related or neighboring rights ("Copyright and
Related Rights"). Copyright and Related Rights include, but are not
limited to, the following:
i. the right to reproduce, adapt, distribute, perform, display,
communicate, and translate a Work;
ii. moral rights retained by the original author(s) and/or performer(s);
iii. publicity and privacy rights pertaining to a person's image or
likeness depicted in a Work;
iv. rights protecting against unfair competition in regards to a Work,
subject to the limitations in paragraph 4(a), below;
v. rights protecting the extraction, dissemination, use and reuse of data
in a Work;
vi. database rights (such as those arising under Directive 96/9/EC of the
European Parliament and of the Council of 11 March 1996 on the legal
protection of databases, and under any national implementation
thereof, including any amended or successor version of such
directive); and
vii. other similar, equivalent or corresponding rights throughout the
world based on applicable law or treaty, and any national
implementations thereof.
2. Waiver. To the greatest extent permitted by, but not in contravention
of, applicable law, Affirmer hereby overtly, fully, permanently,
irrevocably and unconditionally waives, abandons, and surrenders all of
Affirmer's Copyright and Related Rights and associated claims and causes
of action, whether now known or unknown (including existing as well as
future claims and causes of action), in the Work (i) in all territories
worldwide, (ii) for the maximum duration provided by applicable law or
treaty (including future time extensions), (iii) in any current or future
medium and for any number of copies, and (iv) for any purpose whatsoever,
including without limitation commercial, advertising or promotional
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each
member of the public at large and to the detriment of Affirmer's heirs and
successors, fully intending that such Waiver shall not be subject to
revocation, rescission, cancellation, termination, or any other legal or
equitable action to disrupt the quiet enjoyment of the Work by the public
as contemplated by Affirmer's express Statement of Purpose.
3. Public License Fallback. Should any part of the Waiver for any reason
be judged legally invalid or ineffective under applicable law, then the
Waiver shall be preserved to the maximum extent permitted taking into
account Affirmer's express Statement of Purpose. In addition, to the
extent the Waiver is so judged Affirmer hereby grants to each affected
person a royalty-free, non transferable, non sublicensable, non exclusive,
irrevocable and unconditional license to exercise Affirmer's Copyright and
Related Rights in the Work (i) in all territories worldwide, (ii) for the
maximum duration provided by applicable law or treaty (including future
time extensions), (iii) in any current or future medium and for any number
of copies, and (iv) for any purpose whatsoever, including without
limitation commercial, advertising or promotional purposes (the
"License"). The License shall be deemed effective as of the date CC0 was
applied by Affirmer to the Work. Should any part of the License for any
reason be judged legally invalid or ineffective under applicable law, such
partial invalidity or ineffectiveness shall not invalidate the remainder
of the License, and in such case Affirmer hereby affirms that he or she
will not (i) exercise any of his or her remaining Copyright and Related
Rights in the Work or (ii) assert any associated claims and causes of
action with respect to the Work, in either case contrary to Affirmer's
express Statement of Purpose.
4. Limitations and Disclaimers.
a. No trademark or patent rights held by Affirmer are waived, abandoned,
surrendered, licensed or otherwise affected by this document.
b. Affirmer offers the Work as-is and makes no representations or
warranties of any kind concerning the Work, express, implied,
statutory or otherwise, including without limitation warranties of
title, merchantability, fitness for a particular purpose, non
infringement, or the absence of latent or other defects, accuracy, or
the present or absence of errors, whether or not discoverable, all to
the greatest extent permissible under applicable law.
c. Affirmer disclaims responsibility for clearing rights of other persons
that may apply to the Work or any use thereof, including without
limitation any person's Copyright and Related Rights in the Work.
Further, Affirmer disclaims responsibility for obtaining any necessary
consents, permissions or other rights required for any use of the
Work.
d. Affirmer understands and acknowledges that Creative Commons is not a
party to this document and has no duty or obligation with respect to
this CC0 or use of the Work.
...@@ -3,12 +3,12 @@ ...@@ -3,12 +3,12 @@
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 status APPS = general showindex diff rev-list cat-file status log rev-parse init blame
all: $(APPS) all: $(APPS)
% : %.c % : %.c
$(CC) -o $@ $(CFLAGS) $< $(LFLAGS) $(CC) -o $@ common.c $(CFLAGS) $< $(LFLAGS)
clean: clean:
$(RM) $(APPS) $(RM) $(APPS)
......
libgit2 examples libgit2 examples
================ ================
These examples are meant as thin, easy-to-read snippets for Docurium These examples are a mixture of basic emulation of core Git command line
(https://github.com/github/docurium) rather than full-blown functions and simple snippets demonstrating libgit2 API usage (for use
implementations of Git commands. They are not vetted as carefully with Docurium). As a whole, they are not vetted carefully for bugs, error
for bugs, error handling, or cross-platform compatibility as the handling, and cross-platform compatibility in the same manner as the rest
rest of the code in libgit2, so copy with some caution. of the code in libgit2, so copy with caution.
For HTML versions, check "Examples" at http://libgit2.github.com/libgit2 That being said, you are welcome to copy code from these examples as
desired when using libgit2. They have been [released to the public domain][cc0],
so there are no restrictions on their use.
[cc0]: COPYING
For annotated HTML versions, see the "Examples" section of:
http://libgit2.github.com/libgit2
such as:
http://libgit2.github.com/libgit2/ex/HEAD/general.html
/*
* libgit2 "add" example - shows how to modify the index
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
#include <assert.h>
enum print_options {
SKIP = 1,
VERBOSE = 2,
UPDATE = 4,
};
struct print_payload {
enum print_options options;
git_repository *repo;
};
/* Forward declarations for helpers */
static void parse_opts(int *options, int *count, int argc, char *argv[]);
void init_array(git_strarray *array, int argc, char **argv);
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload);
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 options = 0, count = 0;
struct print_payload payload = {0};
git_threads_init();
parse_opts(&options, &count, argc, argv);
init_array(&array, argc-count, argv+count);
check_lg2(git_repository_open(&repo, "."), "No git repository", NULL);
check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
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;
}
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 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;
}
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");
exit(1);
}
static void parse_opts(int *options, int *count, int argc, char *argv[])
{
int i;
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();
}
}
if (argc<=i)
print_usage();
*count = i;
}
/*
* libgit2 "blame" example - shows how to use the blame API
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
/**
* This example demonstrates how to invoke the libgit2 blame API to roughly
* simulate the output of `git blame` and a few of its command line arguments.
*/
struct opts {
char *path;
char *commitspec;
int C;
int M;
int start_line;
int end_line;
};
static void parse_opts(struct opts *o, int argc, char *argv[]);
int main(int argc, char *argv[])
{
int i, line, break_on_null_hunk;
char spec[1024] = {0};
struct opts o = {0};
const char *rawdata;
git_repository *repo = NULL;
git_revspec revspec = {0};
git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT;
git_blame *blame = NULL;
git_blob *blob;
git_object *obj;
git_threads_init();
parse_opts(&o, argc, argv);
if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
/** Open the repository. */
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "Couldn't open repository", NULL);
/**
* The commit range comes in "commitish" form. Use the rev-parse API to
* nail down the end points.
*/
if (o.commitspec) {
check_lg2(git_revparse(&revspec, repo, o.commitspec), "Couldn't parse commit spec", NULL);
if (revspec.flags & GIT_REVPARSE_SINGLE) {
git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.from));
git_object_free(revspec.from);
} else {
git_oid_cpy(&blameopts.oldest_commit, git_object_id(revspec.from));
git_oid_cpy(&blameopts.newest_commit, git_object_id(revspec.to));
git_object_free(revspec.from);
git_object_free(revspec.to);
}
}
/** Run the blame. */
check_lg2(git_blame_file(&blame, repo, o.path, &blameopts), "Blame error", NULL);
/**
* Get the raw data inside the blob for output. We use the
* `commitish:path/to/file.txt` format to find it.
*/
if (git_oid_iszero(&blameopts.newest_commit))
strcpy(spec, "HEAD");
else
git_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit);
strcat(spec, ":");
strcat(spec, o.path);
check_lg2(git_revparse_single(&obj, repo, spec), "Object lookup error", NULL);
check_lg2(git_blob_lookup(&blob, repo, git_object_id(obj)), "Blob lookup error", NULL);
git_object_free(obj);
rawdata = git_blob_rawcontent(blob);
/** Produce the output. */
line = 1;
i = 0;
break_on_null_hunk = 0;
while (i < git_blob_rawsize(blob)) {
const char *eol = strchr(rawdata+i, '\n');
char oid[10] = {0};
const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line);
if (break_on_null_hunk && !hunk) break;
if (hunk) {
break_on_null_hunk = 1;
char sig[128] = {0};
git_oid_tostr(oid, 10, &hunk->final_commit_id);
snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);
printf("%s ( %-30s %3d) %.*s\n",
oid,
sig,
line,
(int)(eol-rawdata-i),
rawdata+i);
}
i = (int)(eol - rawdata + 1);
line++;
}
/** Cleanup. */
git_blob_free(blob);
git_blame_free(blame);
git_repository_free(repo);
git_threads_shutdown();
return 0;
}
/** Tell the user how to make this thing work. */
static void usage(const char *msg, const char *arg)
{
if (msg && arg)
fprintf(stderr, "%s: %s\n", msg, arg);
else if (msg)
fprintf(stderr, "%s\n", msg);
fprintf(stderr, "usage: blame [options] [<commit range>] <path>\n");
fprintf(stderr, "\n");
fprintf(stderr, " <commit range> example: `HEAD~10..HEAD`, or `1234abcd`\n");
fprintf(stderr, " -L <n,m> process only line range n-m, counting from 1\n");
fprintf(stderr, " -M find line moves within and across files\n");
fprintf(stderr, " -C find line copies within and across files\n");
fprintf(stderr, "\n");
exit(1);
}
/** Parse the arguments. */
static void parse_opts(struct opts *o, int argc, char *argv[])
{
int i;
char *bare_args[3] = {0};
if (argc < 2) usage(NULL, NULL);
for (i=1; i<argc; i++) {
char *a = argv[i];
if (a[0] != '-') {
int i=0;
while (bare_args[i] && i < 3) ++i;
if (i >= 3)
usage("Invalid argument set", NULL);
bare_args[i] = a;
}
else if (!strcmp(a, "--"))
continue;
else if (!strcasecmp(a, "-M"))
o->M = 1;
else if (!strcasecmp(a, "-C"))
o->C = 1;
else if (!strcasecmp(a, "-L")) {
i++; a = argv[i];
if (i >= argc) fatal("Not enough arguments to -L", NULL);
check_lg2(sscanf(a, "%d,%d", &o->start_line, &o->end_line)-2, "-L format error", NULL);
}
else {
/* commit range */
if (o->commitspec) fatal("Only one commit spec allowed", NULL);
o->commitspec = a;
}
}
/* Handle the bare arguments */
if (!bare_args[0]) usage("Please specify a path", NULL);
o->path = bare_args[0];
if (bare_args[1]) {
/* <commitspec> <path> */
o->path = bare_args[1];
o->commitspec = bare_args[0];
}
if (bare_args[2]) {
/* <oldcommit> <newcommit> <path> */
char spec[128] = {0};
o->path = bare_args[2];
sprintf(spec, "%s..%s", bare_args[0], bare_args[1]);
o->commitspec = spec;
}
}
#include <stdio.h> /*
#include <git2.h> * libgit2 "cat-file" example - shows how to print data from the ODB
#include <stdlib.h> *
#include <string.h> * Written by the libgit2 contributors
*
static git_repository *g_repo; * To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
static void check(int error, const char *message) * worldwide. This software is distributed without any warranty.
{ *
if (error) { * You should have received a copy of the CC0 Public Domain Dedication along
fprintf(stderr, "%s (%d)\n", message, error); * with this software. If not, see
exit(1); * <http://creativecommons.org/publicdomain/zero/1.0/>.
} */
}
#include "common.h"
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: cat-file (-t | -s | -e | -p) [<options>] <object>\n");
exit(1);
}
static int check_str_param(
const char *arg, const char *pattern, const char **val)
{
size_t len = strlen(pattern);
if (strncmp(arg, pattern, len))
return 0;
*val = (const char *)(arg + len);
return 1;
}
static void print_signature(const char *header, const git_signature *sig) static void print_signature(const char *header, const git_signature *sig)
{ {
...@@ -57,12 +38,14 @@ static void print_signature(const char *header, const git_signature *sig) ...@@ -57,12 +38,14 @@ static void print_signature(const char *header, const git_signature *sig)
sign, hours, minutes); sign, hours, minutes);
} }
/** Printing out a blob is simple, get the contents and print */
static void show_blob(const git_blob *blob) static void show_blob(const git_blob *blob)
{ {
/* ? Does this need crlf filtering? */ /* ? Does this need crlf filtering? */
fwrite(git_blob_rawcontent(blob), git_blob_rawsize(blob), 1, stdout); fwrite(git_blob_rawcontent(blob), git_blob_rawsize(blob), 1, stdout);
} }
/** Show each entry with its type, id and attributes */
static void show_tree(const git_tree *tree) static void show_tree(const git_tree *tree)
{ {
size_t i, max_i = (int)git_tree_entrycount(tree); size_t i, max_i = (int)git_tree_entrycount(tree);
...@@ -81,6 +64,9 @@ static void show_tree(const git_tree *tree) ...@@ -81,6 +64,9 @@ static void show_tree(const git_tree *tree)
} }
} }
/**
* Commits and tags have a few interesting fields in their header.
*/
static void show_commit(const git_commit *commit) static void show_commit(const git_commit *commit)
{ {
unsigned int i, max_i; unsigned int i, max_i;
...@@ -123,53 +109,34 @@ enum { ...@@ -123,53 +109,34 @@ enum {
SHOW_PRETTY = 4 SHOW_PRETTY = 4
}; };
/* Forward declarations for option-parsing helper */
struct opts {
const char *dir;
const char *rev;
int action;
int verbose;
};
static void parse_opts(struct opts *o, int argc, char *argv[]);
/** Entry point for this command */
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
const char *dir = ".", *rev = NULL; git_repository *repo;
int i, action = 0, verbose = 0; struct opts o = { ".", NULL, 0, 0 };
git_object *obj = NULL; git_object *obj = NULL;
char oidstr[GIT_OID_HEXSZ + 1]; char oidstr[GIT_OID_HEXSZ + 1];
git_threads_init(); git_threads_init();
for (i = 1; i < argc; ++i) { parse_opts(&o, argc, argv);
char *a = argv[i];
if (a[0] != '-') { check_lg2(git_repository_open_ext(&repo, o.dir, 0, NULL),
if (rev != NULL) "Could not open repository", NULL);
usage("Only one rev should be provided", NULL); check_lg2(git_revparse_single(&obj, repo, o.rev),
else "Could not resolve", o.rev);
rev = a;
}
else if (!strcmp(a, "-t"))
action = SHOW_TYPE;
else if (!strcmp(a, "-s"))
action = SHOW_SIZE;
else if (!strcmp(a, "-e"))
action = SHOW_NONE;
else if (!strcmp(a, "-p"))
action = SHOW_PRETTY;
else if (!strcmp(a, "-q"))
verbose = 0;
else if (!strcmp(a, "-v"))
verbose = 1;
else if (!strcmp(a, "--help") || !strcmp(a, "-h"))
usage(NULL, NULL);
else if (!check_str_param(a, "--git-dir=", &dir))
usage("Unknown option", a);
}
if (!action || !rev) if (o.verbose) {
usage(NULL, NULL);
check(git_repository_open_ext(&g_repo, dir, 0, NULL),
"Could not open repository");
if (git_revparse_single(&obj, g_repo, rev) < 0) {
fprintf(stderr, "Could not resolve '%s'\n", rev);
exit(1);
}
if (verbose) {
char oidstr[GIT_OID_HEXSZ + 1]; char oidstr[GIT_OID_HEXSZ + 1];
git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj)); git_oid_tostr(oidstr, sizeof(oidstr), git_object_id(obj));
...@@ -177,7 +144,7 @@ int main(int argc, char *argv[]) ...@@ -177,7 +144,7 @@ int main(int argc, char *argv[])
git_object_type2string(git_object_type(obj)), oidstr); git_object_type2string(git_object_type(obj)), oidstr);
} }
switch (action) { switch (o.action) {
case SHOW_TYPE: case SHOW_TYPE:
printf("%s\n", git_object_type2string(git_object_type(obj))); printf("%s\n", git_object_type2string(git_object_type(obj)));
break; break;
...@@ -185,9 +152,9 @@ int main(int argc, char *argv[]) ...@@ -185,9 +152,9 @@ int main(int argc, char *argv[])
git_odb *odb; git_odb *odb;
git_odb_object *odbobj; git_odb_object *odbobj;
check(git_repository_odb(&odb, g_repo), "Could not open ODB"); check_lg2(git_repository_odb(&odb, repo), "Could not open ODB", NULL);
check(git_odb_read(&odbobj, odb, git_object_id(obj)), check_lg2(git_odb_read(&odbobj, odb, git_object_id(obj)),
"Could not find obj"); "Could not find obj", NULL);
printf("%ld\n", (long)git_odb_object_size(odbobj)); printf("%ld\n", (long)git_odb_object_size(odbobj));
...@@ -221,9 +188,59 @@ int main(int argc, char *argv[]) ...@@ -221,9 +188,59 @@ int main(int argc, char *argv[])
} }
git_object_free(obj); git_object_free(obj);
git_repository_free(g_repo); git_repository_free(repo);
git_threads_shutdown(); git_threads_shutdown();
return 0; return 0;
} }
/** Print out usage information */
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: cat-file (-t | -s | -e | -p) [-v] [-q] "
"[-h|--help] [--git-dir=<dir>] <object>\n");
exit(1);
}
/** Parse the command-line options taken from git */
static void parse_opts(struct opts *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
for (args.pos = 1; args.pos < argc; ++args.pos) {
char *a = argv[args.pos];
if (a[0] != '-') {
if (o->rev != NULL)
usage("Only one rev should be provided", NULL);
else
o->rev = a;
}
else if (!strcmp(a, "-t"))
o->action = SHOW_TYPE;
else if (!strcmp(a, "-s"))
o->action = SHOW_SIZE;
else if (!strcmp(a, "-e"))
o->action = SHOW_NONE;
else if (!strcmp(a, "-p"))
o->action = SHOW_PRETTY;
else if (!strcmp(a, "-q"))
o->verbose = 0;
else if (!strcmp(a, "-v"))
o->verbose = 1;
else if (!strcmp(a, "--help") || !strcmp(a, "-h"))
usage(NULL, NULL);
else if (!match_str_arg(&o->dir, &args, "--git-dir"))
usage("Unknown option", a);
}
if (!o->action || !o->rev)
usage(NULL, NULL);
}
/*
* Utilities library for libgit2 examples
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
void check_lg2(int error, const char *message, const char *extra)
{
const git_error *lg2err;
const char *lg2msg = "", *lg2spacer = "";
if (!error)
return;
if ((lg2err = giterr_last()) != NULL && lg2err->message != NULL) {
lg2msg = lg2err->message;
lg2spacer = " - ";
}
if (extra)
fprintf(stderr, "%s '%s' [%d]%s%s\n",
message, extra, error, lg2spacer, lg2msg);
else
fprintf(stderr, "%s [%d]%s%s\n",
message, error, lg2spacer, lg2msg);
exit(1);
}
void fatal(const char *message, const char *extra)
{
if (extra)
fprintf(stderr, "%s %s\n", message, extra);
else
fprintf(stderr, "%s\n", message);
exit(1);
}
size_t is_prefixed(const char *str, const char *pfx)
{
size_t len = strlen(pfx);
return strncmp(str, pfx, len) ? 0 : len;
}
int match_str_arg(
const char **out, struct args_info *args, const char *opt)
{
const char *found = args->argv[args->pos];
size_t len = is_prefixed(found, opt);
if (!len)
return 0;
if (!found[len]) {
if (args->pos + 1 == args->argc)
fatal("expected value following argument", opt);
args->pos += 1;
*out = args->argv[args->pos];
return 1;
}
if (found[len] == '=') {
*out = found + len + 1;
return 1;
}
return 0;
}
static const char *match_numeric_arg(struct args_info *args, const char *opt)
{
const char *found = args->argv[args->pos];
size_t len = is_prefixed(found, opt);
if (!len)
return NULL;
if (!found[len]) {
if (args->pos + 1 == args->argc)
fatal("expected numeric value following argument", opt);
args->pos += 1;
found = args->argv[args->pos];
} else {
found = found + len;
if (*found == '=')
found++;
}
return found;
}
int match_uint16_arg(
uint16_t *out, struct args_info *args, const char *opt)
{
const char *found = match_numeric_arg(args, opt);
uint16_t val;
char *endptr = NULL;
if (!found)
return 0;
val = (uint16_t)strtoul(found, &endptr, 0);
if (!endptr || *endptr != '\0')
fatal("expected number after argument", opt);
if (out)
*out = val;
return 1;
}
static int match_int_internal(
int *out, const char *str, int allow_negative, const char *opt)
{
char *endptr = NULL;
int val = (int)strtol(str, &endptr, 10);
if (!endptr || *endptr != '\0')
fatal("expected number", opt);
else if (val < 0 && !allow_negative)
fatal("negative values are not allowed", opt);
if (out)
*out = val;
return 1;
}
int is_integer(int *out, const char *str, int allow_negative)
{
return match_int_internal(out, str, allow_negative, NULL);
}
int match_int_arg(
int *out, struct args_info *args, const char *opt, int allow_negative)
{
const char *found = match_numeric_arg(args, opt);
if (!found)
return 0;
return match_int_internal(out, found, allow_negative, opt);
}
int diff_output(
const git_diff_delta *d,
const git_diff_hunk *h,
const git_diff_line *l,
void *p)
{
FILE *fp = p;
(void)d; (void)h;
if (!fp)
fp = stdout;
if (l->origin == GIT_DIFF_LINE_CONTEXT ||
l->origin == GIT_DIFF_LINE_ADDITION ||
l->origin == GIT_DIFF_LINE_DELETION)
fputc(l->origin, fp);
fwrite(l->content, 1, l->content_len, fp);
return 0;
}
void treeish_to_tree(
git_tree **out, git_repository *repo, const char *treeish)
{
git_object *obj = NULL;
check_lg2(
git_revparse_single(&obj, repo, treeish),
"looking up object", treeish);
check_lg2(
git_object_peel((git_object **)out, obj, GIT_OBJ_TREE),
"resolving object to tree", treeish);
git_object_free(obj);
}
/*
* Utilities library for libgit2 examples
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <git2.h>
/**
* Check libgit2 error code, printing error to stderr on failure and
* exiting the program.
*/
extern void check_lg2(int error, const char *message, const char *extra);
/**
* Exit the program, printing error to stderr
*/
extern void fatal(const char *message, const char *extra);
/**
* Check if a string has the given prefix. Returns 0 if not prefixed
* or the length of the prefix if it is.
*/
extern size_t is_prefixed(const char *str, const char *pfx);
/**
* Match an integer string, returning 1 if matched, 0 if not.
*/
extern int is_integer(int *out, const char *str, int allow_negative);
struct args_info {
int argc;
char **argv;
int pos;
};
#define ARGS_INFO_INIT { argc, argv, 0 }
/**
* Check current `args` entry against `opt` string. If it matches
* exactly, take the next arg as a string; if it matches as a prefix with
* an equal sign, take the remainder as a string; otherwise return 0.
*/
extern int match_str_arg(
const char **out, struct args_info *args, const char *opt);
/**
* Check current `args` entry against `opt` string parsing as uint16. If
* `opt` matches exactly, take the next arg as a uint16_t value; if `opt`
* is a prefix (equal sign optional), take the remainder of the arg as a
* uint16_t value; otherwise return 0.
*/
extern int match_uint16_arg(
uint16_t *out, struct args_info *args, const char *opt);
/**
* Check current `args` entry against `opt` string parsing as int. If
* `opt` matches exactly, take the next arg as an int value; if it matches
* as a prefix (equal sign optional), take the remainder of the arg as a
* int value; otherwise return 0.
*/
extern int match_int_arg(
int *out, struct args_info *args, const char *opt, int allow_negative);
/**
* Basic output function for plain text diff output
* Pass `FILE*` such as `stdout` or `stderr` as payload (or NULL == `stdout`)
*/
extern int diff_output(
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
/**
* Convert a treeish argument to an actual tree; this will call check_lg2
* and exit the program if `treeish` cannot be resolved to a tree
*/
extern void treeish_to_tree(
git_tree **out, git_repository *repo, const char *treeish);
/*
* libgit2 "general" example - shows basic libgit2 concepts
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
// [**libgit2**][lg] is a portable, pure C implementation of the Git core // [**libgit2**][lg] is a portable, pure C implementation of the Git core
// methods provided as a re-entrant linkable library with a solid API, // methods provided as a re-entrant linkable library with a solid API,
// allowing you to write native speed custom Git applications in any // allowing you to write native speed custom Git applications in any
...@@ -52,7 +66,7 @@ int main (int argc, char** argv) ...@@ -52,7 +66,7 @@ int main (int argc, char** argv)
// simplest. There are also [methods][me] for specifying the index file // simplest. There are also [methods][me] for specifying the index file
// and work tree locations, here we assume they are in the normal places. // and work tree locations, here we assume they are in the normal places.
// //
// (Try running this program against tests-clar/resources/testrepo.git.) // (Try running this program against tests/resources/testrepo.git.)
// //
// [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository // [me]: http://libgit2.github.com/libgit2/#HEAD/group/repository
int error; int error;
......
/*
* libgit2 "init" example - shows how to initialize a new repo
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
/**
* 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.
*/
/** Forward declarations of helpers */
struct opts {
int no_options;
int quiet;
int bare;
int initial_commit;
uint32_t shared;
const char *template;
const char *gitdir;
const char *dir;
};
static void create_initial_commit(git_repository *repo);
static void parse_opts(struct opts *o, int argc, char *argv[]);
int main(int argc, char *argv[])
{
git_repository *repo = NULL;
struct opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
git_threads_init();
parse_opts(&o, argc, argv);
/* Initialize repository. */
if (o.no_options) {
/**
* No options were specified, so let's demonstrate the default
* simple case of git_repository_init() API usage...
*/
check_lg2(git_repository_init(&repo, o.dir, 0),
"Could not initialize repository", NULL);
}
else {
/**
* Some command line options were specified, so we'll use the
* extended init API to handle them
*/
git_repository_init_options initopts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
initopts.flags = GIT_REPOSITORY_INIT_MKPATH;
if (o.bare)
initopts.flags |= GIT_REPOSITORY_INIT_BARE;
if (o.template) {
initopts.flags |= GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
initopts.template_path = o.template;
}
if (o.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)
*/
initopts.workdir_path = o.dir;
o.dir = o.gitdir;
}
if (o.shared != 0)
initopts.mode = o.shared;
check_lg2(git_repository_init_ext(&repo, o.dir, &initopts),
"Could not initialize repository", NULL);
}
/** Print a message to stdout like "git init" does. */
if (!o.quiet) {
if (o.bare || o.gitdir)
o.dir = git_repository_path(repo);
else
o.dir = git_repository_workdir(repo);
printf("Initialized empty Git repository in %s\n", o.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 (o.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)
fatal("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)
fatal("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)
fatal("Unable to write initial tree from index", NULL);
git_index_free(index);
if (git_tree_lookup(&tree, repo, &tree_id) < 0)
fatal("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)
fatal("Could not create the initial commit", NULL);
/** Clean up so we don't leak memory. */
git_tree_free(tree);
git_signature_free(sig);
}
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>]\n"
" [--shared[=perms]] [--initial-commit]\n"
" [--separate-git-dir] <directory>\n");
exit(1);
}
/** 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;
}
static void parse_opts(struct opts *o, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
const char *sharedarg;
/** Process arguments. */
for (args.pos = 1; args.pos < argc; ++args.pos) {
char *a = argv[args.pos];
if (a[0] == '-')
o->no_options = 0;
if (a[0] != '-') {
if (o->dir != NULL)
usage("extra argument", a);
o->dir = a;
}
else if (!strcmp(a, "-q") || !strcmp(a, "--quiet"))
o->quiet = 1;
else if (!strcmp(a, "--bare"))
o->bare = 1;
else if (!strcmp(a, "--shared"))
o->shared = GIT_REPOSITORY_INIT_SHARED_GROUP;
else if (!strcmp(a, "--initial-commit"))
o->initial_commit = 1;
else if (match_str_arg(&sharedarg, &args, "--shared"))
o->shared = parse_shared(sharedarg);
else if (!match_str_arg(&o->template, &args, "--template") ||
!match_str_arg(&o->gitdir, &args, "--separate-git-dir"))
usage("unknown option", a);
}
if (!o->dir)
usage("must specify directory to init", NULL);
}
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;
...@@ -38,13 +25,19 @@ static void print_progress(const progress_data *pd) ...@@ -38,13 +25,19 @@ static void print_progress(const progress_data *pd)
: 0.f; : 0.f;
int kbytes = pd->fetch_progress.received_bytes / 1024; int kbytes = pd->fetch_progress.received_bytes / 1024;
printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n", if (pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) {
printf("Resolving deltas %d/%d\r",
pd->fetch_progress.indexed_deltas,
pd->fetch_progress.total_deltas);
} else {
printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n",
network_percent, kbytes, network_percent, kbytes,
pd->fetch_progress.received_objects, pd->fetch_progress.total_objects, pd->fetch_progress.received_objects, pd->fetch_progress.total_objects,
index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects, index_percent, pd->fetch_progress.indexed_objects, pd->fetch_progress.total_objects,
checkout_percent, checkout_percent,
pd->completed_steps, pd->total_steps, pd->completed_steps, pd->total_steps,
pd->path); pd->path);
}
} }
static int fetch_progress(const git_transfer_progress *stats, void *payload) static int fetch_progress(const git_transfer_progress *stats, void *payload)
...@@ -63,24 +56,6 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa ...@@ -63,24 +56,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)
{ {
...@@ -105,9 +80,9 @@ int do_clone(git_repository *repo, int argc, char **argv) ...@@ -105,9 +80,9 @@ int do_clone(git_repository *repo, int argc, char **argv)
checkout_opts.progress_cb = checkout_progress; checkout_opts.progress_cb = checkout_progress;
checkout_opts.progress_payload = &pd; checkout_opts.progress_payload = &pd;
clone_opts.checkout_opts = checkout_opts; clone_opts.checkout_opts = checkout_opts;
clone_opts.fetch_progress_cb = &fetch_progress; clone_opts.remote_callbacks.transfer_progress = &fetch_progress;
clone_opts.fetch_progress_payload = &pd; clone_opts.remote_callbacks.credentials = cred_acquire_cb;
clone_opts.cred_acquire_cb = cred_acquire; clone_opts.remote_callbacks.payload = &pd;
// 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__)
......
...@@ -14,11 +14,12 @@ struct dl_data { ...@@ -14,11 +14,12 @@ struct dl_data {
int finished; int finished;
}; };
static void progress_cb(const char *str, int len, void *data) static int progress_cb(const char *str, int len, void *data)
{ {
(void)data; (void)data;
printf("remote: %.*s", len, str); printf("remote: %.*s", len, str);
fflush(stdout); /* We don't have the \n to force the flush */ fflush(stdout); /* We don't have the \n to force the flush */
return 0;
} }
static void *download(void *ptr) static void *download(void *ptr)
...@@ -35,7 +36,7 @@ static void *download(void *ptr) ...@@ -35,7 +36,7 @@ static void *download(void *ptr)
// Download the packfile and index it. This function updates the // Download the packfile and index it. This function updates the
// amount of received data and the indexer stats which lets you // amount of received data and the indexer stats which lets you
// inform the user about progress. // inform the user about progress.
if (git_remote_download(data->remote, NULL, NULL) < 0) { if (git_remote_download(data->remote) < 0) {
data->ret = -1; data->ret = -1;
goto exit; goto exit;
} }
...@@ -47,6 +48,11 @@ exit: ...@@ -47,6 +48,11 @@ exit:
return &data->ret; return &data->ret;
} }
/**
* This function gets called for each remote-tracking branch that gets
* updated. The message we output depends on whether it's a new one or
* an update.
*/
static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data) static int update_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
{ {
char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1]; char a_str[GIT_OID_HEXSZ+1], b_str[GIT_OID_HEXSZ+1];
...@@ -66,6 +72,7 @@ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, vo ...@@ -66,6 +72,7 @@ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, vo
return 0; return 0;
} }
/** Entry point for this command */
int fetch(git_repository *repo, int argc, char **argv) int fetch(git_repository *repo, int argc, char **argv)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
...@@ -91,6 +98,7 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -91,6 +98,7 @@ int fetch(git_repository *repo, int argc, char **argv)
// Set up the callbacks (only update_tips for now) // Set up the callbacks (only update_tips for now)
callbacks.update_tips = &update_cb; callbacks.update_tips = &update_cb;
callbacks.progress = &progress_cb; callbacks.progress = &progress_cb;
callbacks.credentials = cred_acquire_cb;
git_remote_set_callbacks(remote, &callbacks); git_remote_set_callbacks(remote, &callbacks);
// Set up the information for the background worker thread // Set up the information for the background worker thread
...@@ -112,10 +120,14 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -112,10 +120,14 @@ int fetch(git_repository *repo, int argc, char **argv)
do { do {
usleep(10000); usleep(10000);
if (stats->total_objects > 0) if (stats->received_objects == stats->total_objects) {
printf("Resolving deltas %d/%d\r",
stats->indexed_deltas, stats->total_deltas);
} else if (stats->total_objects > 0) {
printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r", printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r",
stats->received_objects, stats->total_objects, stats->received_objects, stats->total_objects,
stats->indexed_objects, stats->received_bytes); stats->indexed_objects, stats->received_bytes);
}
} while (!data.finished); } while (!data.finished);
if (data.ret < 0) if (data.ret < 0)
...@@ -124,8 +136,18 @@ int fetch(git_repository *repo, int argc, char **argv) ...@@ -124,8 +136,18 @@ int fetch(git_repository *repo, int argc, char **argv)
pthread_join(worker, NULL); pthread_join(worker, NULL);
#endif #endif
printf("\rReceived %d/%d objects in %zu bytes\n", /**
* If there are local objects (we got a thin pack), then tell
* the user how many objects we saved from having to cross the
* network.
*/
if (stats->local_objects > 0) {
printf("\rReceived %d/%d objects in %zu bytes (used %d local objects)\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
} else{
printf("\rReceived %d/%d objects in %zu bytes\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes); stats->indexed_objects, stats->total_objects, stats->received_bytes);
}
// Disconnect the underlying connection to prevent from idling. // Disconnect the underlying connection to prevent from idling.
git_remote_disconnect(remote); git_remote_disconnect(remote);
......
...@@ -31,7 +31,7 @@ static int index_cb(const git_transfer_progress *stats, void *data) ...@@ -31,7 +31,7 @@ static int index_cb(const git_transfer_progress *stats, void *data)
int index_pack(git_repository *repo, int argc, char **argv) int index_pack(git_repository *repo, int argc, char **argv)
{ {
git_indexer_stream *idx; git_indexer *idx;
git_transfer_progress stats = {0, 0}; git_transfer_progress stats = {0, 0};
int error; int error;
char hash[GIT_OID_HEXSZ + 1] = {0}; char hash[GIT_OID_HEXSZ + 1] = {0};
...@@ -46,7 +46,7 @@ int index_pack(git_repository *repo, int argc, char **argv) ...@@ -46,7 +46,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (git_indexer_stream_new(&idx, ".", NULL, NULL) < 0) { if (git_indexer_new(&idx, ".", 0, NULL, NULL, NULL) < 0) {
puts("bad idx"); puts("bad idx");
return -1; return -1;
} }
...@@ -61,7 +61,7 @@ int index_pack(git_repository *repo, int argc, char **argv) ...@@ -61,7 +61,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
if (read_bytes < 0) if (read_bytes < 0)
break; break;
if ((error = git_indexer_stream_add(idx, buf, read_bytes, &stats)) < 0) if ((error = git_indexer_append(idx, buf, read_bytes, &stats)) < 0)
goto cleanup; goto cleanup;
index_cb(&stats, NULL); index_cb(&stats, NULL);
...@@ -73,16 +73,16 @@ int index_pack(git_repository *repo, int argc, char **argv) ...@@ -73,16 +73,16 @@ int index_pack(git_repository *repo, int argc, char **argv)
goto cleanup; goto cleanup;
} }
if ((error = git_indexer_stream_finalize(idx, &stats)) < 0) if ((error = git_indexer_commit(idx, &stats)) < 0)
goto cleanup; goto cleanup;
printf("\rIndexing %d of %d\n", stats.indexed_objects, stats.total_objects); printf("\rIndexing %d of %d\n", stats.indexed_objects, stats.total_objects);
git_oid_fmt(hash, git_indexer_stream_hash(idx)); git_oid_fmt(hash, git_indexer_hash(idx));
puts(hash); puts(hash);
cleanup: cleanup:
close(fd); close(fd);
git_indexer_stream_free(idx); git_indexer_free(idx);
return error; return error;
} }
...@@ -4,65 +4,52 @@ ...@@ -4,65 +4,52 @@
#include <string.h> #include <string.h>
#include "common.h" #include "common.h"
static int show_ref__cb(git_remote_head *head, void *payload)
{
char oid[GIT_OID_HEXSZ + 1] = {0};
(void)payload;
git_oid_fmt(oid, &head->oid);
printf("%s\t%s\n", oid, head->name);
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;
int error; int error;
const git_remote_head **refs;
size_t refs_len, i;
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
// 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;
}
/**
* Connect to the remote and call the printing function for
* each of the remote references.
*/
callbacks.credentials = cred_acquire_cb;
git_remote_set_callbacks(remote, &callbacks);
error = git_remote_connect(remote, GIT_DIRECTION_FETCH); error = git_remote_connect(remote, GIT_DIRECTION_FETCH);
if (error < 0) if (error < 0)
goto cleanup; goto cleanup;
error = git_remote_ls(remote, &show_ref__cb, NULL); /**
* Get the list of references on the remote and print out
* their name next to what they point to.
*/
if (git_remote_ls(&refs, &refs_len, remote) < 0)
goto cleanup;
for (i = 0; i < refs_len; i++) {
char oid[GIT_OID_HEXSZ + 1] = {0};
git_oid_fmt(oid, &refs[i]->oid);
printf("%s\t%s\n", oid, refs[i]->name);
}
cleanup: cleanup:
git_remote_free(remote); git_remote_free(remote);
return error; return error;
} }
// This gets called to do the work. The remote can be given either as /** Entry point for this command */
// the name of a configured remote or an URL.
int ls_remote(git_repository *repo, int argc, char **argv) int ls_remote(git_repository *repo, int argc, char **argv)
{ {
int error; int error;
...@@ -72,12 +59,7 @@ int ls_remote(git_repository *repo, int argc, char **argv) ...@@ -72,12 +59,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 <string.h> * libgit2 "rev-list" example - shows how to transform a rev-spec into a list
* of commit ids
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts);
#include <git2.h> int main (int argc, char **argv)
static void check_error(int error_code, const char *action)
{ {
if (!error_code) git_repository *repo;
return; git_revwalk *walk;
git_oid oid;
char buf[41];
git_threads_init();
const git_error *error = giterr_last(); check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "opening repository", NULL);
fprintf(stderr, "Error %d %s: %s\n", -error_code, action, check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL);
(error && error->message) ? error->message : "???"); check_lg2(revwalk_parseopts(repo, walk, argc-1, argv+1), "parsing options", NULL);
exit(1);
while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid);
buf[40] = '\0';
printf("%s\n", buf);
}
git_threads_shutdown();
return 0;
} }
static int push_commit(git_revwalk *walk, const git_oid *oid, int hide) static int push_commit(git_revwalk *walk, const git_oid *oid, int hide)
...@@ -93,27 +119,3 @@ static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, ...@@ -93,27 +119,3 @@ static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts,
return 0; return 0;
} }
int main (int argc, char **argv)
{
int error;
git_repository *repo;
git_revwalk *walk;
git_oid oid;
char buf[41];
error = git_repository_open_ext(&repo, ".", 0, NULL);
check_error(error, "opening repository");
error = git_revwalk_new(&walk, repo);
check_error(error, "allocating revwalk");
error = revwalk_parseopts(repo, walk, argc-1, argv+1);
check_error(error, "parsing options");
while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid);
buf[40] = '\0';
printf("%s\n", buf);
}
return 0;
}
/*
* libgit2 "rev-parse" example - shows how to parse revspecs
*
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
/** Forward declarations for helpers. */
struct parse_state {
git_repository *repo;
const char *repodir;
const char *spec;
int not;
};
static void parse_opts(struct parse_state *ps, int argc, char *argv[]);
static int parse_revision(struct parse_state *ps);
int main(int argc, char *argv[])
{
struct parse_state ps = {0};
git_threads_init();
parse_opts(&ps, argc, argv);
check_lg2(parse_revision(&ps), "Parsing", NULL);
git_repository_free(ps.repo);
git_threads_shutdown();
return 0;
}
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);
}
static void parse_opts(struct parse_state *ps, int argc, char *argv[])
{
struct args_info args = ARGS_INFO_INIT;
for (args.pos=1; args.pos < argc; ++args.pos) {
const char *a = argv[args.pos];
if (a[0] != '-') {
if (ps->spec)
usage("Too many specs", a);
ps->spec = a;
} else if (!strcmp(a, "--not"))
ps->not = !ps->not;
else if (!match_str_arg(&ps->repodir, &args, "--git-dir"))
usage("Cannot handle argument", a);
}
}
static int parse_revision(struct parse_state *ps)
{
git_revspec rs;
char str[GIT_OID_HEXSZ + 1];
if (!ps->repo) {
if (!ps->repodir)
ps->repodir = ".";
check_lg2(git_repository_open_ext(&ps->repo, ps->repodir, 0, NULL),
"Could not open repository from", ps->repodir);
}
check_lg2(git_revparse(&rs, ps->repo, ps->spec), "Could not parse", ps->spec);
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_lg2(git_merge_base(&base, ps->repo,
git_object_id(rs.from), git_object_id(rs.to)),
"Could not find merge base", ps->spec);
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 {
fatal("Invalid results from git_revparse", ps->spec);
}
return 0;
}
#include <git2.h> /*
#include <stdio.h> * libgit2 "showindex" example - shows how to extract data from the index
#include <string.h> *
* Written by the libgit2 contributors
*
* To the extent possible under law, the author(s) have dedicated all copyright
* and related and neighboring rights to this software to the public domain
* worldwide. This software is distributed without any warranty.
*
* You should have received a copy of the CC0 Public Domain Dedication along
* with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>.
*/
#include "common.h"
int main (int argc, char** argv) int main (int argc, char** argv)
{ {
git_repository *repo = NULL;
git_index *index; git_index *index;
unsigned int i, ecount; unsigned int i, ecount;
char *dir = "."; char *dir = ".";
...@@ -12,31 +23,24 @@ int main (int argc, char** argv) ...@@ -12,31 +23,24 @@ int main (int argc, char** argv)
char out[41]; char out[41];
out[40] = '\0'; out[40] = '\0';
git_threads_init();
if (argc > 2)
fatal("usage: showindex [<repo-dir>]", NULL);
if (argc > 1) if (argc > 1)
dir = argv[1]; dir = argv[1];
if (!dir || argc > 2) {
fprintf(stderr, "usage: showindex [<repo-dir>]\n");
return 1;
}
dirlen = strlen(dir); dirlen = strlen(dir);
if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) {
if (git_index_open(&index, dir) < 0) { check_lg2(git_index_open(&index, dir), "could not open index", dir);
fprintf(stderr, "could not open index: %s\n", dir);
return 1;
}
} else { } else {
if (git_repository_open_ext(&repo, dir, 0, NULL) < 0) { git_repository *repo;
fprintf(stderr, "could not open repository: %s\n", dir); check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir);
return 1; check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL);
} git_repository_free(repo);
if (git_repository_index(&index, repo) < 0) {
fprintf(stderr, "could not open repository index\n");
return 1;
}
} }
git_index_read(index); git_index_read(index, 0);
ecount = git_index_entrycount(index); ecount = git_index_entrycount(index);
if (!ecount) if (!ecount)
...@@ -60,8 +64,7 @@ int main (int argc, char** argv) ...@@ -60,8 +64,7 @@ int main (int argc, char** argv)
} }
git_index_free(index); git_index_free(index);
git_repository_free(repo); git_threads_shutdown();
return 0; return 0;
} }
...@@ -4,7 +4,7 @@ THIS_FILE="$(readlink -f "$0")" ...@@ -4,7 +4,7 @@ THIS_FILE="$(readlink -f "$0")"
ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")" ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")"
PROGRAM="$ROOT"/examples/rev-list PROGRAM="$ROOT"/examples/rev-list
LIBDIR="$ROOT"/build LIBDIR="$ROOT"/build
REPO="$ROOT"/tests-clar/resources/testrepo.git REPO="$ROOT"/tests/resources/testrepo.git
cd "$REPO" cd "$REPO"
......
...@@ -68,3 +68,4 @@ ok Sebastian Schuberth <sschuberth@gmail.com> ...@@ -68,3 +68,4 @@ ok Sebastian Schuberth <sschuberth@gmail.com>
ok Shawn O. Pearce <spearce@spearce.org> ok Shawn O. Pearce <spearce@spearce.org>
ok Steffen Prohaska <prohaska@zib.de> ok Steffen Prohaska <prohaska@zib.de>
ok Sven Verdoolaege <skimo@kotnet.org> ok Sven Verdoolaege <skimo@kotnet.org>
ok Torsten Bögershausen <tboegi@web.de>
...@@ -8,53 +8,52 @@ ...@@ -8,53 +8,52 @@
#ifndef INCLUDE_git_git_h__ #ifndef INCLUDE_git_git_h__
#define INCLUDE_git_git_h__ #define INCLUDE_git_git_h__
#include "git2/version.h" #include "git2/attr.h"
#include "git2/common.h"
#include "git2/threads.h"
#include "git2/errors.h"
#include "git2/types.h"
#include "git2/oid.h"
#include "git2/signature.h"
#include "git2/odb.h"
#include "git2/repository.h"
#include "git2/revwalk.h"
#include "git2/merge.h"
#include "git2/graph.h"
#include "git2/refs.h"
#include "git2/reflog.h"
#include "git2/revparse.h"
#include "git2/object.h"
#include "git2/blob.h" #include "git2/blob.h"
#include "git2/blame.h"
#include "git2/branch.h"
#include "git2/buffer.h"
#include "git2/checkout.h"
#include "git2/clone.h"
#include "git2/commit.h" #include "git2/commit.h"
#include "git2/tag.h" #include "git2/common.h"
#include "git2/tree.h"
#include "git2/diff.h"
#include "git2/index.h"
#include "git2/config.h" #include "git2/config.h"
#include "git2/transport.h" #include "git2/diff.h"
#include "git2/remote.h" #include "git2/errors.h"
#include "git2/clone.h" #include "git2/filter.h"
#include "git2/checkout.h" #include "git2/graph.h"
#include "git2/push.h"
#include "git2/attr.h"
#include "git2/ignore.h" #include "git2/ignore.h"
#include "git2/branch.h" #include "git2/index.h"
#include "git2/refspec.h"
#include "git2/net.h"
#include "git2/status.h"
#include "git2/indexer.h" #include "git2/indexer.h"
#include "git2/submodule.h" #include "git2/merge.h"
#include "git2/notes.h"
#include "git2/reset.h"
#include "git2/message.h" #include "git2/message.h"
#include "git2/net.h"
#include "git2/notes.h"
#include "git2/object.h"
#include "git2/odb.h"
#include "git2/oid.h"
#include "git2/pack.h" #include "git2/pack.h"
#include "git2/patch.h"
#include "git2/pathspec.h"
#include "git2/push.h"
#include "git2/refdb.h"
#include "git2/reflog.h"
#include "git2/refs.h"
#include "git2/refspec.h"
#include "git2/remote.h"
#include "git2/repository.h"
#include "git2/reset.h"
#include "git2/revparse.h"
#include "git2/revwalk.h"
#include "git2/signature.h"
#include "git2/stash.h" #include "git2/stash.h"
#include "git2/status.h"
#include "git2/submodule.h"
#include "git2/tag.h"
#include "git2/threads.h"
#include "git2/transport.h"
#include "git2/tree.h"
#include "git2/types.h"
#include "git2/version.h"
#endif #endif
/*
* 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_blame_h__
#define INCLUDE_git_blame_h__
#include "common.h"
#include "oid.h"
/**
* @file git2/blame.h
* @brief Git blame routines
* @defgroup git_blame Git blame routines
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Flags for indicating option behavior for git_blame APIs.
*/
typedef enum {
/** Normal blame, the default */
GIT_BLAME_NORMAL = 0,
/** Track lines that have moved within a file (like `git blame -M`).
* NOT IMPLEMENTED. */
GIT_BLAME_TRACK_COPIES_SAME_FILE = (1<<0),
/** Track lines that have moved across files in the same commit (like `git blame -C`).
* NOT IMPLEMENTED. */
GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES = (1<<1),
/** Track lines that have been copied from another file that exists in the
* same commit (like `git blame -CC`). Implies SAME_FILE.
* NOT IMPLEMENTED. */
GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES = (1<<2),
/** Track lines that have been copied from another file that exists in *any*
* commit (like `git blame -CCC`). Implies SAME_COMMIT_COPIES.
* NOT IMPLEMENTED. */
GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES = (1<<3),
} git_blame_flag_t;
/**
* Blame options structure
*
* Use zeros to indicate default settings. It's easiest to use the
* `GIT_BLAME_OPTIONS_INIT` macro:
* git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
*
* - `flags` is a combination of the `git_blame_flag_t` values above.
* - `min_match_characters` is the lower bound on the number of alphanumeric
* characters that must be detected as moving/copying within a file for it to
* associate those lines with the parent commit. The default value is 20.
* This value only takes effect if any of the `GIT_BLAME_TRACK_COPIES_*`
* flags are specified.
* - `newest_commit` is the id of the newest commit to consider. The default
* is HEAD.
* - `oldest_commit` is the id of the oldest commit to consider. The default
* is the first commit encountered with a NULL parent.
* - `min_line` is the first line in the file to blame. The default is 1 (line
* numbers start with 1).
* - `max_line` is the last line in the file to blame. The default is the last
* line of the file.
*/
typedef struct git_blame_options {
unsigned int version;
uint32_t flags;
uint16_t min_match_characters;
git_oid newest_commit;
git_oid oldest_commit;
uint32_t min_line;
uint32_t max_line;
} git_blame_options;
#define GIT_BLAME_OPTIONS_VERSION 1
#define GIT_BLAME_OPTIONS_INIT {GIT_BLAME_OPTIONS_VERSION}
/**
* Structure that represents a blame hunk.
*
* - `lines_in_hunk` is the number of lines in this hunk
* - `final_commit_id` is the OID of the commit where this line was last
* changed.
* - `final_start_line_number` is the 1-based line number where this hunk
* begins, in the final version of the file
* - `orig_commit_id` is the OID of the commit where this hunk was found. This
* will usually be the same as `final_commit_id`, except when
* `GIT_BLAME_TRACK_COPIES_ANY_COMMIT_COPIES` has been specified.
* - `orig_path` is the path to the file where this hunk originated, as of the
* commit specified by `orig_commit_id`.
* - `orig_start_line_number` is the 1-based line number where this hunk begins
* in the file named by `orig_path` in the commit specified by
* `orig_commit_id`.
* - `boundary` is 1 iff the hunk has been tracked to a boundary commit (the
* root, or the commit specified in git_blame_options.oldest_commit)
*/
typedef struct git_blame_hunk {
uint16_t lines_in_hunk;
git_oid final_commit_id;
uint16_t final_start_line_number;
git_signature *final_signature;
git_oid orig_commit_id;
const char *orig_path;
uint16_t orig_start_line_number;
git_signature *orig_signature;
char boundary;
} git_blame_hunk;
/* Opaque structure to hold blame results */
typedef struct git_blame git_blame;
/**
* Gets the number of hunks that exist in the blame structure.
*/
GIT_EXTERN(uint32_t) git_blame_get_hunk_count(git_blame *blame);
/**
* Gets the blame hunk at the given index.
*
* @param blame the blame structure to query
* @param index index of the hunk to retrieve
* @return the hunk at the given index, or NULL on error
*/
GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byindex(
git_blame *blame,
uint32_t index);
/**
* Gets the hunk that relates to the given line number in the newest commit.
*
* @param blame the blame structure to query
* @param lineno the (1-based) line number to find a hunk for
* @return the hunk that contains the given line, or NULL on error
*/
GIT_EXTERN(const git_blame_hunk*) git_blame_get_hunk_byline(
git_blame *blame,
uint32_t lineno);
/**
* Get the blame for a single file.
*
* @param out pointer that will receive the blame object
* @param repo repository whose history is to be walked
* @param path path to file to consider
* @param options options for the blame operation. If NULL, this is treated as
* though GIT_BLAME_OPTIONS_INIT were passed.
* @return 0 on success, or an error code. (use giterr_last for information
* about the error.)
*/
GIT_EXTERN(int) git_blame_file(
git_blame **out,
git_repository *repo,
const char *path,
git_blame_options *options);
/**
* Get blame data for a file that has been modified in memory. The `reference`
* parameter is a pre-calculated blame for the in-odb history of the file. This
* means that once a file blame is completed (which can be expensive), updating
* the buffer blame is very fast.
*
* Lines that differ between the buffer and the committed version are marked as
* having a zero OID for their final_commit_id.
*
* @param out pointer that will receive the resulting blame data
* @param reference cached blame from the history of the file (usually the output
* from git_blame_file)
* @param buffer the (possibly) modified contents of the file
* @param buffer_len number of valid bytes in the buffer
* @return 0 on success, or an error code. (use giterr_last for information
* about the error)
*/
GIT_EXTERN(int) git_blame_buffer(
git_blame **out,
git_blame *reference,
const char *buffer,
uint32_t buffer_len);
/**
* Free memory allocated by git_blame_file or git_blame_buffer.
*
* @param blame the blame structure to free
*/
GIT_EXTERN(void) git_blame_free(git_blame *blame);
/** @} */
GIT_END_DECL
#endif
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "types.h" #include "types.h"
#include "oid.h" #include "oid.h"
#include "object.h" #include "object.h"
#include "buffer.h"
/** /**
* @file git2/blob.h * @file git2/blob.h
...@@ -96,6 +97,37 @@ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob); ...@@ -96,6 +97,37 @@ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob);
GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob); GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob);
/** /**
* Get a buffer with the filtered content of a blob.
*
* This applies filters as if the blob was being checked out to the
* working directory under the specified filename. This may apply
* CRLF filtering or other types of changes depending on the file
* attributes set for the blob and the content detected in it.
*
* The output is written into a `git_buf` which the caller must free
* when done (via `git_buf_free`).
*
* If no filters need to be applied, then the `out` buffer will just be
* populated with a pointer to the raw content of the blob. In that case,
* be careful to *not* free the blob until done with the buffer. To keep
* the data detached from the blob, call `git_buf_grow` on the buffer
* with a `want_size` of 0 and the buffer will be reallocated to be
* detached from the blob.
*
* @param out The git_buf to be filled in
* @param blob Pointer to the blob
* @param as_path Path used for file attribute lookups, etc.
* @param check_for_binary_data Should this test if blob content contains
* NUL bytes / looks like binary data before applying filters?
* @return 0 on success or an error code
*/
GIT_EXTERN(int) git_blob_filtered_content(
git_buf *out,
git_blob *blob,
const char *as_path,
int check_for_binary_data);
/**
* Read a file from the working folder of a repository * Read a file from the working folder of a repository
* and write it to the Object Database as a loose blob * and write it to the Object Database as a loose blob
* *
......
...@@ -66,33 +66,41 @@ GIT_EXTERN(int) git_branch_create( ...@@ -66,33 +66,41 @@ GIT_EXTERN(int) git_branch_create(
*/ */
GIT_EXTERN(int) git_branch_delete(git_reference *branch); GIT_EXTERN(int) git_branch_delete(git_reference *branch);
typedef int (*git_branch_foreach_cb)( /** Iterator type for branches */
const char *branch_name, typedef struct git_branch_iterator git_branch_iterator;
git_branch_t branch_type,
void *payload);
/** /**
* Loop over all the branches and issue a callback for each one. * Create an iterator which loops over the requested branches.
*
* If the callback returns a non-zero value, this will stop looping.
* *
* @param out the iterator
* @param repo Repository where to find the branches. * @param repo Repository where to find the branches.
*
* @param list_flags Filtering flags for the branch * @param list_flags Filtering flags for the branch
* listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE * listing. Valid values are GIT_BRANCH_LOCAL, GIT_BRANCH_REMOTE
* or a combination of the two. * or a combination of the two.
* *
* @param branch_cb Callback to invoke per found branch. * @return 0 on success or an error code
*/
GIT_EXTERN(int) git_branch_iterator_new(
git_branch_iterator **out,
git_repository *repo,
git_branch_t list_flags);
/**
* Retrieve the next branch from the iterator
* *
* @param payload Extra parameter to callback function. * @param out the reference
* @param out_type the type of branch (local or remote-tracking)
* @param iter the branch iterator
* @return 0 on success, GIT_ITEROVER if there are no more branches or an error code.
*/
GIT_EXTERN(int) git_branch_next(git_reference **out, git_branch_t *out_type, git_branch_iterator *iter);
/**
* Free a branch iterator
* *
* @return 0 on success, GIT_EUSER on non-zero callback, or error code * @param iter the iterator to free
*/ */
GIT_EXTERN(int) git_branch_foreach( GIT_EXTERN(void) git_branch_iterator_free(git_branch_iterator *iter);
git_repository *repo,
unsigned int list_flags,
git_branch_foreach_cb branch_cb,
void *payload);
/** /**
* Move/rename an existing local branch reference. * Move/rename an existing local branch reference.
......
/*
* 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_buf_h__
#define INCLUDE_git_buf_h__
#include "common.h"
/**
* @file git2/buffer.h
* @brief Buffer export structure
*
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* A data buffer for exporting data from libgit2
*
* Sometimes libgit2 wants to return an allocated data buffer to the
* caller and have the caller take responsibility for freeing that memory.
* This can be awkward if the caller does not have easy access to the same
* allocation functions that libgit2 is using. In those cases, libgit2
* will fill in a `git_buf` and the caller can use `git_buf_free()` to
* release it when they are done.
*
* A `git_buf` may also be used for the caller to pass in a reference to
* a block of memory they hold. In this case, libgit2 will not resize or
* free the memory, but will read from it as needed.
*
* A `git_buf` is a public structure with three fields:
*
* - `ptr` points to the start of the allocated memory. If it is NULL,
* then the `git_buf` is considered empty and libgit2 will feel free
* to overwrite it with new data.
*
* - `size` holds the size (in bytes) of the data that is actually used.
*
* - `asize` holds the known total amount of allocated memory if the `ptr`
* was allocated by libgit2. It may be larger than `size`. If `ptr`
* was not allocated by libgit2 and should not be resized and/or freed,
* then `asize` will be set to zero.
*
* Some APIs may occasionally do something slightly unusual with a buffer,
* such as setting `ptr` to a value that was passed in by the user. In
* those cases, the behavior will be clearly documented by the API.
*/
typedef struct {
char *ptr;
size_t asize, size;
} git_buf;
/**
* Static initializer for git_buf from static buffer
*/
#define GIT_BUF_INIT_CONST(STR,LEN) { (char *)(STR), 0, (size_t)(LEN) }
/**
* Free the memory referred to by the git_buf.
*
* Note that this does not free the `git_buf` itself, just the memory
* pointed to by `buffer->ptr`. This will not free the memory if it looks
* like it was not allocated internally, but it will clear the buffer back
* to the empty state.
*
* @param buffer The buffer to deallocate
*/
GIT_EXTERN(void) git_buf_free(git_buf *buffer);
/**
* Resize the buffer allocation to make more space.
*
* This will attempt to grow the buffer to accomodate the target size.
*
* If the buffer refers to memory that was not allocated by libgit2 (i.e.
* the `asize` field is zero), then `ptr` will be replaced with a newly
* allocated block of data. Be careful so that memory allocated by the
* caller is not lost. As a special variant, if you pass `target_size` as
* 0 and the memory is not allocated by libgit2, this will allocate a new
* buffer of size `size` and copy the external data into it.
*
* Currently, this will never shrink a buffer, only expand it.
*
* If the allocation fails, this will return an error and the buffer will be
* marked as invalid for future operations, invaliding the contents.
*
* @param buffer The buffer to be resized; may or may not be allocated yet
* @param target_size The desired available size
* @return 0 on success, -1 on allocation failure
*/
GIT_EXTERN(int) git_buf_grow(git_buf *buffer, size_t target_size);
/**
* Set buffer to a copy of some raw data.
*
* @param buffer The buffer to set
* @param data The data to copy into the buffer
* @param datalen The length of the data to copy into the buffer
* @return 0 on success, -1 on allocation failure
*/
GIT_EXTERN(int) git_buf_set(
git_buf *buffer, const void *data, size_t datalen);
GIT_END_DECL
/** @} */
#endif
...@@ -131,6 +131,13 @@ typedef enum { ...@@ -131,6 +131,13 @@ typedef enum {
/** Don't refresh index/config/etc before doing checkout */ /** Don't refresh index/config/etc before doing checkout */
GIT_CHECKOUT_NO_REFRESH = (1u << 9), GIT_CHECKOUT_NO_REFRESH = (1u << 9),
/** Allow checkout to skip unmerged files */
GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10),
/** For unmerged files, checkout stage 2 from index */
GIT_CHECKOUT_USE_OURS = (1u << 11),
/** For unmerged files, checkout stage 3 from index */
GIT_CHECKOUT_USE_THEIRS = (1u << 12),
/** Treat pathspec as simple list of exact match file paths */ /** Treat pathspec as simple list of exact match file paths */
GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13), GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH = (1u << 13),
...@@ -141,13 +148,6 @@ typedef enum { ...@@ -141,13 +148,6 @@ typedef enum {
* THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED * THE FOLLOWING OPTIONS ARE NOT YET IMPLEMENTED
*/ */
/** Allow checkout to skip unmerged files (NOT IMPLEMENTED) */
GIT_CHECKOUT_SKIP_UNMERGED = (1u << 10),
/** For unmerged files, checkout stage 2 from index (NOT IMPLEMENTED) */
GIT_CHECKOUT_USE_OURS = (1u << 11),
/** For unmerged files, checkout stage 3 from index (NOT IMPLEMENTED) */
GIT_CHECKOUT_USE_THEIRS = (1u << 12),
/** Recursively checkout submodules with same options (NOT IMPLEMENTED) */ /** Recursively checkout submodules with same options (NOT IMPLEMENTED) */
GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16), GIT_CHECKOUT_UPDATE_SUBMODULES = (1u << 16),
/** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */ /** Recursively checkout submodules if HEAD moved in super repo (NOT IMPLEMENTED) */
...@@ -238,6 +238,9 @@ typedef struct git_checkout_opts { ...@@ -238,6 +238,9 @@ typedef struct git_checkout_opts {
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 */ const char *target_directory; /** alternative checkout path to workdir */
const char *our_label; /** the name of the "our" side of conflicts */
const char *their_label; /** the name of the "their" side of conflicts */
} git_checkout_opts; } git_checkout_opts;
#define GIT_CHECKOUT_OPTS_VERSION 1 #define GIT_CHECKOUT_OPTS_VERSION 1
...@@ -249,13 +252,13 @@ typedef struct git_checkout_opts { ...@@ -249,13 +252,13 @@ typedef struct git_checkout_opts {
* *
* @param repo repository to check out (must be non-bare) * @param repo repository to check out (must be non-bare)
* @param opts specifies checkout options (may be NULL) * @param opts specifies checkout options (may be NULL)
* @return 0 on success, GIT_EORPHANEDHEAD when HEAD points to a non existing * @return 0 on success, GIT_EUNBORNBRANCH when HEAD points to a non existing
* branch, GIT_ERROR otherwise (use giterr_last for information * branch, GIT_ERROR otherwise (use giterr_last for information
* about the error) * about the error)
*/ */
GIT_EXTERN(int) git_checkout_head( GIT_EXTERN(int) git_checkout_head(
git_repository *repo, git_repository *repo,
git_checkout_opts *opts); const git_checkout_opts *opts);
/** /**
* Updates files in the working tree to match the content of the index. * Updates files in the working tree to match the content of the index.
...@@ -269,7 +272,7 @@ GIT_EXTERN(int) git_checkout_head( ...@@ -269,7 +272,7 @@ GIT_EXTERN(int) git_checkout_head(
GIT_EXTERN(int) git_checkout_index( GIT_EXTERN(int) git_checkout_index(
git_repository *repo, git_repository *repo,
git_index *index, git_index *index,
git_checkout_opts *opts); const git_checkout_opts *opts);
/** /**
* Updates files in the index and working tree to match the content of the * Updates files in the index and working tree to match the content of the
...@@ -277,7 +280,7 @@ GIT_EXTERN(int) git_checkout_index( ...@@ -277,7 +280,7 @@ GIT_EXTERN(int) git_checkout_index(
* *
* @param repo repository to check out (must be non-bare) * @param repo repository to check out (must be non-bare)
* @param treeish a commit, tag or tree which content will be used to update * @param treeish a commit, tag or tree which content will be used to update
* the working directory * the working directory (or NULL to use HEAD)
* @param opts specifies checkout options (may be NULL) * @param opts specifies checkout options (may be NULL)
* @return 0 on success, GIT_ERROR otherwise (use giterr_last for information * @return 0 on success, GIT_ERROR otherwise (use giterr_last for information
* about the error) * about the error)
...@@ -285,7 +288,7 @@ GIT_EXTERN(int) git_checkout_index( ...@@ -285,7 +288,7 @@ GIT_EXTERN(int) git_checkout_index(
GIT_EXTERN(int) git_checkout_tree( GIT_EXTERN(int) git_checkout_tree(
git_repository *repo, git_repository *repo,
const git_object *treeish, const git_object *treeish,
git_checkout_opts *opts); const git_checkout_opts *opts);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
......
...@@ -35,30 +35,12 @@ GIT_BEGIN_DECL ...@@ -35,30 +35,12 @@ GIT_BEGIN_DECL
* set the `checkout_strategy` to GIT_CHECKOUT_DEFAULT. * set the `checkout_strategy` to GIT_CHECKOUT_DEFAULT.
* - `bare` should be set to zero to create a standard repo, non-zero for * - `bare` should be set to zero to create a standard repo, non-zero for
* a bare repo * a bare repo
* - `fetch_progress_cb` is optional callback for fetch progress. Be aware that * - `ignore_cert_errors` should be set to 1 if errors validating the remote host's
* this is called inline with network and indexing operations, so performance * certificate should be ignored.
* may be affected.
* - `fetch_progress_payload` is payload for fetch_progress_cb
* *
* ** "origin" remote options: ** * ** "origin" remote options: **
* - `remote_name` is the name given to the "origin" remote. The default is * - `remote_name` is the name given to the "origin" remote. The default is
* "origin". * "origin".
* - `pushurl` is a URL to be used for pushing. NULL means use the fetch url.
* - `fetch_spec` is the fetch specification to be used for fetching. NULL
* results in the same behavior as GIT_REMOTE_DEFAULT_FETCH.
* - `push_spec` is the fetch specification to be used for pushing. NULL means
* use the same spec as for fetching.
* - `cred_acquire_cb` is a callback to be used if credentials are required
* during the initial fetch.
* - `cred_acquire_payload` is the payload for the above callback.
* - `transport_flags` is flags used to create transport if no transport is
* provided.
* - `transport` is a custom transport to be used for the initial fetch. NULL
* means use the transport autodetected from the URL.
* - `remote_callbacks` may be used to specify custom progress callbacks for
* the origin remote before the fetch is initiated.
* - `remote_autotag` may be used to specify the autotag setting before the
* initial fetch. The default is GIT_REMOTE_DOWNLOAD_TAGS_ALL.
* - `checkout_branch` gives the name of the branch to checkout. NULL means * - `checkout_branch` gives the name of the branch to checkout. NULL means
* use the remote's HEAD. * use the remote's HEAD.
*/ */
...@@ -67,29 +49,23 @@ typedef struct git_clone_options { ...@@ -67,29 +49,23 @@ typedef struct git_clone_options {
unsigned int version; unsigned int version;
git_checkout_opts checkout_opts; git_checkout_opts checkout_opts;
int bare; git_remote_callbacks remote_callbacks;
git_transfer_progress_callback fetch_progress_cb;
void *fetch_progress_payload;
int bare;
int ignore_cert_errors;
const char *remote_name; const char *remote_name;
const char *pushurl;
const char *fetch_spec;
const char *push_spec;
git_cred_acquire_cb cred_acquire_cb;
void *cred_acquire_payload;
git_transport_flags_t transport_flags;
git_transport *transport;
git_remote_callbacks *remote_callbacks;
git_remote_autotag_option_t remote_autotag;
const char* checkout_branch; const char* checkout_branch;
} git_clone_options; } git_clone_options;
#define GIT_CLONE_OPTIONS_VERSION 1 #define GIT_CLONE_OPTIONS_VERSION 1
#define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE_CREATE}} #define GIT_CLONE_OPTIONS_INIT {GIT_CLONE_OPTIONS_VERSION, {GIT_CHECKOUT_OPTS_VERSION, GIT_CHECKOUT_SAFE_CREATE}, GIT_REMOTE_CALLBACKS_INIT}
/** /**
* Clone a remote repository, and checkout the branch pointed to by the remote * Clone a remote repository.
* HEAD. *
* This version handles the simple case. If you'd like to create the
* repository or remote with non-default settings, you can create and
* configure them and then use `git_clone_into()`.
* *
* @param out pointer that will receive the resulting repository object * @param out pointer that will receive the resulting repository object
* @param url the remote repository to clone * @param url the remote repository to clone
...@@ -105,6 +81,22 @@ GIT_EXTERN(int) git_clone( ...@@ -105,6 +81,22 @@ GIT_EXTERN(int) git_clone(
const char *local_path, const char *local_path,
const git_clone_options *options); const git_clone_options *options);
/**
* Clone into a repository
*
* After creating the repository and remote and configuring them for
* paths and callbacks respectively, you can call this function to
* perform the clone operation and optionally checkout files.
*
* @param repo the repository to use
* @param remote the remote repository to clone from
* @param co_opts options to use during checkout
* @param branch the branch to checkout after the clone, pass NULL for the remote's
* default branch
* @return 0 on success or an error code
*/
GIT_EXTERN(int) git_clone_into(git_repository *repo, git_remote *remote, const git_checkout_opts *co_opts, const char *branch);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -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
...@@ -92,12 +100,23 @@ GIT_EXTERN(const char *) git_commit_message_encoding(const git_commit *commit); ...@@ -92,12 +100,23 @@ GIT_EXTERN(const char *) git_commit_message_encoding(const git_commit *commit);
/** /**
* Get the full message of a commit. * Get the full message of a commit.
* *
* The returned message will be slightly prettified by removing any
* potential leading newlines.
*
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
* @return the message of a commit * @return the message of a commit
*/ */
GIT_EXTERN(const char *) git_commit_message(const git_commit *commit); GIT_EXTERN(const char *) git_commit_message(const git_commit *commit);
/** /**
* Get the full raw message of a commit.
*
* @param commit a previously loaded commit.
* @return the raw message of a commit
*/
GIT_EXTERN(const char *) git_commit_message_raw(const git_commit *commit);
/**
* Get the commit time (i.e. committer time) of a commit. * Get the commit time (i.e. committer time) of a commit.
* *
* @param commit a previously loaded commit. * @param commit a previously loaded commit.
...@@ -130,6 +149,14 @@ GIT_EXTERN(const git_signature *) git_commit_committer(const git_commit *commit) ...@@ -130,6 +149,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
......
...@@ -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;
/** /**
...@@ -135,7 +136,9 @@ typedef enum { ...@@ -135,7 +136,9 @@ typedef enum {
GIT_OPT_SET_CACHE_OBJECT_LIMIT, GIT_OPT_SET_CACHE_OBJECT_LIMIT,
GIT_OPT_SET_CACHE_MAX_SIZE, GIT_OPT_SET_CACHE_MAX_SIZE,
GIT_OPT_ENABLE_CACHING, GIT_OPT_ENABLE_CACHING,
GIT_OPT_GET_CACHED_MEMORY GIT_OPT_GET_CACHED_MEMORY,
GIT_OPT_GET_TEMPLATE_PATH,
GIT_OPT_SET_TEMPLATE_PATH
} git_libgit2_opt_t; } git_libgit2_opt_t;
/** /**
...@@ -209,6 +212,18 @@ typedef enum { ...@@ -209,6 +212,18 @@ typedef enum {
* > Get the current bytes in cache and the maximum that would be * > Get the current bytes in cache and the maximum that would be
* > allowed in the cache. * > allowed in the cache.
* *
* * opts(GIT_OPT_GET_TEMPLATE_PATH, char *out, size_t len)
*
* > Get the default template path.
* > The path is written to the `out`
* > buffer up to size `len`. Returns GIT_EBUFS if buffer is too small.
*
* * opts(GIT_OPT_SET_TEMPLATE_PATH, const char *path)
*
* > Set the default template path.
* >
* > - `path` directory of template.
*
* @param option Option key * @param option Option key
* @param ... value to set the option * @param ... value to set the option
* @return 0 on success, <0 on failure * @return 0 on success, <0 on failure
......
...@@ -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,
...@@ -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
* *
...@@ -338,7 +339,34 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c ...@@ -338,7 +339,34 @@ GIT_EXTERN(int) git_config_get_string(const char **out, const git_config *cfg, c
* @param callback 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 payload opaque pointer to pass to the callback * @param payload opaque pointer to pass to the callback
*/ */
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_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_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
...@@ -407,6 +435,17 @@ GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const ...@@ -407,6 +435,17 @@ GIT_EXTERN(int) git_config_set_multivar(git_config *cfg, const char *name, const
GIT_EXTERN(int) git_config_delete_entry(git_config *cfg, const char *name); GIT_EXTERN(int) git_config_delete_entry(git_config *cfg, const char *name);
/** /**
* Deletes one or several entries from a multivar in the local config file.
*
* @param cfg where to look for the variables
* @param name the variable's name
* @param regexp a regular expression to indicate which values to delete
*
* @return 0 or an error code
*/
GIT_EXTERN(int) git_config_delete_multivar(git_config *cfg, const char *name, const char *regexp);
/**
* Perform an operation on each config variable. * Perform an operation on each config variable.
* *
* The callback receives the normalized name and value of each variable * The callback receives the normalized name and value of each variable
...@@ -425,6 +464,29 @@ GIT_EXTERN(int) git_config_foreach( ...@@ -425,6 +464,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 +597,25 @@ GIT_EXTERN(int) git_config_parse_int32(int32_t *out, const char *value); ...@@ -535,6 +597,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
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define INCLUDE_git_errors_h__ #define INCLUDE_git_errors_h__
#include "common.h" #include "common.h"
#include "buffer.h"
/** /**
* @file git2/errors.h * @file git2/errors.h
...@@ -27,11 +28,12 @@ typedef enum { ...@@ -27,11 +28,12 @@ typedef enum {
GIT_EBUFS = -6, GIT_EBUFS = -6,
GIT_EUSER = -7, GIT_EUSER = -7,
GIT_EBAREREPO = -8, GIT_EBAREREPO = -8,
GIT_EORPHANEDHEAD = -9, GIT_EUNBORNBRANCH = -9,
GIT_EUNMERGED = -10, GIT_EUNMERGED = -10,
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,
...@@ -44,6 +46,7 @@ typedef struct { ...@@ -44,6 +46,7 @@ typedef struct {
/** Error classes */ /** Error classes */
typedef enum { typedef enum {
GITERR_NONE = 0,
GITERR_NOMEMORY, GITERR_NOMEMORY,
GITERR_OS, GITERR_OS,
GITERR_INVALID, GITERR_INVALID,
...@@ -66,6 +69,8 @@ typedef enum { ...@@ -66,6 +69,8 @@ typedef enum {
GITERR_CHECKOUT, GITERR_CHECKOUT,
GITERR_FETCHHEAD, GITERR_FETCHHEAD,
GITERR_MERGE, GITERR_MERGE,
GITERR_SSH,
GITERR_FILTER,
} git_error_t; } git_error_t;
/** /**
...@@ -82,6 +87,18 @@ GIT_EXTERN(const git_error *) giterr_last(void); ...@@ -82,6 +87,18 @@ GIT_EXTERN(const git_error *) giterr_last(void);
GIT_EXTERN(void) giterr_clear(void); GIT_EXTERN(void) giterr_clear(void);
/** /**
* Get the last error data and clear it.
*
* This copies the last error into the given `git_error` struct
* and returns 0 if the copy was successful, leaving the error
* cleared as if `giterr_clear` had been called.
*
* If there was no existing error in the library, -1 will be returned
* and the contents of `cpy` will be left unmodified.
*/
GIT_EXTERN(int) giterr_detach(git_error *cpy);
/**
* Set the error message string for this thread. * Set the error message string for this thread.
* *
* This function is public so that custom ODB backends and the like can * This function is public so that custom ODB backends and the like can
......
/*
* 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_filter_h__
#define INCLUDE_git_filter_h__
#include "common.h"
#include "types.h"
#include "oid.h"
#include "buffer.h"
/**
* @file git2/filter.h
* @brief Git filter APIs
*
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Filters are applied in one of two directions: smudging - which is
* exporting a file from the Git object database to the working directory,
* and cleaning - which is importing a file from the working directory to
* the Git object database. These values control which direction of
* change is being applied.
*/
typedef enum {
GIT_FILTER_TO_WORKTREE = 0,
GIT_FILTER_SMUDGE = GIT_FILTER_TO_WORKTREE,
GIT_FILTER_TO_ODB = 1,
GIT_FILTER_CLEAN = GIT_FILTER_TO_ODB,
} git_filter_mode_t;
/**
* A filter that can transform file data
*
* This represents a filter that can be used to transform or even replace
* file data. Libgit2 includes one built in filter and it is possible to
* write your own (see git2/sys/filter.h for information on that).
*
* The two builtin filters are:
*
* * "crlf" which uses the complex rules with the "text", "eol", and
* "crlf" file attributes to decide how to convert between LF and CRLF
* line endings
* * "ident" which replaces "$Id$" in a blob with "$Id: <blob OID>$" upon
* checkout and replaced "$Id: <anything>$" with "$Id$" on checkin.
*/
typedef struct git_filter git_filter;
/**
* List of filters to be applied
*
* This represents a list of filters to be applied to a file / blob. You
* can build the list with one call, apply it with another, and dispose it
* with a third. In typical usage, there are not many occasions where a
* git_filter_list is needed directly since the library will generally
* handle conversions for you, but it can be convenient to be able to
* build and apply the list sometimes.
*/
typedef struct git_filter_list git_filter_list;
/**
* Load the filter list for a given path.
*
* This will return 0 (success) but set the output git_filter_list to NULL
* if no filters are requested for the given file.
*
* @param filters Output newly created git_filter_list (or NULL)
* @param repo Repository object that contains `path`
* @param blob The blob to which the filter will be applied (if known)
* @param path Relative path of the file to be filtered
* @param mode Filtering direction (WT->ODB or ODB->WT)
* @return 0 on success (which could still return NULL if no filters are
* needed for the requested file), <0 on error
*/
GIT_EXTERN(int) git_filter_list_load(
git_filter_list **filters,
git_repository *repo,
git_blob *blob, /* can be NULL */
const char *path,
git_filter_mode_t mode);
/**
* Apply filter list to a data buffer.
*
* See `git2/buffer.h` for background on `git_buf` objects.
*
* If the `in` buffer holds data allocated by libgit2 (i.e. `in->asize` is
* not zero), then it will be overwritten when applying the filters. If
* not, then it will be left untouched.
*
* If there are no filters to apply (or `filters` is NULL), then the `out`
* buffer will reference the `in` buffer data (with `asize` set to zero)
* instead of allocating data. This keeps allocations to a minimum, but
* it means you have to be careful about freeing the `in` data since `out`
* may be pointing to it!
*
* @param out Buffer to store the result of the filtering
* @param filters A loaded git_filter_list (or NULL)
* @param in Buffer containing the data to filter
* @return 0 on success, an error code otherwise
*/
GIT_EXTERN(int) git_filter_list_apply_to_data(
git_buf *out,
git_filter_list *filters,
git_buf *in);
/**
* Apply filter list to the contents of a file on disk
*/
GIT_EXTERN(int) git_filter_list_apply_to_file(
git_buf *out,
git_filter_list *filters,
git_repository *repo,
const char *path);
/**
* Apply filter list to the contents of a blob
*/
GIT_EXTERN(int) git_filter_list_apply_to_blob(
git_buf *out,
git_filter_list *filters,
git_blob *blob);
/**
* Free a git_filter_list
*
* @param filters A git_filter_list created by `git_filter_list_load`
*/
GIT_EXTERN(void) git_filter_list_free(git_filter_list *filters);
GIT_END_DECL
/** @} */
#endif
...@@ -120,9 +120,9 @@ typedef struct git_index_entry { ...@@ -120,9 +120,9 @@ typedef struct git_index_entry {
/** Capabilities of system that affect index actions. */ /** Capabilities of system that affect index actions. */
typedef enum { typedef enum {
GIT_INDEXCAP_IGNORE_CASE = 1, GIT_INDEXCAP_IGNORE_CASE = 1u,
GIT_INDEXCAP_NO_FILEMODE = 2, GIT_INDEXCAP_NO_FILEMODE = 2u,
GIT_INDEXCAP_NO_SYMLINKS = 4, GIT_INDEXCAP_NO_SYMLINKS = 4u,
GIT_INDEXCAP_FROM_OWNER = ~0u GIT_INDEXCAP_FROM_OWNER = ~0u
} git_indexcap_t; } git_indexcap_t;
...@@ -138,6 +138,14 @@ typedef enum { ...@@ -138,6 +138,14 @@ typedef enum {
GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2), GIT_INDEX_ADD_CHECK_PATHSPEC = (1u << 2),
} git_index_add_option_t; } 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.
...@@ -214,13 +222,23 @@ GIT_EXTERN(unsigned int) git_index_caps(const git_index *index); ...@@ -214,13 +222,23 @@ GIT_EXTERN(unsigned int) git_index_caps(const git_index *index);
GIT_EXTERN(int) git_index_set_caps(git_index *index, unsigned int caps); GIT_EXTERN(int) git_index_set_caps(git_index *index, unsigned int caps);
/** /**
* Update the contents of an existing index object in memory * Update the contents of an existing index object in memory by reading
* by reading from the hard disk. * from the hard disk.
*
* If `force` is true, this performs a "hard" read that discards in-memory
* changes and always reloads the on-disk index data. If there is no
* on-disk version, the index will be cleared.
*
* If `force` is false, this does a "soft" read that reloads the index
* data from disk only if it has changed since the last time it was
* loaded. Purely in-memory index data will be untouched. Be aware: if
* there are changes on disk, unwritten in-memory changes are discarded.
* *
* @param index an existing index object * @param index an existing index object
* @param force if true, always reload, vs. only read if file has changed
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_index_read(git_index *index); GIT_EXTERN(int) git_index_read(git_index *index, int force);
/** /**
* Write an existing index object from memory back to disk * Write an existing index object from memory back to disk
...@@ -232,6 +250,14 @@ GIT_EXTERN(int) git_index_read(git_index *index); ...@@ -232,6 +250,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.
......
...@@ -13,19 +13,25 @@ ...@@ -13,19 +13,25 @@
GIT_BEGIN_DECL GIT_BEGIN_DECL
typedef struct git_indexer_stream git_indexer_stream; typedef struct git_indexer git_indexer;
/** /**
* Create a new streaming indexer instance * Create a new indexer instance
* *
* @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 mode permissions to use creating packfile or 0 for defaults
* @param odb object database from which to read base objects when
* fixing thin packs. Pass NULL if no thin pack is expected (an error
* will be returned if there are bases missing)
* @param progress_cb function to call with progress information * @param progress_cb function to call with progress information
* @param progress_cb_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_new(
git_indexer_stream **out, git_indexer **out,
const char *path, const char *path,
unsigned int mode,
git_odb *odb,
git_transfer_progress_callback progress_cb, git_transfer_progress_callback progress_cb,
void *progress_cb_payload); void *progress_cb_payload);
...@@ -37,7 +43,7 @@ GIT_EXTERN(int) git_indexer_stream_new( ...@@ -37,7 +43,7 @@ GIT_EXTERN(int) git_indexer_stream_new(
* @param size the size of the data in bytes * @param size the size of the data in bytes
* @param stats stat storage * @param stats stat storage
*/ */
GIT_EXTERN(int) git_indexer_stream_add(git_indexer_stream *idx, const void *data, size_t size, git_transfer_progress *stats); GIT_EXTERN(int) git_indexer_append(git_indexer *idx, const void *data, size_t size, git_transfer_progress *stats);
/** /**
* Finalize the pack and index * Finalize the pack and index
...@@ -46,7 +52,7 @@ GIT_EXTERN(int) git_indexer_stream_add(git_indexer_stream *idx, const void *data ...@@ -46,7 +52,7 @@ GIT_EXTERN(int) git_indexer_stream_add(git_indexer_stream *idx, const void *data
* *
* @param idx the indexer * @param idx the indexer
*/ */
GIT_EXTERN(int) git_indexer_stream_finalize(git_indexer_stream *idx, git_transfer_progress *stats); GIT_EXTERN(int) git_indexer_commit(git_indexer *idx, git_transfer_progress *stats);
/** /**
* Get the packfile's hash * Get the packfile's hash
...@@ -56,14 +62,14 @@ GIT_EXTERN(int) git_indexer_stream_finalize(git_indexer_stream *idx, git_transfe ...@@ -56,14 +62,14 @@ GIT_EXTERN(int) git_indexer_stream_finalize(git_indexer_stream *idx, git_transfe
* *
* @param idx the indexer instance * @param idx the indexer instance
*/ */
GIT_EXTERN(const git_oid *) git_indexer_stream_hash(const git_indexer_stream *idx); GIT_EXTERN(const git_oid *) git_indexer_hash(const git_indexer *idx);
/** /**
* Free the indexer and its resources * Free the indexer and its resources
* *
* @param idx the indexer to free * @param idx the indexer to free
*/ */
GIT_EXTERN(void) git_indexer_stream_free(git_indexer_stream *idx); GIT_EXTERN(void) git_indexer_free(git_indexer *idx);
GIT_END_DECL GIT_END_DECL
......
...@@ -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
...@@ -66,6 +66,29 @@ typedef struct { ...@@ -66,6 +66,29 @@ typedef struct {
/** /**
* Option flags for `git_merge`.
*
* GIT_MERGE_NO_FASTFORWARD - Do not fast-forward.
*/
typedef enum {
GIT_MERGE_NO_FASTFORWARD = 1,
GIT_MERGE_FASTFORWARD_ONLY = 2,
} git_merge_flags_t;
typedef struct {
unsigned int version;
git_merge_flags_t merge_flags;
git_merge_tree_opts merge_tree_opts;
git_checkout_opts checkout_opts;
} git_merge_opts;
#define GIT_MERGE_OPTS_VERSION 1
#define GIT_MERGE_OPTS_INIT {GIT_MERGE_OPTS_VERSION, 0, GIT_MERGE_TREE_OPTS_INIT, GIT_CHECKOUT_OPTS_INIT}
/**
* Find a merge base between two commits * Find a merge base between two commits
* *
* @param out the OID of a merge base between 'one' and 'two' * @param out the OID of a merge base between 'one' and 'two'
...@@ -85,15 +108,15 @@ GIT_EXTERN(int) git_merge_base( ...@@ -85,15 +108,15 @@ GIT_EXTERN(int) git_merge_base(
* *
* @param out the OID of a merge base considering all the commits * @param out the OID of a merge base considering all the commits
* @param repo the repository where the commits exist * @param repo the repository where the commits exist
* @param input_array oids of the commits
* @param length The number of commits in the provided `input_array` * @param length The number of commits in the provided `input_array`
* @param input_array oids of the commits
* @return Zero on success; GIT_ENOTFOUND or -1 on failure. * @return Zero on success; GIT_ENOTFOUND or -1 on failure.
*/ */
GIT_EXTERN(int) git_merge_base_many( GIT_EXTERN(int) git_merge_base_many(
git_oid *out, git_oid *out,
git_repository *repo, git_repository *repo,
const git_oid input_array[], size_t length,
size_t length); const git_oid input_array[]);
/** /**
* Creates a `git_merge_head` from the given reference * Creates a `git_merge_head` from the given reference
...@@ -168,6 +191,43 @@ GIT_EXTERN(int) git_merge_trees( ...@@ -168,6 +191,43 @@ GIT_EXTERN(int) git_merge_trees(
const git_tree *their_tree, const git_tree *their_tree,
const git_merge_tree_opts *opts); const git_merge_tree_opts *opts);
/**
* Merges the given commits into HEAD, producing a new commit.
*
* @param out the results of the merge
* @param repo the repository to merge
* @param merge_heads the heads to merge into
* @param merge_heads_len the number of heads to merge
* @param flags merge flags
*/
GIT_EXTERN(int) git_merge(
git_merge_result **out,
git_repository *repo,
const git_merge_head **their_heads,
size_t their_heads_len,
const git_merge_opts *opts);
/**
* Returns true if a merge is up-to-date (we were asked to merge the target
* into itself.)
*/
GIT_EXTERN(int) git_merge_result_is_uptodate(git_merge_result *merge_result);
/**
* Returns true if a merge is eligible for fastforward
*/
GIT_EXTERN(int) git_merge_result_is_fastforward(git_merge_result *merge_result);
/**
* Gets the fast-forward OID if the merge was a fastforward.
*
* @param out the OID of the fast-forward
* @param merge_result the results of the merge
*/
GIT_EXTERN(int) git_merge_result_fastforward_oid(git_oid *out, git_merge_result *merge_result);
GIT_EXTERN(void) git_merge_result_free(git_merge_result *merge_result);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif
...@@ -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,
...@@ -78,6 +78,23 @@ GIT_EXTERN(int) git_object_lookup_prefix( ...@@ -78,6 +78,23 @@ GIT_EXTERN(int) git_object_lookup_prefix(
size_t len, size_t len,
git_otype type); git_otype type);
/**
* Lookup an object that represents a tree entry.
*
* @param out buffer that receives a pointer to the object (which must be freed
* by the caller)
* @param treeish root object that can be peeled to a tree
* @param path relative path from the root object to the desired object
* @param type type of object desired
* @return 0 on success, or an error code
*/
GIT_EXTERN(int) git_object_lookup_bypath(
git_object **out,
const git_object *treeish,
const char *path,
git_otype type);
/** /**
* Get the id (SHA1) of a repository object * Get the id (SHA1) of a repository 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`
* is called and returns without an error
* *
* The stream must always be free'd or will leak memory. * The stream must always be freed when done with `git_odb_stream_free` 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
...@@ -322,6 +358,20 @@ GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_oty ...@@ -322,6 +358,20 @@ GIT_EXTERN(int) git_odb_hash(git_oid *out, const void *data, size_t len, git_oty
GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_otype type); GIT_EXTERN(int) git_odb_hashfile(git_oid *out, const char *path, git_otype type);
/** /**
* Create a copy of an odb_object
*
* The returned copy must be manually freed with `git_odb_object_free`.
* Note that because of an implementation detail, the returned copy will be
* the same pointer as `source`: the object is internally refcounted, so the
* copy still needs to be freed twice.
*
* @param dest pointer where to store the copy
* @param source object to copy
* @return 0 or an error code
*/
GIT_EXTERN(int) git_odb_object_dup(git_odb_object **dest, git_odb_object *source);
/**
* Close an ODB object * Close an ODB object
* *
* This method must always be called once a `git_odb_object` is no * This method must always be called once a `git_odb_object` is no
......
...@@ -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
...@@ -40,10 +40,18 @@ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_ ...@@ -40,10 +40,18 @@ GIT_EXTERN(int) git_odb_backend_pack(git_odb_backend **out, const char *objects_
* @param objects_dir the Git repository's objects directory * @param objects_dir the Git repository's objects directory
* @param compression_level zlib compression level to use * @param compression_level zlib compression level to use
* @param do_fsync whether to do an fsync() after writing (currently ignored) * @param do_fsync whether to do an fsync() after writing (currently ignored)
* @param dir_mode permissions to use creating a directory or 0 for defaults
* @param file_mode permissions to use creating a file or 0 for defaults
* *
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_odb_backend_loose(git_odb_backend **out, const char *objects_dir, int compression_level, int do_fsync); GIT_EXTERN(int) git_odb_backend_loose(
git_odb_backend **out,
const char *objects_dir,
int compression_level,
int do_fsync,
unsigned int dir_mode,
unsigned int file_mode);
/** /**
* Create a backend out of a single packfile * Create a backend out of a single packfile
...@@ -65,14 +73,50 @@ typedef enum { ...@@ -65,14 +73,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);
}; };
...@@ -80,7 +124,7 @@ struct git_odb_stream { ...@@ -80,7 +124,7 @@ struct git_odb_stream {
struct git_odb_writepack { struct git_odb_writepack {
git_odb_backend *backend; git_odb_backend *backend;
int (*add)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats); int (*append)(git_odb_writepack *writepack, const void *data, size_t size, git_transfer_progress *stats);
int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats); int (*commit)(git_odb_writepack *writepack, git_transfer_progress *stats);
void (*free)(git_odb_writepack *writepack); void (*free)(git_odb_writepack *writepack);
}; };
......
...@@ -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
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
* `git_packbuilder_set_threads` can be used to adjust the number of * `git_packbuilder_set_threads` can be used to adjust the number of
* threads used for the process. * threads used for the process.
* *
* See tests-clar/pack/packbuilder.c for an example. * See tests/pack/packbuilder.c for an example.
* *
* @ingroup Git * @ingroup Git
* @{ * @{
...@@ -46,6 +46,14 @@ ...@@ -46,6 +46,14 @@
GIT_BEGIN_DECL GIT_BEGIN_DECL
/** /**
* Stages that are reported by the packbuilder progress callback.
*/
typedef enum {
GIT_PACKBUILDER_ADDING_OBJECTS = 0,
GIT_PACKBUILDER_DELTAFICATION = 1,
} git_packbuilder_stage_t;
/**
* Initialize a new packbuilder * Initialize a new packbuilder
* *
* @param out The new packbuilder object * @param out The new packbuilder object
...@@ -111,6 +119,7 @@ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid ...@@ -111,6 +119,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 mode permissions to use creating a packfile or 0 for defaults
* @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_cb_payload payload for the progress callback (optional) * @param progress_cb_payload payload for the progress callback (optional)
* *
...@@ -119,9 +128,20 @@ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid ...@@ -119,9 +128,20 @@ GIT_EXTERN(int) git_packbuilder_insert_commit(git_packbuilder *pb, const git_oid
GIT_EXTERN(int) git_packbuilder_write( GIT_EXTERN(int) git_packbuilder_write(
git_packbuilder *pb, git_packbuilder *pb,
const char *path, const char *path,
unsigned int mode,
git_transfer_progress_callback progress_cb, git_transfer_progress_callback progress_cb,
void *progress_cb_payload); void *progress_cb_payload);
/**
* Get the packfile's hash
*
* A packfile's name is derived from the sorted hashing of all object
* names. This is only correct after the packfile has been written.
*
* @param pb The packbuilder object
*/
GIT_EXTERN(const git_oid *) git_packbuilder_hash(git_packbuilder *pb);
typedef int (*git_packbuilder_foreach_cb)(void *buf, size_t size, void *payload); typedef int (*git_packbuilder_foreach_cb)(void *buf, size_t size, void *payload);
/** /**
* Create the new pack and pass each object to the callback * Create the new pack and pass each object to the callback
...@@ -137,7 +157,7 @@ GIT_EXTERN(int) git_packbuilder_foreach(git_packbuilder *pb, git_packbuilder_for ...@@ -137,7 +157,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,10 +165,32 @@ GIT_EXTERN(uint32_t) git_packbuilder_object_count(git_packbuilder *pb); ...@@ -145,10 +165,32 @@ 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);
/** Packbuilder progress notification function */
typedef int (*git_packbuilder_progress)(
int stage,
unsigned int current,
unsigned int total,
void *payload);
/**
* Set the callbacks for a packbuilder
*
* @param pb The packbuilder object
* @param progress_cb Function to call with progress information during
* pack building. Be aware that this is called inline with pack building
* operations, so performance may be affected.
* @param progress_cb_payload Payload for progress callback.
* @return 0 or an error code
*/
GIT_EXTERN(int) git_packbuilder_set_callbacks(
git_packbuilder *pb,
git_packbuilder_progress progress_cb,
void *progress_cb_payload);
/** /**
* Free the packbuilder and all associated data * Free the packbuilder and all associated data
* *
......
/*
* 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_patch_h__
#define INCLUDE_git_patch_h__
#include "common.h"
#include "types.h"
#include "oid.h"
#include "diff.h"
/**
* @file git2/patch.h
* @brief Patch handling routines.
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* The diff patch is used to store all the text diffs for a delta.
*
* You can easily loop over the content of patches and get information about
* them.
*/
typedef struct git_patch git_patch;
/**
* Return the diff delta and patch for an entry in the diff list.
*
* The `git_patch` is a newly created object contains the text diffs
* for the delta. You have to call `git_patch_free()` when you are
* done with it. You can use the patch object to loop over all the hunks
* and lines in the diff of the one delta.
*
* For an unchanged file or a binary file, no `git_patch` will be
* created, the output will be set to NULL, and the `binary` flag will be
* set true in the `git_diff_delta` structure.
*
* The `git_diff_delta` pointer points to internal data and you do not have
* to release it when you are done with it. It will go away when the
* `git_diff` and `git_patch` go away.
*
* It is okay to pass NULL for either of the output parameters; if you pass
* NULL for the `git_patch`, then the text diff will not be calculated.
*
* @param out Output parameter for the delta patch object
* @param diff Diff list object
* @param idx Index into diff list
* @return 0 on success, other value < 0 on error
*/
GIT_EXTERN(int) git_patch_from_diff(
git_patch **out, git_diff *diff, size_t idx);
/**
* Directly generate a patch from the difference between two blobs.
*
* This is just like `git_diff_blobs()` except it generates a patch object
* for the difference instead of directly making callbacks. You can use the
* standard `git_patch` accessor functions to read the patch data, and
* you must call `git_patch_free()` on the patch when done.
*
* @param out The generated patch; NULL on error
* @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_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
*/
GIT_EXTERN(int) git_patch_from_blobs(
git_patch **out,
const git_blob *old_blob,
const char *old_as_path,
const git_blob *new_blob,
const char *new_as_path,
const git_diff_options *opts);
/**
* Directly generate a patch from the difference between a blob and a buffer.
*
* This is just like `git_diff_blob_to_buffer()` except it generates a patch
* object for the difference instead of directly making callbacks. You can
* use the standard `git_patch` accessor functions to read the patch
* data, and you must call `git_patch_free()` on the patch when done.
*
* @param out The generated patch; NULL on error
* @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_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 opts Options for diff, or NULL for default options
* @return 0 on success or error code < 0
*/
GIT_EXTERN(int) git_patch_from_blob_and_buffer(
git_patch **out,
const git_blob *old_blob,
const char *old_as_path,
const char *buffer,
size_t buffer_len,
const char *buffer_as_path,
const git_diff_options *opts);
/**
* Free a git_patch object.
*/
GIT_EXTERN(void) git_patch_free(git_patch *patch);
/**
* Get the delta associated with a patch
*/
GIT_EXTERN(const git_diff_delta *) git_patch_get_delta(git_patch *patch);
/**
* Get the number of hunks in a patch
*/
GIT_EXTERN(size_t) git_patch_num_hunks(git_patch *patch);
/**
* Get line counts of each type in a patch.
*
* This helps imitate a diff --numstat type of output. For that purpose,
* you only need the `total_additions` and `total_deletions` values, but we
* include the `total_context` line count in case you want the total number
* of lines of diff output that will be generated.
*
* All outputs are optional. Pass NULL if you don't need a particular count.
*
* @param total_context Count of context lines in output, can be NULL.
* @param total_additions Count of addition lines in output, can be NULL.
* @param total_deletions Count of deletion lines in output, can be NULL.
* @param patch The git_patch object
* @return 0 on success, <0 on error
*/
GIT_EXTERN(int) git_patch_line_stats(
size_t *total_context,
size_t *total_additions,
size_t *total_deletions,
const git_patch *patch);
/**
* Get the information about a hunk in a patch
*
* Given a patch and a hunk index into the patch, this returns detailed
* information about that hunk. Any of the output pointers can be passed
* as NULL if you don't care about that particular piece of information.
*
* @param out Output pointer to git_diff_hunk of hunk
* @param lines_in_hunk Output count of total lines in this hunk
* @param patch Input pointer to patch object
* @param hunk_idx Input index of hunk to get information about
* @return 0 on success, GIT_ENOTFOUND if hunk_idx out of range, <0 on error
*/
GIT_EXTERN(int) git_patch_get_hunk(
const git_diff_hunk **out,
size_t *lines_in_hunk,
git_patch *patch,
size_t hunk_idx);
/**
* Get the number of lines in a hunk.
*
* @param patch The git_patch object
* @param hunk_idx Index of the hunk
* @return Number of lines in hunk or -1 if invalid hunk index
*/
GIT_EXTERN(int) git_patch_num_lines_in_hunk(
git_patch *patch,
size_t hunk_idx);
/**
* Get data about a line in a hunk of a patch.
*
* Given a patch, a hunk index, and a line index in the hunk, this
* will return a lot of details about that line. If you pass a hunk
* index larger than the number of hunks or a line index larger than
* the number of lines in the hunk, this will return -1.
*
* @param out The git_diff_line data for this line
* @param patch The patch to look in
* @param hunk_idx The index of the hunk
* @param line_of_hunk The index of the line in the hunk
* @return 0 on success, <0 on failure
*/
GIT_EXTERN(int) git_patch_get_line_in_hunk(
const git_diff_line **out,
git_patch *patch,
size_t hunk_idx,
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_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_patch_size(
git_patch *patch,
int include_context,
int include_hunk_headers,
int include_file_headers);
/**
* Serialize the patch to text via callback.
*
* Returning a non-zero value from the callback will terminate the iteration
* and cause this return `GIT_EUSER`.
*
* @param patch A git_patch representing changes to one file
* @param print_cb Callback function to output lines of the patch. Will be
* called for file headers, hunk headers, and diff lines.
* @param payload Reference pointer that will be passed to your callbacks.
* @return 0 on success, GIT_EUSER on non-zero callback, or error code
*/
GIT_EXTERN(int) git_patch_print(
git_patch *patch,
git_diff_line_cb print_cb,
void *payload);
/**
* Get the content of a patch as a single diff text.
*
* @param string Allocated string; caller must free.
* @param patch A git_patch representing changes to one file
* @return 0 on success, <0 on failure.
*/
GIT_EXTERN(int) git_patch_to_str(
char **string,
git_patch *patch);
GIT_END_DECL
/**@}*/
#endif
/*
* 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 *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
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
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