New upstream version 0.99.0+dfsg.1

This commit is contained in:
Utkarsh Gupta 2020-03-14 00:52:48 +05:30
parent b6832cbfa8
commit 0c9c969a9b
641 changed files with 20449 additions and 11180 deletions

View File

@ -1,15 +1,21 @@
; Check http://editorconfig.org/ for more informations ; Check http://editorconfig.org/ for more informations
; Top-most EditorConfig file
root = true root = true
; tab indentation
[*] [*]
indent_style = tab indent_style = tab
tab_width = 8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
; 4-column space indentation [*.yml]
indent_style = space
indent_size = 2
[*.md] [*.md]
indent_style = space indent_style = space
indent_size = 4 indent_size = 4
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.py]
indent_style = space
indent_size = 4

2
.gitignore vendored
View File

@ -33,3 +33,5 @@ tags
mkmf.log mkmf.log
*.profdata *.profdata
*.profraw *.profraw
CMakeSettings.json
.vs

View File

@ -23,6 +23,7 @@ Dmitry Kovega
Emeric Fermas Emeric Fermas
Emmanuel Rodriguez Emmanuel Rodriguez
Eric Myhre Eric Myhre
Erik Aigner
Florian Forster Florian Forster
Holger Weiss Holger Weiss
Ingmar Vanhassel Ingmar Vanhassel

View File

@ -12,7 +12,7 @@
# > cmake --build . --target install # > cmake --build . --target install
PROJECT(libgit2 C) PROJECT(libgit2 C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11) CMAKE_MINIMUM_REQUIRED(VERSION 3.5.1)
CMAKE_POLICY(SET CMP0015 NEW) CMAKE_POLICY(SET CMP0015 NEW)
IF(POLICY CMP0051) IF(POLICY CMP0051)
CMAKE_POLICY(SET CMP0051 NEW) CMAKE_POLICY(SET CMP0051 NEW)
@ -50,21 +50,28 @@ OPTION(BUILD_EXAMPLES "Build library usage example apps" OFF)
OPTION(BUILD_FUZZERS "Build the fuzz targets" OFF) OPTION(BUILD_FUZZERS "Build the fuzz targets" 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" ON)
OPTION(LIBGIT2_FILENAME "Name of the produced binary" OFF) OPTION(LIBGIT2_FILENAME "Name of the produced binary" OFF)
SET(SHA1_BACKEND "CollisionDetection" CACHE STRING
"Backend to use for SHA1. One of Generic, OpenSSL, Win32, CommonCrypto, mbedTLS, CollisionDetection.")
OPTION(USE_SSH "Link with libssh2 to enable SSH support" ON) OPTION(USE_SSH "Link with libssh2 to enable SSH support" ON)
OPTION(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON) OPTION(USE_HTTPS "Enable HTTPS support. Can be set to a specific backend" ON)
OPTION(USE_SHA1 "Enable SHA1. Can be set to CollisionDetection(ON)/HTTPS/Generic" ON)
OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF) OPTION(USE_GSSAPI "Link with libgssapi for SPNEGO auth" OFF)
OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF) OPTION(USE_STANDALONE_FUZZERS "Enable standalone fuzzers (compatible with gcc)" OFF)
OPTION(VALGRIND "Configure build for valgrind" OFF) OPTION(USE_LEAK_CHECKER "Run tests with leak checker" OFF)
OPTION(USE_EXT_HTTP_PARSER "Use system HTTP_Parser if available" ON)
OPTION(DEBUG_POOL "Enable debug pool allocator" OFF) OPTION(DEBUG_POOL "Enable debug pool allocator" OFF)
OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF) OPTION(ENABLE_WERROR "Enable compilation with -Werror" OFF)
OPTION(USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF) OPTION(USE_BUNDLED_ZLIB "Use the bundled version of zlib" OFF)
SET(USE_HTTP_PARSER "" CACHE STRING "Specifies the HTTP Parser implementation; either system or builtin.")
OPTION(DEPRECATE_HARD "Do not include deprecated functions in the library" OFF) OPTION(DEPRECATE_HARD "Do not include deprecated functions in the library" OFF)
SET(REGEX_BACKEND "" CACHE STRING "Regular expression implementation. One of regcomp_l, pcre2, pcre, regcomp, or builtin.")
IF (UNIX)
IF (NOT USE_HTTPS)
OPTION(USE_NTLMCLIENT "Enable NTLM support on Unix." OFF )
ELSE()
OPTION(USE_NTLMCLIENT "Enable NTLM support on Unix." ON )
ENDIF()
ENDIF()
IF (UNIX AND NOT APPLE) IF (UNIX AND NOT APPLE)
OPTION(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF) OPTION(ENABLE_REPRODUCIBLE_BUILDS "Enable reproducible builds" OFF)
@ -103,8 +110,8 @@ STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_V
STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_REV "${GIT2_HEADER}")
SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}") SET(LIBGIT2_VERSION_STRING "${LIBGIT2_VERSION_MAJOR}.${LIBGIT2_VERSION_MINOR}.${LIBGIT2_VERSION_REV}")
FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION [0-9]+$") FILE(STRINGS "${libgit2_SOURCE_DIR}/include/git2/version.h" GIT2_HEADER_SOVERSION REGEX "^#define LIBGIT2_SOVERSION \"([0-9.]+)\"$")
STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION ([0-9]+)$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}") STRING(REGEX REPLACE "^.*LIBGIT2_SOVERSION \"([0-9.]+)\"$" "\\1" LIBGIT2_SOVERSION "${GIT2_HEADER_SOVERSION}")
IF (DEPRECATE_HARD) IF (DEPRECATE_HARD)
ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD) ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD)
@ -232,10 +239,22 @@ ELSE ()
ENABLE_WARNINGS(shift-count-overflow) ENABLE_WARNINGS(shift-count-overflow)
ENABLE_WARNINGS(unused-const-variable) ENABLE_WARNINGS(unused-const-variable)
ENABLE_WARNINGS(unused-function) ENABLE_WARNINGS(unused-function)
ENABLE_WARNINGS(format)
ENABLE_WARNINGS(format-security)
ENABLE_WARNINGS(int-conversion) ENABLE_WARNINGS(int-conversion)
DISABLE_WARNINGS(documentation-deprecated-sync)
# MinGW uses gcc, which expects POSIX formatting for printf, but
# uses the Windows C library, which uses its own format specifiers.
# Disable format specifier warnings.
IF(MINGW)
DISABLE_WARNINGS(format)
DISABLE_WARNINGS(format-security)
ELSE()
ENABLE_WARNINGS(format)
ENABLE_WARNINGS(format-security)
ENDIF()
IF("${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")
DISABLE_WARNINGS(documentation-deprecated-sync)
ENDIF()
IF (PROFILE) IF (PROFILE)
SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}") SET(CMAKE_C_FLAGS "-pg ${CMAKE_C_FLAGS}")
@ -243,6 +262,11 @@ ELSE ()
ENDIF () ENDIF ()
ENDIF() ENDIF()
# Ensure that MinGW provides the correct header files.
IF (WIN32 AND NOT CYGWIN)
ADD_DEFINITIONS(-DWIN32 -D_WIN32_WINNT=0x0600)
ENDIF()
IF( NOT CMAKE_CONFIGURATION_TYPES ) IF( NOT CMAKE_CONFIGURATION_TYPES )
# Build Debug by default # Build Debug by default
IF (NOT CMAKE_BUILD_TYPE) IF (NOT CMAKE_BUILD_TYPE)
@ -310,10 +334,5 @@ IF(BUILD_FUZZERS)
ADD_SUBDIRECTORY(fuzzers) ADD_SUBDIRECTORY(fuzzers)
ENDIF() ENDIF()
IF(CMAKE_VERSION VERSION_GREATER 3) FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:")
FEATURE_SUMMARY(WHAT ENABLED_FEATURES DESCRIPTION "Enabled features:") FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
FEATURE_SUMMARY(WHAT DISABLED_FEATURES DESCRIPTION "Disabled features:")
ELSE()
PRINT_ENABLED_FEATURES()
PRINT_DISABLED_FEATURES()
ENDIF()

28
COPYING
View File

@ -991,3 +991,31 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
----------------------------------------------------------------------
The bundled wildmatch code is licensed under the BSD license:
Copyright Rich Salz.
All rights reserved.
Redistribution and use in any form are permitted provided that the
following restrictions are are met:
1. Source distributions must retain this entire copyright notice
and comment.
2. Binary distributions must include the acknowledgement ``This
product includes software developed by Rich Salz'' in the
documentation or other materials provided with the
distribution. This must not be represented as an endorsement
or promotion without specific prior written permission.
3. The origin of this software must not be misrepresented, either
by explicit claim or by omission. Credits must appear in the
source and documentation.
4. Altered versions must be plainly marked as such in the source
and documentation and must not be misrepresented as being the
original software.
THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.

View File

@ -73,17 +73,17 @@ Quick Start
2. Create the cmake build environment: `cmake ..` 2. Create the cmake build environment: `cmake ..`
3. Build libgit2: `cmake --build .` 3. Build libgit2: `cmake --build .`
Trouble with these steps? Read our (troubleshooting guide)[docs/troubleshooting.md]. Trouble with these steps? Read our [troubleshooting guide](docs/troubleshooting.md).
More detailed build guidance is available below. More detailed build guidance is available below.
Getting Help Getting Help
============ ============
**Join us on Slack** **Chat with us**
Visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up, then join - via IRC: join [#libgit2](https://webchat.freenode.net/#libgit2) on Freenode
us in `#libgit2`. If you prefer IRC, you can also point your client to our - via Slack: visit [slack.libgit2.org](http://slack.libgit2.org/) to sign up,
slack channel once you've registered. then join us in `#libgit2`
**Getting Help** **Getting Help**
@ -103,9 +103,7 @@ We ask that you not open a GitHub Issue for help, only for bug reports.
**Reporting Security Issues** **Reporting Security Issues**
In case you think to have found a security issue with libgit2, please do not Please have a look at SECURITY.md.
open a public issue. Instead, you can report the issue to the private mailing
list [security@libgit2.com](mailto:security@libgit2.com).
What It Can Do What It Can Do
============== ==============
@ -333,7 +331,7 @@ Here are the bindings to libgit2 that are currently available:
* Java * Java
* Jagged <https://github.com/ethomson/jagged> * Jagged <https://github.com/ethomson/jagged>
* Julia * Julia
* LibGit2.jl <https://github.com/jakebolewski/LibGit2.jl> * LibGit2.jl <https://github.com/JuliaLang/julia/tree/master/stdlib/LibGit2>
* Lua * Lua
* luagit2 <https://github.com/libgit2/luagit2> * luagit2 <https://github.com/libgit2/luagit2>
* .NET * .NET
@ -359,7 +357,7 @@ Here are the bindings to libgit2 that are currently available:
* Ruby * Ruby
* Rugged <https://github.com/libgit2/rugged> * Rugged <https://github.com/libgit2/rugged>
* Rust * Rust
* git2-rs <https://github.com/alexcrichton/git2-rs> * git2-rs <https://github.com/rust-lang/git2-rs>
* Swift * Swift
* SwiftGit2 <https://github.com/SwiftGit2/SwiftGit2> * SwiftGit2 <https://github.com/SwiftGit2/SwiftGit2>
* Vala * Vala

14
SECURITY.md Normal file
View File

@ -0,0 +1,14 @@
# Security Policy
## Supported Versions
This project will always provide security fixes for the latest two released
versions. E.g. if the latest version is v0.28.x, then we will provide security
fixes for both v0.28.x and v0.27.y, but no later versions.
## Reporting a Vulnerability
In case you think to have found a security issue with libgit2, please do not
open a public issue. Instead, you can report the issue to the private mailing
list [security@libgit2.com](mailto:security@libgit2.com). We will acknowledge
receipt of your message in at most three days and try to clarify further steps.

View File

@ -6,134 +6,165 @@ trigger:
- maint/* - maint/*
jobs: jobs:
- job: linux_amd64_trusty_gcc_openssl - job: linux_amd64_xenial_gcc_openssl
displayName: 'Linux (amd64; Trusty; GCC; OpenSSL)' displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: azure-pipelines/docker.yml - template: azure-pipelines/docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: linux_amd64_trusty_gcc_mbedtls - job: linux_amd64_xenial_gcc_mbedtls
displayName: 'Linux (amd64; Trusty; GCC; mbedTLS)' displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: azure-pipelines/docker.yml - template: azure-pipelines/docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: linux_amd64_trusty_clang_openssl - job: linux_amd64_xenial_clang_openssl
displayName: 'Linux (amd64; Trusty; Clang; OpenSSL)' displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: azure-pipelines/docker.yml - template: azure-pipelines/docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=clang CC=clang
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: linux_amd64_trusty_clang_mbedtls - job: linux_amd64_xenial_clang_mbedtls
displayName: 'Linux (amd64; Trusty; Clang; mbedTLS)' displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: azure-pipelines/docker.yml - template: azure-pipelines/docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=clang CC=clang
CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind -DUSE_GSSAPI=ON
GITTEST_NEGOTIATE_PASSWORD=${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: macos - job: macos
displayName: 'macOS' displayName: 'macOS'
pool: pool:
vmImage: 'macOS 10.13' vmImage: 'macOS 10.13'
steps: steps:
- bash: . '$(Build.SourcesDirectory)/ci/setup-osx.sh' - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
displayName: Setup displayName: Setup
- template: azure-pipelines/bash.yml - template: azure-pipelines/bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
TMPDIR: $(Agent.TempDirectory) TMPDIR: $(Agent.TempDirectory)
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
LEAK_CHECK: leaks CMAKE_GENERATOR: Ninja
CMAKE_OPTIONS: -G Ninja -DDEPRECATE_HARD=ON CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
SKIP_SSH_TESTS: true SKIP_SSH_TESTS: true
GITTEST_NEGOTIATE_PASSWORD: ${{ variables.GITTEST_NEGOTIATE_PASSWORD }}
- job: windows_vs_amd64 - job: windows_vs_amd64
displayName: 'Windows (amd64; Visual Studio)' displayName: 'Windows (amd64; Visual Studio)'
pool: Hosted pool: Hosted
steps: steps:
- template: azure-pipelines/powershell.yml - template: azure-pipelines/bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013 Win64" -DDEPRECATE_HARD=ON CMAKE_GENERATOR: Visual Studio 12 2013 Win64
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
- job: windows_vs_x86 - job: windows_vs_x86
displayName: 'Windows (x86; Visual Studio)' displayName: 'Windows (x86; Visual Studio)'
pool: Hosted pool: Hosted
steps: steps:
- template: azure-pipelines/powershell.yml - template: azure-pipelines/bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013" -DDEPRECATE_HARD=ON CMAKE_GENERATOR: Visual Studio 12 2013
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
- job: windows_mingw_amd64 - job: windows_mingw_amd64
displayName: 'Windows (amd64; MinGW)' displayName: 'Windows (amd64; MinGW)'
pool: Hosted pool: Hosted
steps: steps:
- powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1' - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup displayName: Setup
env: env:
TEMP: $(Agent.TempDirectory) TEMP: $(Agent.TempDirectory)
ARCH: amd64 ARCH: amd64
- template: azure-pipelines/powershell.yml - template: azure-pipelines/bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
PATH: $(Agent.TempDirectory)\mingw64\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin CMAKE_GENERATOR: MinGW Makefiles
CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
- job: windows_mingw_x86 - job: windows_mingw_x86
displayName: 'Windows (x86; MinGW)' displayName: 'Windows (x86; MinGW)'
pool: Hosted pool: Hosted
steps: steps:
- powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1' - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup displayName: Setup
workingDirectory: '$(Build.BinariesDirectory)' workingDirectory: '$(Build.BinariesDirectory)'
env: env:
TEMP: $(Agent.TempDirectory) TEMP: $(Agent.TempDirectory)
ARCH: x86 ARCH: x86
- template: azure-pipelines/powershell.yml - template: azure-pipelines/bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
PATH: $(Agent.TempDirectory)\mingw32\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin CMAKE_GENERATOR: MinGW Makefiles
CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
SKIP_SSH_TESTS: true
SKIP_NEGOTIATE_TESTS: true
- job: documentation - job: documentation
displayName: 'Generate Documentation' displayName: 'Generate Documentation'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- script: |
cd $(Build.SourcesDirectory)/azure-pipelines/docker
docker build -t libgit2/docurium --build-arg BASE=ubuntu:trusty -f docurium .
displayName: 'Build Docker image'
- script: | - script: |
git config user.name 'Documentation Generation' git config user.name 'Documentation Generation'
git config user.email 'noreply@libgit2.org' git config user.email 'libgit2@users.noreply.github.com'
docker run --rm -v /home/vsts/work/1/s:/src -w /src libgit2/docurium:test cm doc api.docurium git branch gh-pages origin/gh-pages
docker run --rm -v $(Build.SourcesDirectory):/home/libgit2/source -w /home/libgit2/source libgit2/docurium:latest cm doc api.docurium
git checkout gh-pages git checkout gh-pages
cp -R * '$(Build.BinariesDirectory)' cp -R * '$(Build.BinariesDirectory)'
displayName: 'Generate Documentation'
- task: archivefiles@2 - task: archivefiles@2
displayName: 'Archive Documentation' displayName: 'Archive Documentation'
inputs: inputs:
@ -141,7 +172,15 @@ jobs:
includeRootFolder: false includeRootFolder: false
archiveFile: '$(Build.ArtifactStagingDirectory)/api-documentation.zip' archiveFile: '$(Build.ArtifactStagingDirectory)/api-documentation.zip'
- task: publishbuildartifacts@1 - task: publishbuildartifacts@1
displayName: 'Upload Documentation' displayName: 'Upload Documentation Artifact'
inputs: inputs:
pathToPublish: '$(Build.ArtifactStagingDirectory)' pathToPublish: '$(Build.ArtifactStagingDirectory)'
artifactName: 'docs' artifactName: 'docs'
- script: |
git remote -v
echo 'machine github.com' > ~/.netrc
echo 'login $(GITHUB_USERNAME)' >> ~/.netrc
echo 'password $(GITHUB_PAT)' >> ~/.netrc
git push origin gh-pages
displayName: 'Publish Documentation'
condition: and(eq(variables['Build.Repository.Name'], 'libgit2/libgit2'), eq(variables['Build.Reason'], 'IndividualCI'))

View File

@ -1,10 +1,10 @@
# These are the steps used for building on machines with bash. # These are the steps used for building on machines with bash.
steps: steps:
- bash: . '$(Build.SourcesDirectory)/ci/build.sh' - bash: . '$(Build.SourcesDirectory)/azure-pipelines/build.sh'
displayName: Build displayName: Build
workingDirectory: '$(Build.BinariesDirectory)' workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }} env: ${{ parameters.environmentVariables }}
- bash: . '$(Build.SourcesDirectory)/ci/test.sh' - bash: . '$(Build.SourcesDirectory)/azure-pipelines/test.sh'
displayName: Test displayName: Test
workingDirectory: '$(Build.BinariesDirectory)' workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }} env: ${{ parameters.environmentVariables }}

View File

@ -9,7 +9,9 @@ set -e
SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )} SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
BUILD_DIR=$(pwd) BUILD_DIR=$(pwd)
CC=${CC:-cc} BUILD_PATH=${BUILD_PATH:=$PATH}
CMAKE=$(which cmake)
CMAKE_GENERATOR=${CMAKE_GENERATOR:-Unix Makefiles}
indent() { sed "s/^/ /"; } indent() { sed "s/^/ /"; }
@ -24,28 +26,31 @@ fi
if [ -f "/etc/debian_version" ]; then if [ -f "/etc/debian_version" ]; then
echo "Debian version:" echo "Debian version:"
lsb_release -a | indent (source /etc/lsb-release && echo "${DISTRIB_DESCRIPTION}") | indent
fi fi
echo "Kernel version:" echo "Kernel version:"
uname -a 2>&1 | indent uname -a 2>&1 | indent
echo "CMake version:" echo "CMake version:"
cmake --version 2>&1 | indent env PATH="$BUILD_PATH" "$CMAKE" --version 2>&1 | indent
echo "Compiler version:"
$CC --version 2>&1 | indent if test -n "$CC"; then
echo "Compiler version:"
"$CC" --version 2>&1 | indent
fi
echo "" echo ""
echo "##############################################################################" echo "##############################################################################"
echo "## Configuring build environment" echo "## Configuring build environment"
echo "##############################################################################" echo "##############################################################################"
echo cmake ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON ${CMAKE_OPTIONS} echo cmake ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G \"${CMAKE_GENERATOR}\" ${CMAKE_OPTIONS}
cmake ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON ${CMAKE_OPTIONS} env PATH="$BUILD_PATH" "$CMAKE" ${SOURCE_DIR} -DENABLE_WERROR=ON -DBUILD_EXAMPLES=ON -DBUILD_FUZZERS=ON -DUSE_STANDALONE_FUZZERS=ON -G "${CMAKE_GENERATOR}" ${CMAKE_OPTIONS}
echo "" echo ""
echo "##############################################################################" echo "##############################################################################"
echo "## Building libgit2" echo "## Building libgit2"
echo "##############################################################################" echo "##############################################################################"
cmake --build . env PATH="$BUILD_PATH" "$CMAKE" --build .

62
azure-pipelines/coverity.sh Executable file
View File

@ -0,0 +1,62 @@
#!/bin/bash -e
if test -z "$COVERITY_TOKEN"
then
echo "Need to set a coverity token"
exit 1
fi
case $(uname -m) in
i?86)
BITS=32;;
amd64|x86_64)
BITS=64;;
*)
echo "Unsupported arch '$(uname -m)'"
exit 1;;
esac
SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
SOURCE_DIR=$(realpath "$(dirname "${BASH_SOURCE[0]}")"/..)
BUILD_DIR=${SOURCE_DIR}/coverity-build
TOOL_DIR=${BUILD_DIR}/coverity-tools
# Install coverity tools
if ! test -d "$TOOL_DIR"
then
mkdir -p "$TOOL_DIR"
curl --silent --location --data "project=libgit2&token=$COVERITY_TOKEN" "$SCAN_TOOL" |
tar -xzC "$TOOL_DIR"
ln -s "$(find "$TOOL_DIR" -type d -name 'cov-analysis*')" "$TOOL_DIR"/cov-analysis
fi
cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_DIR"/cov-analysis/config/
# Build libgit2 with Coverity
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
cmake "$SOURCE_DIR"
COVERITY_UNSUPPORTED=1 \
"$TOOL_DIR/cov-analysis/bin/cov-build" --dir cov-int \
cmake --build .
# Upload results
tar -czf libgit2.tgz cov-int
REVISION=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
HTML="$(curl \
--silent \
--write-out "\n%{http_code}" \
--form token="$COVERITY_TOKEN" \
--form email=libgit2@gmail.com \
--form file=@libgit2.tgz \
--form version="$REVISION" \
--form description="libgit2 build" \
https://scan.coverity.com/builds?project=libgit2)"
# Status code is the last line
STATUS_CODE="$(echo "$HTML" | tail -n1)"
if test "${STATUS_CODE}" != 200 && test "${STATUS_CODE}" != 201
then
echo "Received error code ${STATUS_CODE} from Coverity"
exit 1
fi

View File

@ -7,30 +7,20 @@ jobs:
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- script: |
cd $(Build.SourcesDirectory)/azure-pipelines/docker
docker build -t libgit2/xenial --build-arg BASE=ubuntu:xenial -f xenial .
displayName: 'Build Docker image'
- task: Docker@0 - task: Docker@0
displayName: Build displayName: Analyze
inputs: inputs:
action: 'Run an image' action: 'Run an image'
imageName: 'libgit2/trusty-openssl:latest' imageName: libgit2/xenial
volumes: | volumes: |
$(Build.SourcesDirectory):/src $(Build.SourcesDirectory):/home/libgit2/source
$(Build.BinariesDirectory):/build $(Build.BinariesDirectory):/home/libgit2/build
envVars: | envVars: |
COVERITY_TOKEN=$(COVERITY_TOKEN) COVERITY_TOKEN=$(COVERITY_TOKEN)
workDir: '/build' workDir: '/home/libgit2/build'
containerCommand: '/src/ci/coverity-build.sh' containerCommand: '/home/libgit2/source/azure-pipelines/coverity.sh'
detached: false detached: false
- task: Docker@0
displayName: Publish
inputs:
action: 'Run an image'
imageName: 'libgit2/trusty-openssl:latest'
volumes: |
$(Build.SourcesDirectory):/src
$(Build.BinariesDirectory):/build
envVars: |
COVERITY_TOKEN=$(COVERITY_TOKEN)
workDir: '/build'
containerCommand: '/src/ci/coverity-publish.sh'
detached: false
continueOnError: true

View File

@ -4,29 +4,43 @@ steps:
- script: docker run --rm --privileged multiarch/qemu-user-static:register --reset - script: docker run --rm --privileged multiarch/qemu-user-static:register --reset
displayName: 'Register Docker QEMU' displayName: 'Register Docker QEMU'
- task: cache@2
displayName: Cache Docker layers
inputs:
key: docker
path: /tmp/dockercache
- script: |
if [ -f /tmp/dockercache/${{parameters.docker.image}}.tar ]; then docker load < /tmp/dockercache/${{parameters.docker.image}}.tar; fi
displayName: 'Load Docker cache'
- script: |
cd $(Build.SourcesDirectory)/azure-pipelines/docker &&
docker build -t libgit2/${{parameters.docker.image}} --build-arg BASE=${{parameters.docker.base}} -f ${{parameters.docker.image}} . &&
if [ ! -d /tmp/dockercache ]; then mkdir /tmp/dockercache; fi &&
docker save libgit2/${{parameters.docker.image}} $(docker history -q libgit2/${{parameters.docker.image}} | grep -v '<missing>') > /tmp/dockercache/${{parameters.docker.image}}.tar
displayName: 'Build Docker image'
- task: docker@0 - task: docker@0
displayName: Build displayName: Build
inputs: inputs:
action: 'Run an image' action: 'Run an image'
imageName: ${{ parameters.imageName }} imageName: libgit2/${{ parameters.docker.image }}
volumes: | volumes: |
$(Build.SourcesDirectory):/src $(Build.SourcesDirectory):/home/libgit2/source
$(Build.BinariesDirectory):/build $(Build.BinariesDirectory):/home/libgit2/build
envVars: ${{ parameters.environmentVariables }} envVars: ${{ parameters.environmentVariables }}
workDir: '/build' workDir: '/home/libgit2/build'
containerCommand: '/src/ci/build.sh' containerCommand: '/home/libgit2/source/azure-pipelines/build.sh'
detached: false detached: false
- task: docker@0 - task: docker@0
displayName: Test displayName: Test
inputs: inputs:
action: 'Run an image' action: 'Run an image'
imageName: ${{ parameters.imageName }} imageName: libgit2/${{ parameters.docker.image }}
volumes: | volumes: |
$(Build.SourcesDirectory):/src $(Build.SourcesDirectory):/home/libgit2/source
$(Build.BinariesDirectory):/build $(Build.BinariesDirectory):/home/libgit2/build
envVars: ${{ parameters.environmentVariables }} envVars: ${{ parameters.environmentVariables }}
workDir: '/build' workDir: '/home/libgit2/build'
containerCommand: '/src/ci/test.sh' containerCommand: '/home/libgit2/source/azure-pipelines/test.sh'
detached: false detached: false
- task: publishtestresults@2 - task: publishtestresults@2
displayName: Publish Test Results displayName: Publish Test Results

View File

@ -0,0 +1,42 @@
ARG BASE
FROM $BASE AS apt
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
clang \
cmake \
curl \
gcc \
git \
libcurl4-openssl-dev \
libpcre3-dev \
libssh2-1-dev \
libssl-dev \
libz-dev \
ninja-build \
openjdk-8-jre-headless \
openssh-server \
openssl \
pkgconf \
python \
sudo \
valgrind \
&& \
rm -rf /var/lib/apt/lists/*
FROM apt AS mbedtls
RUN cd /tmp && \
curl --location --silent https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
tar -xz && \
cd mbedtls-2.16.2 && \
scripts/config.pl set MBEDTLS_MD4_C 1 && \
CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
ninja install && \
cd .. && \
rm -rf mbedtls-2.16.2
FROM mbedtls AS configure
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod a+x /usr/local/bin/entrypoint.sh
RUN mkdir /var/run/sshd
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View File

@ -0,0 +1,6 @@
FROM debian:jessie-slim
ARG CACHEBUST=1
RUN apt-get update
RUN apt install -y cmake pkg-config ruby ruby-dev llvm libclang-3.5-dev libssl-dev python-pygments
ARG CACHEBUST=1
RUN gem install docurium

View File

@ -0,0 +1,4 @@
#!/bin/bash -e
useradd --shell /bin/bash libgit2
chown --recursive libgit2:libgit2 /home/libgit2
exec sudo --preserve-env --user=libgit2 "$@"

View File

@ -0,0 +1,67 @@
ARG BASE
FROM $BASE AS apt
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
bzip2 \
clang \
cmake \
curl \
gcc \
git \
krb5-user \
libcurl4-gnutls-dev \
libgcrypt20-dev \
libkrb5-dev \
libpcre3-dev \
libssl-dev \
libz-dev \
make \
ninja-build \
openjdk-8-jre-headless \
openssh-server \
openssl \
pkgconf \
python \
sudo \
valgrind \
&& \
rm -rf /var/lib/apt/lists/*
FROM apt AS mbedtls
RUN cd /tmp && \
curl --location --silent https://tls.mbed.org/download/mbedtls-2.16.2-apache.tgz | \
tar -xz && \
cd mbedtls-2.16.2 && \
scripts/config.pl set MBEDTLS_MD4_C 1 && \
CFLAGS=-fPIC cmake -G Ninja -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON . && \
ninja install && \
cd .. && \
rm -rf mbedtls-2.16.2
FROM mbedtls AS libssh2
RUN cd /tmp && \
curl --location --silent https://www.libssh2.org/download/libssh2-1.8.2.tar.gz | \
tar -xz && \
cd libssh2-1.8.2 && \
CFLAGS=-fPIC cmake -G Ninja -DBUILD_SHARED_LIBS=ON -DCRYPTO_BACKEND=Libgcrypt . && \
ninja install && \
cd .. && \
rm -rf libssh2-1.8.2
FROM libssh2 AS valgrind
RUN cd /tmp && \
curl --location --silent https://sourceware.org/pub/valgrind/valgrind-3.15.0.tar.bz2 | \
tar -xj && \
cd valgrind-3.15.0 && \
./configure && \
make && \
make install && \
cd .. && \
rm -rf valgrind-3.15.0
FROM valgrind AS configure
COPY entrypoint.sh /usr/local/bin/entrypoint.sh
RUN chmod a+x /usr/local/bin/entrypoint.sh
RUN mkdir /var/run/sshd
ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

View File

@ -2,60 +2,68 @@ resources:
- repo: self - repo: self
jobs: jobs:
- job: linux_amd64_trusty_gcc_openssl - job: linux_amd64_xenial_gcc_openssl
displayName: 'Linux (amd64; Trusty; GCC; OpenSSL)' displayName: 'Linux (amd64; Xenial; GCC; OpenSSL)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: docker.yml - template: docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DREGEX_BACKEND=builtin -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: linux_amd64_trusty_gcc_mbedtls - job: linux_amd64_xenial_gcc_mbedtls
displayName: 'Linux (amd64; Trusty; GCC; mbedTLS)' displayName: 'Linux (amd64; Xenial; GCC; mbedTLS)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: docker.yml - template: docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: linux_amd64_trusty_clang_openssl - job: linux_amd64_xenial_clang_openssl
displayName: 'Linux (amd64; Trusty; Clang; OpenSSL)' displayName: 'Linux (amd64; Xenial; Clang; OpenSSL)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: docker.yml - template: docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=clang CC=clang
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: linux_amd64_trusty_clang_mbedtls - job: linux_amd64_xenial_clang_mbedtls
displayName: 'Linux (amd64; Trusty; Clang; mbedTLS)' displayName: 'Linux (amd64; Xenial; Clang; mbedTLS)'
pool: pool:
vmImage: 'Ubuntu 16.04' vmImage: 'Ubuntu 16.04'
steps: steps:
- template: docker.yml - template: docker.yml
parameters: parameters:
imageName: 'libgit2/trusty-amd64:latest' docker:
image: xenial
base: ubuntu:xenial
environmentVariables: | environmentVariables: |
CC=clang CC=clang
CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DSHA1_BACKEND=mbedTLS -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=mbedTLS -DUSE_SHA1=HTTPS -DREGEX_BACKEND=pcre -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: macos - job: macos
@ -63,15 +71,15 @@ jobs:
pool: pool:
vmImage: 'macOS 10.13' vmImage: 'macOS 10.13'
steps: steps:
- bash: . '$(Build.SourcesDirectory)/ci/setup-osx.sh' - bash: . '$(Build.SourcesDirectory)/azure-pipelines/setup-osx.sh'
displayName: Setup displayName: Setup
- template: bash.yml - template: bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
TMPDIR: $(Agent.TempDirectory) TMPDIR: $(Agent.TempDirectory)
PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig PKG_CONFIG_PATH: /usr/local/opt/openssl/lib/pkgconfig
LEAK_CHECK: leaks CMAKE_GENERATOR: Ninja
CMAKE_OPTIONS: -G Ninja -DDEPRECATE_HARD=ON CMAKE_OPTIONS: -DREGEX_BACKEND=regcomp_l -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=leaks -DUSE_GSSAPI=ON
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true SKIP_SSH_TESTS: true
@ -79,54 +87,62 @@ jobs:
displayName: 'Windows (amd64; Visual Studio)' displayName: 'Windows (amd64; Visual Studio)'
pool: Hosted pool: Hosted
steps: steps:
- template: powershell.yml - template: bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013 Win64" -DDEPRECATE_HARD=ON CMAKE_GENERATOR: Visual Studio 12 2013 Win64
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true
- job: windows_vs_x86 - job: windows_vs_x86
displayName: 'Windows (x86; Visual Studio)' displayName: 'Windows (x86; Visual Studio)'
pool: Hosted pool: Hosted
steps: steps:
- template: powershell.yml - template: bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -G"Visual Studio 12 2013" -DDEPRECATE_HARD=ON CMAKE_GENERATOR: Visual Studio 12 2013
CMAKE_OPTIONS: -DMSVC_CRTDBG=ON -DDEPRECATE_HARD=ON -DUSE_SHA1=HTTPS
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true
- job: windows_mingw_amd64 - job: windows_mingw_amd64
displayName: 'Windows (amd64; MinGW)' displayName: 'Windows (amd64; MinGW)'
pool: Hosted pool: Hosted
steps: steps:
- powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1' - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup displayName: Setup
env: env:
TEMP: $(Agent.TempDirectory) TEMP: $(Agent.TempDirectory)
ARCH: amd64 ARCH: amd64
- template: powershell.yml - template: bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON BUILD_PATH: $(Agent.TempDirectory)\mingw64\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
PATH: $(Agent.TempDirectory)\mingw64\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin CMAKE_GENERATOR: MinGW Makefiles
CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true
- job: windows_mingw_x86 - job: windows_mingw_x86
displayName: 'Windows (x86; MinGW)' displayName: 'Windows (x86; MinGW)'
pool: Hosted pool: Hosted
steps: steps:
- powershell: . '$(Build.SourcesDirectory)\ci\setup-mingw.ps1' - bash: . '$(Build.SourcesDirectory)\azure-pipelines\setup-mingw.sh'
displayName: Setup displayName: Setup
workingDirectory: '$(Build.BinariesDirectory)' workingDirectory: '$(Build.BinariesDirectory)'
env: env:
TEMP: $(Agent.TempDirectory) TEMP: $(Agent.TempDirectory)
ARCH: x86 ARCH: x86
- template: powershell.yml - template: bash.yml
parameters: parameters:
environmentVariables: environmentVariables:
CMAKE_OPTIONS: -G"MinGW Makefiles" -DDEPRECATE_HARD=ON BUILD_PATH: $(Agent.TempDirectory)\mingw32\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Program Files (x86)\CMake\bin
PATH: $(Agent.TempDirectory)\mingw32\bin;C:\ProgramData\Oracle\Java\javapath;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\CMake\bin CMAKE_GENERATOR: MinGW Makefiles
CMAKE_OPTIONS: -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS: true RUN_INVASIVE_TESTS: true
SKIP_SSH_TESTS: true
- job: linux_x86_bionic_gcc_openssl - job: linux_x86_bionic_gcc_openssl
displayName: 'Linux (x86; Bionic; GCC; OpenSSL)' displayName: 'Linux (x86; Bionic; GCC; OpenSSL)'
@ -136,11 +152,13 @@ jobs:
- template: docker.yml - template: docker.yml
parameters: parameters:
qemu: 'true' qemu: 'true'
imageName: 'libgit2/bionic-x86:latest' docker:
image: bionic
base: multiarch/ubuntu-core:x86-bionic
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: linux_x86_bionic_clang_openssl - job: linux_x86_bionic_clang_openssl
@ -151,11 +169,13 @@ jobs:
- template: docker.yml - template: docker.yml
parameters: parameters:
qemu: 'true' qemu: 'true'
imageName: 'libgit2/bionic-x86:latest' docker:
image: bionic
base: multiarch/ubuntu-core:x86-bionic
environmentVariables: | environmentVariables: |
CC=clang CC=clang
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_GENERATOR=Ninja
LEAK_CHECK=valgrind CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON -DUSE_LEAK_CHECKER=valgrind
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
- job: linux_arm32_bionic_gcc_openssl - job: linux_arm32_bionic_gcc_openssl
@ -166,9 +186,12 @@ jobs:
- template: docker.yml - template: docker.yml
parameters: parameters:
qemu: 'true' qemu: 'true'
imageName: 'libgit2/bionic-arm32:latest' docker:
image: bionic
base: multiarch/ubuntu-core:armhf-bionic
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_GENERATOR=Ninja
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
SKIP_PROXY_TESTS=true SKIP_PROXY_TESTS=true
@ -181,9 +204,12 @@ jobs:
- template: docker.yml - template: docker.yml
parameters: parameters:
qemu: 'true' qemu: 'true'
imageName: 'libgit2/bionic-arm64:latest' docker:
image: bionic
base: multiarch/ubuntu-core:arm64-bionic
environmentVariables: | environmentVariables: |
CC=gcc CC=gcc
CMAKE_GENERATOR=Ninja
CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON CMAKE_OPTIONS=-DUSE_HTTPS=OpenSSL -DDEPRECATE_HARD=ON
RUN_INVASIVE_TESTS=true RUN_INVASIVE_TESTS=true
SKIP_PROXY_TESTS=true SKIP_PROXY_TESTS=true

View File

@ -1,17 +0,0 @@
# These are the steps used for building on machines with PowerShell.
steps:
- powershell: . '$(Build.SourcesDirectory)\ci\build.ps1'
displayName: Build
workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }}
- powershell: . '$(Build.SourcesDirectory)\ci\test.ps1'
displayName: Test
workingDirectory: '$(Build.BinariesDirectory)'
env: ${{ parameters.environmentVariables }}
- task: PublishTestResults@2
displayName: Publish Test Results
condition: succeededOrFailed()
inputs:
testResultsFiles: 'results_*.xml'
searchFolder: '$(Build.BinariesDirectory)'
mergeTestResults: true

15
azure-pipelines/setup-mingw.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh -e
echo "##############################################################################"
echo "## Downloading mingw"
echo "##############################################################################"
case "$ARCH" in
amd64)
MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-x86_64-8.1.0-release-win32-seh-rt_v6-rev0.zip";;
x86)
MINGW_URI="https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip";;
esac
curl -s -L "$MINGW_URI" -o "$TEMP"/mingw-"$ARCH".zip
unzip -q "$TEMP"/mingw-"$ARCH".zip -d "$TEMP"

View File

@ -6,6 +6,11 @@ if [ -n "$SKIP_TESTS" ]; then
exit 0 exit 0
fi fi
# Windows doesn't run the NTLM tests properly (yet)
if [[ "$(uname -s)" == MINGW* ]]; then
SKIP_NTLM_TESTS=1
fi
SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )} SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
BUILD_DIR=$(pwd) BUILD_DIR=$(pwd)
TMPDIR=${TMPDIR:-/tmp} TMPDIR=${TMPDIR:-/tmp}
@ -13,15 +18,12 @@ USER=${USER:-$(whoami)}
SUCCESS=1 SUCCESS=1
VALGRIND="valgrind --leak-check=full --show-reachable=yes --error-exitcode=125 --num-callers=50 --suppressions=\"$SOURCE_DIR/libgit2_clar.supp\""
LEAKS="MallocStackLogging=1 MallocScribble=1 MallocLogFile=/dev/null CLAR_AT_EXIT=\"leaks -quiet \$PPID\""
cleanup() { cleanup() {
echo "Cleaning up..." echo "Cleaning up..."
if [ ! -z "$GITDAEMON_DIR" -a -f "${GITDAEMON_DIR}/pid" ]; then if [ ! -z "$GITDAEMON_PID" ]; then
echo "Stopping git daemon..." echo "Stopping git daemon..."
kill $(cat "${GITDAEMON_DIR}/pid") kill $GITDAEMON_PID
fi fi
if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then if [ ! -z "$SSHD_DIR" -a -f "${SSHD_DIR}/pid" ]; then
@ -32,35 +34,38 @@ cleanup() {
echo "Done." echo "Done."
} }
failure() {
echo "Test exited with code: $1"
SUCCESS=0
}
# Ask ctest what it would run if we were to invoke it directly. This lets
# us manage the test configuration in a single place (tests/CMakeLists.txt)
# instead of running clar here as well. But it allows us to wrap our test
# harness with a leak checker like valgrind. Append the option to write
# JUnit-style XML files.
run_test() { run_test() {
TEST_CMD=$(ctest -N -V -R "^${1}$" | sed -n 's/^[0-9]*: Test command: //p') if [[ "$GITTEST_FLAKY_RETRY" > 0 ]]; then
ATTEMPTS_REMAIN=$GITTEST_FLAKY_RETRY
if [ -z "$TEST_CMD" ]; then
echo "Could not find tests: $1"
exit 1
fi
TEST_CMD="${TEST_CMD} -r${BUILD_DIR}/results_${1}.xml"
if [ "$LEAK_CHECK" = "valgrind" ]; then
RUNNER="$VALGRIND $TEST_CMD"
elif [ "$LEAK_CHECK" = "leaks" ]; then
RUNNER="$LEAKS $TEST_CMD"
else else
RUNNER="$TEST_CMD" ATTEMPTS_REMAIN=1
fi fi
eval $RUNNER || failure FAILED=0
while [[ "$ATTEMPTS_REMAIN" > 0 ]]; do
if [ "$FAILED" -eq 1 ]; then
echo ""
echo "Re-running flaky ${1} tests..."
echo ""
fi
RETURN_CODE=0
CLAR_SUMMARY="${BUILD_DIR}/results_${1}.xml" ctest -V -R "^${1}$" || RETURN_CODE=$? && true
if [ "$RETURN_CODE" -eq 0 ]; then
FAILED=0
break
fi
echo "Test exited with code: $RETURN_CODE"
ATTEMPTS_REMAIN="$(($ATTEMPTS_REMAIN-1))"
FAILED=1
done
if [ "$FAILED" -ne 0 ]; then
SUCCESS=0
fi
} }
# Configure the test environment; run them early so that we're certain # Configure the test environment; run them early so that we're certain
@ -74,13 +79,31 @@ if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
echo "Starting git daemon..." echo "Starting git daemon..."
GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX` GITDAEMON_DIR=`mktemp -d ${TMPDIR}/gitdaemon.XXXXXXXX`
git init --bare "${GITDAEMON_DIR}/test.git" git init --bare "${GITDAEMON_DIR}/test.git"
git daemon --listen=localhost --export-all --enable=receive-pack --pid-file="${GITDAEMON_DIR}/pid" --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null & git daemon --listen=localhost --export-all --enable=receive-pack --base-path="${GITDAEMON_DIR}" "${GITDAEMON_DIR}" 2>/dev/null &
GITDAEMON_PID=$!
disown $GITDAEMON_PID
fi fi
if [ -z "$SKIP_PROXY_TESTS" ]; then if [ -z "$SKIP_PROXY_TESTS" ]; then
echo "Starting HTTP proxy..." curl --location --silent https://github.com/ethomson/poxyproxy/releases/download/v0.7.0/poxyproxy-0.7.0.jar >poxyproxy.jar
curl -L https://github.com/ethomson/poxyproxy/releases/download/v0.4.0/poxyproxy-0.4.0.jar >poxyproxy.jar
java -jar poxyproxy.jar -d --address 127.0.0.1 --port 8080 --credentials foo:bar --quiet & echo ""
echo "Starting HTTP proxy (Basic)..."
java -jar poxyproxy.jar --address 127.0.0.1 --port 8080 --credentials foo:bar --auth-type basic --quiet &
echo ""
echo "Starting HTTP proxy (NTLM)..."
java -jar poxyproxy.jar --address 127.0.0.1 --port 8090 --credentials foo:bar --auth-type ntlm --quiet &
fi
if [ -z "$SKIP_NTLM_TESTS" ]; then
curl --location --silent https://github.com/ethomson/poxygit/releases/download/v0.4.0/poxygit-0.4.0.jar >poxygit.jar
echo ""
echo "Starting HTTP server..."
NTLM_DIR=`mktemp -d ${TMPDIR}/ntlm.XXXXXXXX`
git init --bare "${NTLM_DIR}/test.git"
java -jar poxygit.jar --address 127.0.0.1 --port 9000 --credentials foo:baz --quiet "${NTLM_DIR}" &
fi fi
if [ -z "$SKIP_SSH_TESTS" ]; then if [ -z "$SKIP_SSH_TESTS" ]; then
@ -160,7 +183,9 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then
echo "## Running (online) tests" echo "## Running (online) tests"
echo "##############################################################################" echo "##############################################################################"
export GITTEST_FLAKY_RETRY=5
run_test online run_test online
unset GITTEST_FLAKY_RETRY
fi fi
if [ -z "$SKIP_GITDAEMON_TESTS" ]; then if [ -z "$SKIP_GITDAEMON_TESTS" ]; then
@ -175,7 +200,7 @@ fi
if [ -z "$SKIP_PROXY_TESTS" ]; then if [ -z "$SKIP_PROXY_TESTS" ]; then
echo "" echo ""
echo "Running proxy tests" echo "Running proxy tests (Basic authentication)"
echo "" echo ""
export GITTEST_REMOTE_PROXY_HOST="localhost:8080" export GITTEST_REMOTE_PROXY_HOST="localhost:8080"
@ -185,6 +210,79 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then
unset GITTEST_REMOTE_PROXY_HOST unset GITTEST_REMOTE_PROXY_HOST
unset GITTEST_REMOTE_PROXY_USER unset GITTEST_REMOTE_PROXY_USER
unset GITTEST_REMOTE_PROXY_PASS unset GITTEST_REMOTE_PROXY_PASS
echo ""
echo "Running proxy tests (NTLM authentication)"
echo ""
export GITTEST_REMOTE_PROXY_HOST="localhost:8090"
export GITTEST_REMOTE_PROXY_USER="foo"
export GITTEST_REMOTE_PROXY_PASS="bar"
export GITTEST_FLAKY_RETRY=5
run_test proxy
unset GITTEST_FLAKY_RETRY
unset GITTEST_REMOTE_PROXY_HOST
unset GITTEST_REMOTE_PROXY_USER
unset GITTEST_REMOTE_PROXY_PASS
fi
if [ -z "$SKIP_NTLM_TESTS" ]; then
echo ""
echo "Running NTLM tests (IIS emulation)"
echo ""
export GITTEST_REMOTE_URL="http://localhost:9000/ntlm/test.git"
export GITTEST_REMOTE_USER="foo"
export GITTEST_REMOTE_PASS="baz"
run_test auth_clone_and_push
unset GITTEST_REMOTE_URL
unset GITTEST_REMOTE_USER
unset GITTEST_REMOTE_PASS
echo ""
echo "Running NTLM tests (Apache emulation)"
echo ""
export GITTEST_REMOTE_URL="http://localhost:9000/broken-ntlm/test.git"
export GITTEST_REMOTE_USER="foo"
export GITTEST_REMOTE_PASS="baz"
run_test auth_clone_and_push
unset GITTEST_REMOTE_URL
unset GITTEST_REMOTE_USER
unset GITTEST_REMOTE_PASS
fi
if [ -z "$SKIP_NEGOTIATE_TESTS" -a -n "$GITTEST_NEGOTIATE_PASSWORD" ]; then
echo ""
echo "Running SPNEGO tests"
echo ""
if [ "$(uname -s)" = "Darwin" ]; then
KINIT_FLAGS="--password-file=STDIN"
fi
echo $GITTEST_NEGOTIATE_PASSWORD | kinit $KINIT_FLAGS test@LIBGIT2.ORG
klist -5f
export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
export GITTEST_REMOTE_DEFAULT="true"
run_test auth_clone
unset GITTEST_REMOTE_URL
unset GITTEST_REMOTE_DEFAULT
echo ""
echo "Running SPNEGO tests (expect/continue)"
echo ""
export GITTEST_REMOTE_URL="https://test.libgit2.org/kerberos/empty.git"
export GITTEST_REMOTE_DEFAULT="true"
export GITTEST_REMOTE_EXPECTCONTINUE="true"
run_test auth_clone
unset GITTEST_REMOTE_URL
unset GITTEST_REMOTE_DEFAULT
unset GITTEST_REMOTE_EXPECTCONTINUE
kdestroy -A
fi fi
if [ -z "$SKIP_SSH_TESTS" ]; then if [ -z "$SKIP_SSH_TESTS" ]; then
@ -213,14 +311,12 @@ if [ -z "$SKIP_FUZZERS" ]; then
echo "## Running fuzzers" echo "## Running fuzzers"
echo "##############################################################################" echo "##############################################################################"
for fuzzer in fuzzers/*_fuzzer; do ctest -V -R 'fuzzer'
"${fuzzer}" "${SOURCE_DIR}/fuzzers/corpora/$(basename "${fuzzer%_fuzzer}")" || failure
done
fi fi
cleanup cleanup
if [ "$SUCCESS" -ne "1" ]; then if [ "$SUCCESS" -ne 1 ]; then
echo "Some tests failed." echo "Some tests failed."
exit 1 exit 1
fi fi

View File

@ -1,30 +0,0 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
if ($Env:SOURCE_DIR) { $SourceDirectory = $Env:SOURCE_DIR } else { $SourceDirectory = Split-Path (Split-Path $MyInvocation.MyCommand.Path -Parent) -Parent }
$BuildDirectory = $(Get-Location).Path
Write-Host "Source directory: ${SourceDirectory}"
Write-Host "Build directory: ${BuildDirectory}"
Write-Host ""
Write-Host "Operating system version:"
Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, ServicePackMajorVersion, BuildNumber, OSArchitecture | Format-List
Write-Host "PATH: ${Env:PATH}"
Write-Host ""
Write-Host "##############################################################################"
Write-Host "## Configuring build environment"
Write-Host "##############################################################################"
Invoke-Expression "cmake ${SourceDirectory} -DBUILD_EXAMPLES=ON ${Env:CMAKE_OPTIONS}"
if ($LastExitCode -ne 0) { [Environment]::Exit($LastExitCode) }
Write-Host ""
Write-Host "##############################################################################"
Write-Host "## Building libgit2"
Write-Host "##############################################################################"
cmake --build .
if ($LastExitCode -ne 0) { [Environment]::Exit($LastExitCode) }

View File

@ -1,41 +0,0 @@
#!/bin/bash
set -e
# Environment check
[ -z "$COVERITY_TOKEN" ] && echo "Need to set a coverity token" && exit 1
SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
BUILD_DIR=$(pwd)
case $(uname -m) in
i?86) BITS=32 ;;
amd64|x86_64) BITS=64 ;;
esac
SCAN_TOOL=https://scan.coverity.com/download/cxx/linux${BITS}
TOOL_BASE=$(pwd)/_coverity-scan
# Install coverity tools
if [ ! -d "$TOOL_BASE" ]; then
echo "Downloading coverity..."
mkdir -p "$TOOL_BASE"
pushd "$TOOL_BASE"
wget -O coverity_tool.tgz $SCAN_TOOL \
--post-data "project=libgit2&token=$COVERITY_TOKEN"
tar xzf coverity_tool.tgz
popd
TOOL_DIR=$(find "$TOOL_BASE" -type d -name 'cov-analysis*')
ln -s "$TOOL_DIR" "$TOOL_BASE"/cov-analysis
fi
cp "${SOURCE_DIR}/script/user_nodefs.h" "$TOOL_BASE"/cov-analysis/config/user_nodefs.h
COV_BUILD="$TOOL_BASE/cov-analysis/bin/cov-build"
# Configure and build
cmake ${SOURCE_DIR}
COVERITY_UNSUPPORTED=1 \
$COV_BUILD --dir cov-int \
cmake --build .

View File

@ -1,33 +0,0 @@
#!/bin/bash
set -e
# Results check
[ ! -d "cov-int" ] && echo "Coverity directory not found" && exit 1
# Upload results
tar czf libgit2.tgz cov-int
SOURCE_DIR=${SOURCE_DIR:-$( cd "$( dirname "${BASH_SOURCE[0]}" )" && dirname $( pwd ) )}
SHA=$(cd ${SOURCE_DIR} && git rev-parse --short HEAD)
HTML="$(curl \
--silent \
--write-out "\n%{http_code}" \
--form token="$COVERITY_TOKEN" \
--form email=libgit2@gmail.com \
--form file=@libgit2.tgz \
--form version="$SHA" \
--form description="libgit2 build" \
https://scan.coverity.com/builds?project=libgit2)"
# Body is everything up to the last line
BODY="$(echo "$HTML" | head -n-1)"
# Status code is the last line
STATUS_CODE="$(echo "$HTML" | tail -n1)"
if [ "${STATUS_CODE}" != "200" -a "${STATUS_CODE}" != "201" ]; then
echo "Received error code ${STATUS_CODE} from Coverity"
exit 1
fi

View File

@ -1,27 +0,0 @@
#!/bin/sh
set -e
set -x
TMPDIR=${TMPDIR:-/tmp}
if [ -z "$SKIP_APT" ]; then
apt-get update
apt-get -y install build-essential pkg-config clang cmake openssl libssl-dev libssh2-1-dev libcurl4-gnutls-dev openssh-server
fi
mkdir -p /var/run/sshd
if [ "$MBEDTLS" ]; then
MBEDTLS_DIR=${MBEDTLS_DIR:-$(mktemp -d ${TMPDIR}/mbedtls.XXXXXXXX)}
git clone --depth 10 --single-branch --branch mbedtls-2.6.1 https://github.com/ARMmbed/mbedtls.git ${MBEDTLS_DIR}
cd ${MBEDTLS_DIR}
CFLAGS=-fPIC cmake -DENABLE_PROGRAMS=OFF -DENABLE_TESTING=OFF -DUSE_SHARED_MBEDTLS_LIBRARY=OFF -DUSE_STATIC_MBEDTLS_LIBRARY=ON .
cmake --build .
if [ -z "$SKIP_MBEDTLS_INSTALL" ]; then
make install
fi
fi

View File

@ -1,25 +0,0 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
[Reflection.Assembly]::LoadWithPartialName("System.IO.Compression.FileSystem");
Write-Host "##############################################################################"
Write-Host "## Downloading mingw"
Write-Host "##############################################################################"
if ($env:ARCH -eq "amd64") {
$mingw_uri = "https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-x86_64-8.1.0-release-win32-seh-rt_v6-rev0.zip"
$platform = "x86_64"
} else {
$mingw_uri = "https://bintray.com/libgit2/build-dependencies/download_file?file_path=mingw-w64-i686-8.1.0-release-win32-sjlj-rt_v6-rev0.zip"
$platform = "x86"
}
$wc = New-Object net.webclient
$wc.Downloadfile($mingw_uri, "${Env:TEMP}/mingw-${Env:ARCH}.zip")
[System.IO.Compression.ZipFile]::ExtractToDirectory("${Env:TEMP}/mingw-${Env:ARCH}.zip", $Env:TEMP)

View File

@ -1,96 +0,0 @@
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
$PSDefaultParameterValues['*:ErrorAction'] = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$SourceDir = Split-Path (Split-Path (Get-Variable MyInvocation).Value.MyCommand.Path)
$BuildDir = Get-Location
$global:Success = $true
if ($Env:SKIP_TESTS) { exit }
# Ask ctest what it would run if we were to invoke it directly. This lets
# us manage the test configuration in a single place (tests/CMakeLists.txt)
# instead of running clar here as well. But it allows us to wrap our test
# harness with a leak checker like valgrind. Append the option to write
# JUnit-style XML files.
function run_test {
$TestName = $args[0]
$TestCommand = (ctest -N -V -R "^$TestName$") -join "`n"
if (-Not ($TestCommand -match "(?ms).*\n^[0-9]*: Test command: ")) {
echo "Could not find tests: $TestName"
exit
}
$TestCommand = (ctest -N -V -R "^$TestName$") -join "`n" -replace "(?ms).*\n^[0-9]*: Test command: ","" -replace "\n.*",""
$TestCommand += " -r${BuildDir}\results_${TestName}.xml"
Invoke-Expression $TestCommand
if ($LastExitCode -ne 0) { $global:Success = $false }
}
Write-Host "##############################################################################"
Write-Host "## Configuring test environment"
Write-Host "##############################################################################"
if (-not $Env:SKIP_PROXY_TESTS) {
Write-Host ""
Write-Host "Starting HTTP proxy..."
Invoke-WebRequest -Method GET -Uri https://github.com/ethomson/poxyproxy/releases/download/v0.4.0/poxyproxy-0.4.0.jar -OutFile poxyproxy.jar
javaw -jar poxyproxy.jar -d --port 8080 --credentials foo:bar --quiet
}
Write-Host ""
Write-Host "##############################################################################"
Write-Host "## Running (offline) tests"
Write-Host "##############################################################################"
run_test offline
if ($Env:RUN_INVASIVE_TESTS) {
Write-Host ""
Write-Host "##############################################################################"
Write-Host "## Running (invasive) tests"
Write-Host "##############################################################################"
$Env:GITTEST_INVASIVE_FS_SIZE=1
$Env:GITTEST_INVASIVE_MEMORY=1
$Env:GITTEST_INVASIVE_SPEED=1
run_test invasive
$Env:GITTEST_INVASIVE_FS_SIZE=$null
$Env:GITTEST_INVASIVE_MEMORY=$null
$Env:GITTEST_INVASIVE_SPEED=$null
}
if (-not $Env:SKIP_ONLINE_TESTS) {
Write-Host ""
Write-Host "##############################################################################"
Write-Host "## Running (online) tests"
Write-Host "##############################################################################"
run_test online
}
if (-not $Env:SKIP_PROXY_TESTS) {
Write-Host ""
Write-Host "Running proxy tests"
Write-Host ""
$Env:GITTEST_REMOTE_PROXY_HOST="localhost:8080"
$Env:GITTEST_REMOTE_PROXY_USER="foo"
$Env:GITTEST_REMOTE_PROXY_PASS="bar"
run_test proxy
$Env:GITTEST_REMOTE_PROXY_HOST=$null
$Env:GITTEST_REMOTE_PROXY_USER=$null
$Env:GITTEST_REMOTE_PROXY_PASS=$null
taskkill /F /IM javaw.exe
}
if (-Not $global:Success) { exit 1 }

View File

@ -7,5 +7,9 @@ MACRO(DISABLE_WARNINGS flag)
ENDMACRO() ENDMACRO()
IF(ENABLE_WERROR) IF(ENABLE_WERROR)
ADD_C_FLAG_IF_SUPPORTED(-Werror) IF(MSVC)
ADD_COMPILE_OPTIONS(-WX)
ELSE()
ADD_C_FLAG_IF_SUPPORTED(-Werror)
ENDIF()
ENDIF() ENDIF()

View File

@ -10,14 +10,14 @@ FIND_PATH(COREFOUNDATION_INCLUDE_DIR NAMES CoreFoundation.h)
FIND_LIBRARY(COREFOUNDATION_LIBRARIES NAMES CoreFoundation) FIND_LIBRARY(COREFOUNDATION_LIBRARIES NAMES CoreFoundation)
IF (COREFOUNDATION_INCLUDE_DIR AND COREFOUNDATION_LIBRARIES) IF (COREFOUNDATION_INCLUDE_DIR AND COREFOUNDATION_LIBRARIES)
IF (NOT CoreFoundation_FIND_QUIETLY) IF (NOT CoreFoundation_FIND_QUIETLY)
MESSAGE("-- Found CoreFoundation ${COREFOUNDATION_LIBRARIES}") MESSAGE(STATUS "Found CoreFoundation ${COREFOUNDATION_LIBRARIES}")
ENDIF() ENDIF()
SET(COREFOUNDATION_FOUND TRUE) SET(COREFOUNDATION_FOUND TRUE)
SET(COREFOUNDATION_LDFLAGS "-framework CoreFoundation") SET(COREFOUNDATION_LDFLAGS "-framework CoreFoundation")
ENDIF () ENDIF ()
IF (CoreFoundation_FIND_REQUIRED AND NOT COREFOUNDATION_FOUND) IF (CoreFoundation_FIND_REQUIRED AND NOT COREFOUNDATION_FOUND)
MESSAGE(FATAL "-- CoreFoundation not found") MESSAGE(FATAL_ERROR "CoreFoundation not found")
ENDIF() ENDIF()
MARK_AS_ADVANCED( MARK_AS_ADVANCED(

View File

@ -6,7 +6,7 @@
# #
# Read-Only variables: # Read-Only variables:
# GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found # GSSAPI_FLAVOR_MIT - set to TURE if MIT Kerberos has been found
# GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Keberos has been found # GSSAPI_FLAVOR_HEIMDAL - set to TRUE if Heimdal Kerberos has been found
# GSSAPI_FOUND - system has GSSAPI # GSSAPI_FOUND - system has GSSAPI
# GSSAPI_INCLUDE_DIR - the GSSAPI include directory # GSSAPI_INCLUDE_DIR - the GSSAPI include directory
# GSSAPI_LIBRARIES - Link these to use GSSAPI # GSSAPI_LIBRARIES - Link these to use GSSAPI

View File

@ -0,0 +1,28 @@
# Find GSS.framework
# This will define :
#
# GSSFRAMEWORK_FOUND
# GSSFRAMEWORK_INCLUDE_DIR
# GSSFRAMEWORK_LIBRARIES
# GSSFRAMEWORK_LDFLAGS
#
FIND_PATH(GSSFRAMEWORK_INCLUDE_DIR NAMES GSS.h)
FIND_LIBRARY(GSSFRAMEWORK_LIBRARIES NAMES GSS)
IF (GSSFRAMEWORK_INCLUDE_DIR AND GSSFRAMEWORK_LIBRARIES)
IF (NOT CoreFoundation_FIND_QUIETLY)
MESSAGE(STATUS "Found GSS.framework ${GSSFRAMEWORK_LIBRARIES}")
ENDIF()
SET(GSSFRAMEWORK_FOUND TRUE)
SET(GSSFRAMEWORK_LDFLAGS "-framework GSS")
ENDIF ()
IF (GSS_FIND_REQUIRED AND NOT GSSFRAMEWORK_FOUND)
MESSAGE(FATAL_ERROR "CoreFoundation not found")
ENDIF()
MARK_AS_ADVANCED(
GSSFRAMEWORK_INCLUDE_DIR
GSSFRAMEWORK_LIBRARIES
GSSFRAMEWORK_LDFLAGS
)

View File

@ -0,0 +1,38 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre
# Find the native PCRE headers and libraries.
#
# PCRE_INCLUDE_DIRS - where to find pcre.h, etc.
# PCRE_LIBRARIES - List of libraries when using pcre.
# PCRE_FOUND - True if pcre found.
# Look for the header file.
FIND_PATH(PCRE_INCLUDE_DIR NAMES pcreposix.h)
# Look for the library.
FIND_LIBRARY(PCRE_LIBRARY NAMES pcre)
FIND_LIBRARY(PCRE_POSIX_LIBRARY NAMES pcreposix)
# Handle the QUIETLY and REQUIRED arguments and set PCRE_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE DEFAULT_MSG PCRE_LIBRARY PCRE_POSIX_LIBRARY PCRE_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE_FOUND)
SET(PCRE_LIBRARIES ${PCRE_LIBRARY} ${PCRE_POSIX_LIBRARY})
SET(PCRE_INCLUDE_DIRS ${PCRE_INCLUDE_DIR})
ELSE(PCRE_FOUND)
SET(PCRE_LIBRARIES)
SET(PCRE_INCLUDE_DIRS)
ENDIF(PCRE_FOUND)
MARK_AS_ADVANCED(PCRE_INCLUDE_DIRS PCRE_LIBRARIES)

View File

@ -0,0 +1,37 @@
# Copyright (C) 2007-2009 LuaDist.
# Created by Peter Kapec <kapecp@gmail.com>
# Redistribution and use of this file is allowed according to the terms of the MIT license.
# For details see the COPYRIGHT file distributed with LuaDist.
# Note:
# Searching headers and libraries is very simple and is NOT as powerful as scripts
# distributed with CMake, because LuaDist defines directories to search for.
# Everyone is encouraged to contact the author with improvements. Maybe this file
# becomes part of CMake distribution sometimes.
# - Find pcre
# Find the native PCRE2 headers and libraries.
#
# PCRE2_INCLUDE_DIRS - where to find pcre.h, etc.
# PCRE2_LIBRARIES - List of libraries when using pcre.
# PCRE2_FOUND - True if pcre found.
# Look for the header file.
FIND_PATH(PCRE2_INCLUDE_DIR NAMES pcre2posix.h)
# Look for the library.
FIND_LIBRARY(PCRE2_LIBRARY NAMES pcre2-8)
# Handle the QUIETLY and REQUIRED arguments and set PCRE2_FOUND to TRUE if all listed variables are TRUE.
INCLUDE(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(PCRE2 DEFAULT_MSG PCRE2_LIBRARY PCRE2_INCLUDE_DIR)
# Copy the results to the output variables.
IF(PCRE2_FOUND)
SET(PCRE2_LIBRARIES ${PCRE2_LIBRARY})
SET(PCRE2_INCLUDE_DIRS ${PCRE2_INCLUDE_DIR})
ELSE(PCRE2_FOUND)
SET(PCRE2_LIBRARIES)
SET(PCRE2_INCLUDE_DIRS)
ENDIF(PCRE2_FOUND)
MARK_AS_ADVANCED(PCRE2_INCLUDE_DIRS PCRE2_LIBRARIES)

View File

@ -11,7 +11,7 @@ FIND_PATH(SECURITY_INCLUDE_DIR NAMES Security/Security.h)
FIND_LIBRARY(SECURITY_LIBRARIES NAMES Security) FIND_LIBRARY(SECURITY_LIBRARIES NAMES Security)
IF (SECURITY_INCLUDE_DIR AND SECURITY_LIBRARIES) IF (SECURITY_INCLUDE_DIR AND SECURITY_LIBRARIES)
IF (NOT Security_FIND_QUIETLY) IF (NOT Security_FIND_QUIETLY)
MESSAGE("-- Found Security ${SECURITY_LIBRARIES}") MESSAGE(STATUS "Found Security ${SECURITY_LIBRARIES}")
ENDIF() ENDIF()
SET(SECURITY_FOUND TRUE) SET(SECURITY_FOUND TRUE)
SET(SECURITY_LDFLAGS "-framework Security") SET(SECURITY_LDFLAGS "-framework Security")
@ -19,7 +19,7 @@ IF (SECURITY_INCLUDE_DIR AND SECURITY_LIBRARIES)
ENDIF () ENDIF ()
IF (Security_FIND_REQUIRED AND NOT SECURITY_FOUND) IF (Security_FIND_REQUIRED AND NOT SECURITY_FOUND)
MESSAGE(FATAL "-- Security not found") MESSAGE(FATAL_ERROR "Security not found")
ENDIF() ENDIF()
MARK_AS_ADVANCED( MARK_AS_ADVANCED(

View File

@ -1,3 +1,5 @@
INCLUDE(FeatureSummary)
CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h" CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtim "sys/types.h;sys/stat.h"
HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C) HAVE_STRUCT_STAT_ST_MTIM LANGUAGE C)
CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h" CHECK_STRUCT_HAS_MEMBER ("struct stat" st_mtimespec "sys/types.h;sys/stat.h"
@ -17,4 +19,8 @@ ENDIF()
IF (HAVE_STRUCT_STAT_NSEC OR WIN32) IF (HAVE_STRUCT_STAT_NSEC OR WIN32)
OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON ) OPTION( USE_NSEC "Care about sub-second file mtimes and ctimes" ON )
ELSE()
SET(USE_NSEC OFF)
ENDIF() ENDIF()
ADD_FEATURE_INFO(nanoseconds USE_NSEC "whether to use sub-second file mtimes and ctimes")

View File

@ -0,0 +1,110 @@
# pkg-config file generation
#
# Uses the following globals:
# - PKG_BUILD_PREFIX: the build location (aka prefix). Defaults to CMAKE_INSTALL_PREFIX
# - PKG_BUILD_LIBDIR: the libdir location. Defaults to ${prefix}/lib.
# - PKG_BUILD_INCLUDEDIR: the includedir location. Defaults to ${prefix}/include.
#
function(pkg_build_config)
set(options)
set(oneValueArgs NAME DESCRIPTION VERSION FILENAME LIBS_SELF)
set(multiValueArgs LIBS PRIVATE_LIBS REQUIRES CFLAGS)
cmake_parse_arguments(PKGCONFIG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (NOT DEFINED PKGCONFIG_FILENAME AND DEFINED PKGCONFIG_NAME)
set(PKGCONFIG_FILENAME ${PKGCONFIG_NAME})
endif()
if (NOT DEFINED PKGCONFIG_FILENAME)
message(FATAL_ERROR "Missing FILENAME argument")
endif()
set(PKGCONFIG_FILE "${PROJECT_BINARY_DIR}/${PKGCONFIG_FILENAME}.pc")
if (NOT DEFINED PKGCONFIG_DESCRIPTION)
message(FATAL_ERROR "Missing DESCRIPTION argument")
endif()
if (NOT DEFINED PKGCONFIG_VERSION)
message(FATAL_ERROR "Missing VERSION argument")
endif()
if (DEFINED PKG_BUILD_PREFIX)
set(PKGCONFIG_PREFIX "${PKG_BUILD_PREFIX}")
else()
set(PKGCONFIG_PREFIX "${CMAKE_INSTALL_PREFIX}")
endif()
if(DEFINED PKG_BUILD_LIBDIR)
if (IS_ABSOLUTE ${PKG_BUILD_LIBDIR})
set(PKGCONFIG_LIBDIR ${PKG_BUILD_LIBDIR})
else()
set(PKGCONFIG_LIBDIR "\${prefix}/${PKG_BUILD_LIBDIR}")
endif()
else()
set(PKGCONFIG_LIBDIR "\${prefix}/lib")
endif()
if(DEFINED PKG_BUILD_INCLUDEDIR)
if (IS_ABSOLUTE ${PKG_BUILD_INCLUDEDIR})
set(PKGCONFIG_INCLUDEDIR ${PKG_BUILD_INCLUDEDIR})
else()
set(PKGCONFIG_INCLUDEDIR "\${prefix}/${PKG_BUILD_INCLUDEDIR}")
endif()
else()
set(PKGCONFIG_INCLUDEDIR "\${prefix}/include")
endif()
# Write .pc "header"
file(WRITE "${PKGCONFIG_FILE}"
"prefix=\"${PKGCONFIG_PREFIX}\"\n"
"libdir=\"${PKGCONFIG_LIBDIR}\"\n"
"includedir=\"${PKGCONFIG_INCLUDEDIR}\"\n"
"\n"
"Name: ${PKGCONFIG_NAME}\n"
"Description: ${PKGCONFIG_DESCRIPTION}\n"
"Version: ${PKGCONFIG_VERSION}\n"
)
# Prepare Libs
if(NOT DEFINED PKGCONFIG_LIBS_SELF)
set(PKGCONFIG_LIBS_SELF "${PKGCONFIG_FILE}")
endif()
if(NOT DEFINED PKGCONFIG_LIBS)
set(PKGCONFIG_LIBS "-l${PKGCONFIG_LIBS_SELF}")
else()
list(INSERT PKGCONFIG_LIBS 0 "-l${PKGCONFIG_LIBS_SELF}")
endif()
list(REMOVE_DUPLICATES PKGCONFIG_LIBS)
string(REPLACE ";" " " PKGCONFIG_LIBS "${PKGCONFIG_LIBS}")
file(APPEND "${PKGCONFIG_FILE}" "Libs: -L\${libdir} ${PKGCONFIG_LIBS}\n")
# Prepare Libs.private
if(DEFINED PKGCONFIG_PRIVATE_LIBS)
list(REMOVE_DUPLICATES PKGCONFIG_PRIVATE_LIBS)
string(REPLACE ";" " " PKGCONFIG_PRIVATE_LIBS "${PKGCONFIG_PRIVATE_LIBS}")
file(APPEND "${PKGCONFIG_FILE}" "Libs.private: ${PKGCONFIG_PRIVATE_LIBS}\n")
endif()
# Prepare Requires.private
if(DEFINED PKGCONFIG_REQUIRES)
list(REMOVE_DUPLICATES PKGCONFIG_REQUIRES)
string(REPLACE ";" " " PKGCONFIG_REQUIRES "${PKGCONFIG_REQUIRES}")
file(APPEND "${PKGCONFIG_FILE}" "Requires.private: ${PKGCONFIG_REQUIRES}\n")
endif()
# Prepare Cflags
if(DEFINED PKGCONFIG_CFLAGS)
string(REPLACE ";" " " PKGCONFIG_CFLAGS "${PKGCONFIG_CFLAGS}")
else()
set(PKGCONFIG_CFLAGS "")
endif()
file(APPEND "${PKGCONFIG_FILE}" "Cflags: -I\${includedir} ${PKGCONFIG_CFLAGS}\n")
# Install .pc file
install(FILES "${PKGCONFIG_FILE}"
DESTINATION "${PKGCONFIG_PREFIX}/${PKGCONFIG_LIBDIR}/pkgconfig"
)
endfunction()

View File

@ -0,0 +1,53 @@
# Select the backend to use
# We try to find any packages our backends might use
FIND_PACKAGE(GSSAPI)
IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
INCLUDE(FindGSSFramework)
ENDIF()
# Auto-select GSS backend
IF (USE_GSSAPI STREQUAL ON)
IF (GSSFRAMEWORK_FOUND)
SET(GSS_BACKEND "GSS.framework")
ELSEIF(GSSAPI_FOUND)
SET(GSS_BACKEND "gssapi")
ELSE()
MESSAGE(FATAL_ERROR "Unable to autodetect a usable GSS backend."
"Please pass the backend name explicitly (-DUSE_GSS=backend)")
ENDIF()
ELSEIF(USE_GSSAPI)
# Backend was explicitly set
SET(GSS_BACKEND ${USE_GSSAPI})
ELSE()
SET(GSS_BACKEND NO)
ENDIF()
IF(GSS_BACKEND)
# Check that we can find what's required for the selected backend
IF (GSS_BACKEND STREQUAL "GSS.framework")
IF (NOT GSSFRAMEWORK_FOUND)
MESSAGE(FATAL_ERROR "Asked for GSS.framework backend, but it wasn't found")
ENDIF()
LIST(APPEND LIBGIT2_LIBS ${GSSFRAMEWORK_LIBRARIES})
SET(GIT_GSSFRAMEWORK 1)
ADD_FEATURE_INFO(SPNEGO GIT_GSSFRAMEWORK "SPNEGO authentication support (${GSS_BACKEND})")
ELSEIF (GSS_BACKEND STREQUAL "gssapi")
IF (NOT GSSAPI_FOUND)
MESSAGE(FATAL_ERROR "Asked for gssapi GSS backend, but it wasn't found")
ENDIF()
LIST(APPEND LIBGIT2_LIBS ${GSSAPI_LIBRARIES})
SET(GIT_GSSAPI 1)
ADD_FEATURE_INFO(SPNEGO GIT_GSSAPI "SPNEGO authentication support (${GSS_BACKEND})")
ELSE()
MESSAGE(FATAL_ERROR "Asked for backend ${GSS_BACKEND} but it wasn't found")
ENDIF()
ELSE()
SET(GIT_GSSAPI 0)
ADD_FEATURE_INFO(SPNEGO NO "SPNEGO authentication support")
ENDIF()

View File

@ -0,0 +1,124 @@
# Select the backend to use
# We try to find any packages our backends might use
FIND_PACKAGE(OpenSSL)
FIND_PACKAGE(mbedTLS)
IF (CMAKE_SYSTEM_NAME MATCHES "Darwin")
FIND_PACKAGE(Security)
FIND_PACKAGE(CoreFoundation)
ENDIF()
# Auto-select TLS backend
IF (USE_HTTPS STREQUAL ON)
IF (SECURITY_FOUND)
IF (SECURITY_HAS_SSLCREATECONTEXT)
SET(HTTPS_BACKEND "SecureTransport")
ELSE()
MESSAGE(STATUS "Security framework is too old, falling back to OpenSSL")
SET(HTTPS_BACKEND "OpenSSL")
ENDIF()
ELSEIF (WINHTTP)
SET(HTTPS_BACKEND "WinHTTP")
ELSEIF(OPENSSL_FOUND)
SET(HTTPS_BACKEND "OpenSSL")
ELSEIF(MBEDTLS_FOUND)
SET(HTTPS_BACKEND "mbedTLS")
ELSE()
MESSAGE(FATAL_ERROR "Unable to autodetect a usable HTTPS backend."
"Please pass the backend name explicitly (-DUSE_HTTPS=backend)")
ENDIF()
ELSEIF(USE_HTTPS)
# HTTPS backend was explicitly set
SET(HTTPS_BACKEND ${USE_HTTPS})
ELSE()
SET(HTTPS_BACKEND NO)
ENDIF()
IF(HTTPS_BACKEND)
# Check that we can find what's required for the selected backend
IF (HTTPS_BACKEND STREQUAL "SecureTransport")
IF (NOT COREFOUNDATION_FOUND)
MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, CoreFoundation.framework not found")
ENDIF()
IF (NOT SECURITY_FOUND)
MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, Security.framework not found")
ENDIF()
IF (NOT SECURITY_HAS_SSLCREATECONTEXT)
MESSAGE(FATAL_ERROR "Cannot use SecureTransport backend, SSLCreateContext not supported")
ENDIF()
SET(GIT_SECURE_TRANSPORT 1)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${SECURITY_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS})
LIST(APPEND LIBGIT2_PC_LIBS ${COREFOUNDATION_LDFLAGS} ${SECURITY_LDFLAGS})
ELSEIF (HTTPS_BACKEND STREQUAL "OpenSSL")
IF (NOT OPENSSL_FOUND)
MESSAGE(FATAL_ERROR "Asked for OpenSSL TLS backend, but it wasn't found")
ENDIF()
SET(GIT_OPENSSL 1)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${OPENSSL_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${OPENSSL_LIBRARIES})
LIST(APPEND LIBGIT2_PC_LIBS ${OPENSSL_LDFLAGS})
LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
ELSEIF(HTTPS_BACKEND STREQUAL "mbedTLS")
IF (NOT MBEDTLS_FOUND)
MESSAGE(FATAL_ERROR "Asked for mbedTLS backend, but it wasn't found")
ENDIF()
IF(NOT CERT_LOCATION)
MESSAGE(STATUS "Auto-detecting default certificates location")
IF(CMAKE_SYSTEM_NAME MATCHES Darwin)
# Check for an Homebrew installation
SET(OPENSSL_CMD "/usr/local/opt/openssl/bin/openssl")
ELSE()
SET(OPENSSL_CMD "openssl")
ENDIF()
EXECUTE_PROCESS(COMMAND ${OPENSSL_CMD} version -d OUTPUT_VARIABLE OPENSSL_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
IF(OPENSSL_DIR)
STRING(REGEX REPLACE "^OPENSSLDIR: \"(.*)\"$" "\\1/" OPENSSL_DIR ${OPENSSL_DIR})
SET(OPENSSL_CA_LOCATIONS
"ca-bundle.pem" # OpenSUSE Leap 42.1
"cert.pem" # Ubuntu 14.04, FreeBSD
"certs/ca-certificates.crt" # Ubuntu 16.04
"certs/ca.pem" # Debian 7
)
FOREACH(SUFFIX IN LISTS OPENSSL_CA_LOCATIONS)
SET(LOC "${OPENSSL_DIR}${SUFFIX}")
IF(NOT CERT_LOCATION AND EXISTS "${OPENSSL_DIR}${SUFFIX}")
SET(CERT_LOCATION ${LOC})
ENDIF()
ENDFOREACH()
ELSE()
MESSAGE(FATAL_ERROR "Unable to find OpenSSL executable. Please provide default certificate location via CERT_LOCATION")
ENDIF()
ENDIF()
IF(CERT_LOCATION)
IF(NOT EXISTS ${CERT_LOCATION})
MESSAGE(FATAL_ERROR "Cannot use CERT_LOCATION=${CERT_LOCATION} as it doesn't exist")
ENDIF()
ADD_FEATURE_INFO(CERT_LOCATION ON "using certificates from ${CERT_LOCATION}")
ADD_DEFINITIONS(-DGIT_DEFAULT_CERT_LOCATION="${CERT_LOCATION}")
ENDIF()
SET(GIT_MBEDTLS 1)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
# mbedTLS has no pkgconfig file, hence we can't require it
# https://github.com/ARMmbed/mbedtls/issues/228
# For now, pass its link flags as our own
LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
ELSEIF (HTTPS_BACKEND STREQUAL "WinHTTP")
# WinHTTP setup was handled in the WinHTTP-specific block above
ELSE()
MESSAGE(FATAL_ERROR "Asked for backend ${HTTPS_BACKEND} but it wasn't found")
ENDIF()
SET(GIT_HTTPS 1)
ADD_FEATURE_INFO(HTTPS GIT_HTTPS "using ${HTTPS_BACKEND}")
ELSE()
SET(GIT_HTTPS 0)
ADD_FEATURE_INFO(HTTPS NO "")
ENDIF()

View File

@ -0,0 +1,66 @@
# Select a hash backend
# USE_SHA1=CollisionDetection(ON)/HTTPS/Generic/OFF
IF(USE_SHA1 STREQUAL ON OR USE_SHA1 STREQUAL "CollisionDetection")
SET(SHA1_BACKEND "CollisionDetection")
ELSEIF(USE_SHA1 STREQUAL "HTTPS")
message(STATUS "Checking HTTPS backend… ${HTTPS_BACKEND}")
IF(HTTPS_BACKEND STREQUAL "SecureTransport")
SET(SHA1_BACKEND "CommonCrypto")
ELSEIF(HTTPS_BACKEND STREQUAL "WinHTTP")
SET(SHA1_BACKEND "Win32")
ELSEIF(HTTPS_BACKEND)
SET(SHA1_BACKEND ${HTTPS_BACKEND})
ELSE()
ENDIF()
IF(NOT HTTPS_BACKEND)
SET(SHA1_BACKEND "CollisionDetection")
ENDIF()
message(STATUS "Using SHA1 backend ${SHA1_BACKEND}")
ELSEIF(USE_SHA1 STREQUAL "Generic")
SET(SHA1_BACKEND "Generic")
# ELSEIF(NOT USE_SHA1)
ELSE()
MESSAGE(FATAL_ERROR "Invalid value for USE_SHA1: ${USE_SHA1}")
ENDIF()
IF(SHA1_BACKEND STREQUAL "CollisionDetection")
SET(GIT_SHA1_COLLISIONDETECT 1)
ADD_DEFINITIONS(-DSHA1DC_NO_STANDARD_INCLUDES=1)
ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_SHA1_C=\"common.h\")
ADD_DEFINITIONS(-DSHA1DC_CUSTOM_INCLUDE_UBC_CHECK_C=\"common.h\")
FILE(GLOB SRC_SHA1 hash/sha1/collisiondetect.* hash/sha1/sha1dc/*)
ELSEIF(SHA1_BACKEND STREQUAL "OpenSSL")
# OPENSSL_FOUND should already be set, we're checking HTTPS_BACKEND
SET(GIT_SHA1_OPENSSL 1)
IF(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
LIST(APPEND LIBGIT2_PC_LIBS "-lssl")
ELSE()
LIST(APPEND LIBGIT2_PC_REQUIRES "openssl")
ENDIF()
FILE(GLOB SRC_SHA1 hash/sha1/openssl.*)
ELSEIF(SHA1_BACKEND STREQUAL "CommonCrypto")
SET(GIT_SHA1_COMMON_CRYPTO 1)
FILE(GLOB SRC_SHA1 hash/sha1/common_crypto.*)
ELSEIF(SHA1_BACKEND STREQUAL "mbedTLS")
SET(GIT_SHA1_MBEDTLS 1)
FILE(GLOB SRC_SHA1 hash/sha1/mbedtls.*)
LIST(APPEND LIBGIT2_SYSTEM_INCLUDES ${MBEDTLS_INCLUDE_DIR})
LIST(APPEND LIBGIT2_LIBS ${MBEDTLS_LIBRARIES})
# mbedTLS has no pkgconfig file, hence we can't require it
# https://github.com/ARMmbed/mbedtls/issues/228
# For now, pass its link flags as our own
LIST(APPEND LIBGIT2_PC_LIBS ${MBEDTLS_LIBRARIES})
ELSEIF(SHA1_BACKEND STREQUAL "Win32")
SET(GIT_SHA1_WIN32 1)
FILE(GLOB SRC_SHA1 hash/sha1/win32.*)
ELSEIF(SHA1_BACKEND STREQUAL "Generic")
FILE(GLOB SRC_SHA1 hash/sha1/generic.*)
# ELSEIF(NOT USE_SHA1)
ELSE()
MESSAGE(FATAL_ERROR "Asked for unknown SHA1 backend: ${SHA1_BACKEND}")
ENDIF()
ADD_FEATURE_INFO(SHA ON "using ${SHA1_BACKEND}")

View File

@ -1,7 +1,291 @@
v0.28.4 v0.99
-------- -----
This is a security release fixing the following issues: This is v0.99 "Torschlusspanik". This will be the last minor release
before libgit2 v1.0. We expect to only respond to bugs in this release,
to stabilize it for next major release.
It contains significant refactorings, but is expected to be API-compatible
with v0.28.0.
### Changes or improvements
* When fetching from an anonymous remote using a URL with authentication
information provided in the URL (eg `https://foo:bar@example.com/repo`),
we would erroneously include the literal URL in the FETCH_HEAD file.
We now remove that to match git's behavior.
* Some credential structures, enums and values have been renamed:
`git_cred` is now `git_credential`. `git_credtype_t` is now
`git_credential_t`. Functions and types beginning with
`git_cred_` now begin with `git_credential`, and constants beginning
with `GIT_CREDTYPE` now begin with `GIT_CREDENTIAL`. The former names
are deprecated.
* Several function signatures have been changed to return an `int` to
indicate error conditions. We encourage you to check them for errors
in the standard way.
* `git_attr_cache_flush`
* `git_error_set_str`
* `git_index_name_clear`
* `git_index_reuc_clear`
* `git_libgit2_version`
* `git_mempack_reset`
* `git_oid_cpy`
* `git_oid_fmt`
* `git_oid_fromraw`
* `git_oid_nfmt`
* `git_oid_pathfmt`
* `git_remote_stop`
* `git_remote_disconnect`
* `git_repository__cleanup`
* `git_repository_set_config`
* `git_repository_set_index`
* `git_repository_set_odb`
* `git_repository_set_refdb`
* `git_revwalk_reset`
* `git_revwalk_simplify_first_parent`
* `git_revwalk_sorting`
* `git_treebuilder_clear`
* `git_treebuilder_filter`
* The NTLM and Negotiate authentication mechanisms are now supported when
talking to git implementations hosted on Apache or nginx servers.
* The `HEAD` symbolic reference can no longer be deleted.
* `git_merge_driver_source_repo` no longer returns a `const git_repository *`,
it now returns a non-`const` `git_repository *`.
* Relative symbolic links are now supported on Windows when `core.symlinks`
is enabled.
* Servers that provide query parameters with a redirect are now supported.
* `git_submodule_sync` will now resolve relative URLs.
* When creating git endpoint URLs, double-slashes are no longer used when
the given git URL has a trailing slash.
* On Windows, a `DllMain` function is no longer included and thread-local
storage has moved to fiber-local storage in order to prevent race
conditions during shutdown.
* The tracing mechanism (`GIT_TRACE`) is now enabled by default and does
not need to be explicitly enabled in CMake.
* The size of Git objects is now represented by `git_object_size_t`
instead of `off_t`.
* Binary patches without data can now be parsed.
* A configuration snapshot can now be created from another configuration
snapshot, not just a "true" configuration object.
* The `git_commit_with_signature` API will now ensure that referenced
objects exist in the object database.
* Stash messages containing newlines will now be replaced with spaces;
they will no longer be (erroneously) written to the repository.
* `git_commit_create_with_signature` now verifies the commit information
to ensure that it points to a valid tree and valid parents.
* `git_apply` has an option `GIT_APPLY_CHECK` that will only do a dry-run.
The index and working directory will remain unmodified, and application
will report if it would have worked.
* Patches produced by Mercurial (those that lack some git extended headers)
can now be parsed and applied.
* Reference locks are obeyed correctly on POSIX platforms, instead of
being removed.
* Patches with empty new files can now be read and applied.
* `git_apply_to_tree` can now correctly apply patches that add new files.
* The program data configuration on Windows (`C:\ProgramData\Git\config`)
must be owned by an administrator, a system account or the current user
to be read.
* `git_blob_filtered_content` is now deprecated in favor of `git_blob_filter`.
* Configuration files can now be included conditionally using the
`onbranch` conditional.
* Checkout can now properly create and remove symbolic links to directories
on Windows.
* Stash no longer recomputes trees when committing a worktree, for
improved performance.
* Repository templates can now include a `HEAD` file to default the
initial default branch.
* Some configuration structures, enums and values have been renamed:
`git_cvar_map` is now `git_configmap`, `git_cvar_t` is now
`git_configmap_t`, `GIT_CVAR_FALSE` is now `GIT_CONFIGMAP_FALSE`,
`GIT_CVAR_TRUE` is now `GIT_CONFIGMAP_TRUE`, `GIT_CVAR_INT32` is now
`GIT_CONFIGMAP_INT32`, and `GIT_CVAR_STRING` is now `GIT_CONFIGMAP_STRING`.
The former names are deprecated.
* Repositories can now be created at the root of a Windows drive.
* Configuration lookups are now more efficiently cached.
* `git_commit_create_with_signature` now supports a `NULL` signature,
which will create a commit without adding a signature.
* When a repository lacks an `info` "common directory", we will no
longer erroneously return `GIT_ENOTFOUND` for all attribute lookups.
* Several attribute macros have been renamed: `GIT_ATTR_TRUE` is now
`GIT_ATTR_IS_TRUE`, `GIT_ATTR_FALSE` is now `GIT_ATTR_IS_FALSE`,
`GIT_ATTR_UNSPECIFIED` is now `GIT_ATTR_IS_UNSPECIFIED`. The
attribute enum `git_attr_t` is now `git_attr_value_t` and its
values have been renamed: `GIT_ATTR_UNSPECIFIED_T` is now
`GIT_ATTR_VALUE_UNSPECIFIED`, `GIT_ATTR_TRUE_T` is now
`GIT_ATTR_VALUE_TRUE`, `GIT_ATTR_FALSE_T` is now `GIT_ATTR_VALUE_FALSE`,
and `GIT_ATTR_VALUE_T` is now `GIT_ATTR_VALUE_STRING`. The
former names are deprecated.
* `git_object__size` is now `git_object_size`. The former name is
deprecated.
* `git_tag_create_frombuffer` is now `git_tag_create_from_buffer`. The
former name is deprecated.
* Several blob creation functions have been renamed:
`git_blob_create_frombuffer` is now named `git_blob_create_from_buffer`,
`git_blob_create_fromdisk` is now named `git_blob_create_from_disk`,
`git_blob_create_fromworkdir` is now named `git_blob_create_from_workdir`,
`git_blob_create_fromstream` is now named `git_blob_create_from_stream`,
and `git_blob_create_fromstream_commit` is now named
`git_blob_create_from_stream_commit`. The former names are deprecated.
* The function `git_oid_iszero` is now named `git_oid_is_zero`. The
former name is deprecated.
* Pattern matching is now done using `wildmatch` instead of `fnmatch`
for compatibility with git.
* The option initialization functions suffixed by `init_options` are now
suffixed with `options_init`. (For example, `git_checkout_init_options`
is now `git_checkout_options_init`.) The former names are deprecated.
* NTLM2 authentication is now supported on non-Windows platforms.
* The `git_cred_sign_callback` callback is now named `git_cred_sign_cb`.
The `git_cred_ssh_interactive_callback` callback is now named
`git_cred_ssh_interactive_cb`.
* Ignore files now:
* honor escaped trailing whitespace.
* do not incorrectly negate sibling paths of a negated pattern.
* honor rules that stop ignoring files after a wildcard
* Attribute files now:
* honor leading and trailing whitespace.
* treat paths beginning with `\` as absolute only on Windows.
* properly handle escaped characters.
* stop reading macros defined in subdirectories
* The C locale is now correctly used when parsing regular expressions.
* The system PCRE2 or PCRE regular expression libraries are now used
when `regcomp_l` is not available on the system. If none of these
are available on the system, an included version of PCRE is used.
* Wildcards in reference specifications are now supported beyond simply
a bare wildcard (`*`) for compatibility with git.
* When `git_ignore_path_is_ignored` is provided a path with a trailing
slash (eg, `dir/`), it will now treat it as a directory for the
purposes of ignore matching.
* Patches that add or remove a file with a space in the path can now
be correctly parsed.
* The `git_remote_completion_type` type is now `git_remote_completion_t`.
The former name is deprecated.
* The `git_odb_backend_malloc` is now `git_odb_backend_data_alloc`. The
former name is deprecated.
* The `git_transfer_progress_cb` callback is now `git_indexer_progress_cb`
and the `git_transfer_progress` structure is now `git_indexer_progress`.
The former names are deprecated.
* The example projects are now contained in a single `lg2` executable
for ease of use.
* libgit2 now correctly handles more URLs, such as
`http://example.com:/repo.git` (colon but no port),
`http://example.com` (no path),
and `http://example.com:8080/` (path is /, nonstandard port).
* A carefully constructed commit object with a very large number
of parents may lead to potential out-of-bounds writes or
potential denial of service.
* The ProgramData configuration file is always read for compatibility
with Git for Windows and Portable Git installations. The ProgramData
location is not necessarily writable only by administrators, so we
now ensure that the configuration file is owned by the administrator
or the current user.
### API additions
* The SSH host key now supports SHA-256 when `GIT_CERT_SSH_SHA256` is set.
* The diff format option `GIT_DIFF_FORMAT_PATCH_ID` can now be used to
emit an output like `git patch-id`.
* The `git_apply_options_init` function will initialize a
`git_apply_options` structure.
* The remote callbacks structure adds a `git_url_resolve_cb` callback
that is invoked when connecting to a server, so that applications
may edit or replace the URL before connection.
* The information about the original `HEAD` in a rebase operation is
available with `git_rebase_orig_head_name`. Its ID is available with
`git_rebase_orig_head_id`. The `onto` reference name is available with
`git_rebase_onto_name` and its ID is available with `git_rebase_onto_id`.
* ODB backends can now free backend data when an error occurs during its
backend data creation using `git_odb_backend_data_free`.
* Options may be specified to `git_repository_foreach_head` to control
its behavior: `GIT_REPOSITORY_FOREACH_HEAD_SKIP_REPO` will not skip
the main repository's HEAD reference, while
`GIT_REPOSITORY_FOREACH_HEAD_SKIP_WORKTREES` will now skip the
worktree HEAD references.
* The `GIT_OPT_DISABLE_PACK_KEEP_FILE_CHECKS` option can be specified to
`git_libgit2_opts()` to avoid looking for `.keep` files that correspond
to packfiles. This setting can improve performance when packfiles are
stored on high-latency filesystems like network filesystems.
* Blobs can now be filtered with `git_blob_filter`, which allows for
options to be set with `git_blob_filter_options`, including
`GIT_FILTER_NO_SYSTEM_ATTRIBUTES` to disable filtering with system-level
attributes in `/etc/gitattributes` and `GIT_ATTR_CHECK_INCLUDE_HEAD` to
enable filtering with `.gitattributes` files in the HEAD revision.
### API removals
* The unused `git_headlist_cb` function declaration was removed.
* The unused `git_time_monotonic` API is removed.
* The erroneously exported `inttypes.h` header was removed.
# Security Fixes
- CVE-2019-1348: the fast-import stream command "feature - CVE-2019-1348: the fast-import stream command "feature
export-marks=path" allows writing to arbitrary file paths. As export-marks=path" allows writing to arbitrary file paths. As
@ -58,54 +342,86 @@ This is a security release fixing the following issues:
recursive submodule clones manually are encouraged to review recursive submodule clones manually are encouraged to review
their implementation for this vulnerability. their implementation for this vulnerability.
v0.28.3 ### Breaking API changes
-------
This is a security release fixing the following issues: * The "private" implementation details of the `git_cred` structure have been
moved to a dedicated `git2/sys/cred.h` header, to clarify that the underlying
structures are only provided for custom transport implementers.
The breaking change is that the `username` member of the underlying struct
is now hidden, and a new `git_cred_get_username` function has been provided.
* A carefully constructed commit object with a very large number ### Breaking CMake configuration changes
of parents may lead to potential out-of-bounds writes or
potential denial of service.
* The ProgramData configuration file is always read for compatibility * The CMake option to use a system http-parser library, instead of the
with Git for Windows and Portable Git installations. The ProgramData bundled dependency, has changed. This is due to a deficiency in
location is not necessarily writable only by administrators, so we http-parser that we have fixed in our implementation. The bundled
now ensure that the configuration file is owned by the administrator library is now the default, but if you wish to force the use of the
or the current user. system http-parser implementation despite incompatibilities, you can
specify `-DUSE_HTTP_PARSER=system` to CMake.
v0.28.2 * The interactions between `USE_HTTPS` and `SHA1_BACKEND` have been
------- streamlined. The detection was moved to a new `USE_SHA1`, modeled after
`USE_HTTPS`, which takes the values "CollisionDetection/Backend/Generic", to
better match how the "hashing backend" is selected, the default (ON) being
"CollisionDetection". If you were using `SHA1_BACKEND` previously, you'll
need to check the value you've used, or switch to the autodetection.
This is a bugfix release with the following changes: ### Authors
* Fix include directory ordering when using bundled dependencies. The following individuals provided changes that were included in this
release:
* Fix infinite loop when searching for a non-existing repository with * Aaron Patterson
Windows-style paths including drive prefixes. * Alberto Fanjul
* Anders Borum
* Fix paths with a trailing "/" not always being treated as * Augie Fackler
directories when computing ignores. * Augustin Fabre
* Ayush Shridhar
* Fix false negatives when computing ignores where ignore rules * brian m. carlson
that are a prefix to a negative ignore rule exist. * buddyspike
* Carlos Martín Nieto
* Fix patches with CRLF line endings not being parsed correctly. * cheese1
* Dan Skorupski
* Fix segfault when parsing patches with file addition (deletion) * Daniel Cohen Gindi
where the added (deleted) file name contains a space. * Dave Lee
* David Brooks
* Fix assertion failure when trying to write to a non-existent * David Turner
locked configuration file. * Denis Laxalde
* Dhruva Krishnamurthy
v0.28.1 * Dominik Ritter
------- * Drew DeVault
* Edward Thomson
This is a bugfix release with the following change: * Eric Huss
* Erik Aigner
* The deprecated functions (`git_buf_free` and the `giterr_` family of * Etienne Samson
functions) are now exported properly. In the v0.28 release, they were * Gregory Herrero
not given the correct external attributes and they did not have the * Heiko Voigt
correct linkage visibility in the v0.28 library. * Ian Hattendorf
* Jacques Germishuys
* Janardhan Pulivarthi
* Jason Haslam
* Johannes Schindelin
* Jordan Wallet
* Josh Bleecher Snyder
* kas
* kdj0c
* Laurence McGlashan
* lhchavez
* Lukas Berk
* Max Kostyukevich
* Patrick Steinhardt
* pcpthm
* Remy Suen
* Robert Coup
* romkatv
* Scott Furry
* Sebastian Henke
* Stefan Widgren
* Steve King Jr
* Sven Strickroth
* Tobias Nießen
* Tyler Ang-Wanek
* Tyler Wanek
v0.28 v0.28
----- -----

View File

@ -3,7 +3,7 @@
libgit2 is currently using [libFuzzer](https://libfuzzer.info) to perform libgit2 is currently using [libFuzzer](https://libfuzzer.info) to perform
automated fuzz testing. libFuzzer only works with clang. automated fuzz testing. libFuzzer only works with clang.
## Prerequisites** for building fuzz targets: ## Prerequisites for building fuzz targets:
1. All the prerequisites for [building libgit2](https://github.com/libgit2/libgit2). 1. All the prerequisites for [building libgit2](https://github.com/libgit2/libgit2).
2. A recent version of clang. 6.0 is preferred. [pre-build Debian/Ubuntu 2. A recent version of clang. 6.0 is preferred. [pre-build Debian/Ubuntu
@ -27,14 +27,15 @@ automated fuzz testing. libFuzzer only works with clang.
## Run the fuzz targets ## Run the fuzz targets
1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize-6.0 1. `ASAN_SYMBOLIZER_PATH=/usr/bin/llvm-symbolize
LSAN_OPTIONS=allocator_may_return_null=1 LSAN_OPTIONS=allocator_may_return_null=1
ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzz/fuzz_packfile_raw ASAN_OPTIONS=allocator_may_return_null=1 ./build/fuzzers/packfile_fuzzer
fuzz/corpora/fuzz_packfile_raw/` fuzzers/corpora/packfile/`
The `LSAN_OPTIONS` and `ASAN_OPTIONS` are there to allow `malloc(3)` to return The `LSAN_OPTIONS` and `ASAN_OPTIONS` are there to allow `malloc(3)` to return
`NULL`. The `LLVM_PROFILE_FILE` is there to override the path where libFuzzer `NULL`, which is expected if a huge chunk of memory is allocated. The
will write the coverage report. `LLVM_PROFILE_FILE` environment string can also be added to override the path
where libFuzzer will write the coverage report.
## Get coverage ## Get coverage

View File

@ -68,7 +68,7 @@ Here we do not use release candidates as the changes are supposed to be small an
This is the same as a maintenance release, except that the fix itself will most likely be developed in a private repository and will only be visible to a select group of people until the release. This is the same as a maintenance release, except that the fix itself will most likely be developed in a private repository and will only be visible to a select group of people until the release.
Everything else remains the same. Occasionally we might opt to backport a security fix to the previous series, based on how recently we started the new series and how serious the issue is. We have committed to providing security fixes for the latest two released versions. E.g. if the latest version is v0.28.x, then we will provide security fixes for both v0.28.x and v0.27.y.
## Updating documentation ## Updating documentation

View File

@ -1,8 +1,10 @@
Threads in libgit2 Threading in libgit2
================== ==================
You may safely use any libgit2 object from any thread, though there Unless otherwise specified, libgit2 objects cannot be safely accessed by
may be issues depending on the cryptographic libraries libgit2 or its multiple threads simultaneously.
There are also caveats on the cryptographic libraries libgit2 or its
dependencies link to (more on this later). For libgit2 itself, dependencies link to (more on this later). For libgit2 itself,
provided you take the following into consideration you won't run into provided you take the following into consideration you won't run into
issues: issues:
@ -26,11 +28,11 @@ The error message is thread-local. The `git_error_last()` call must
happen on the same thread as the error in order to get the happen on the same thread as the error in order to get the
message. Often this will be the case regardless, but if you use message. Often this will be the case regardless, but if you use
something like the [GCD](http://en.wikipedia.org/wiki/Grand_Central_Dispatch) something like the [GCD](http://en.wikipedia.org/wiki/Grand_Central_Dispatch)
on Mac OS X (where code is executed on an arbitrary thread), the code on macOS (where code is executed on an arbitrary thread), the code
must make sure to retrieve the error code on the thread where the error must make sure to retrieve the error code on the thread where the error
happened. happened.
Threads and cryptographic libraries Threading and cryptographic libraries
======================================= =======================================
On Windows On Windows
@ -44,17 +46,11 @@ steps necessary. If you are using a MinGW or similar environment where
libssh2 uses OpenSSL or libgcrypt, then the general case affects libssh2 uses OpenSSL or libgcrypt, then the general case affects
you. you.
On Mac OS X On macOS
----------- -----------
By default we use libcurl to perform the encryption. The By default we make use of CommonCrypto and SecureTransport for cryptographic
system-provided libcurl uses SecureTransport, so no special steps are support. These are thread-safe and you do not need to do anything special.
necessary. If you link against another libcurl (e.g. from homebrew)
refer to the general case.
If the option to use libcurl was deactivated, the library makes use of
CommonCrypto and SecureTransport for cryptographic support. These are
thread-safe and you do not need to do anything special.
Note that libssh2 may still use OpenSSL itself. In that case, the Note that libssh2 may still use OpenSSL itself. In that case, the
general case still affects you if you use ssh. general case still affects you if you use ssh.
@ -62,15 +58,11 @@ general case still affects you if you use ssh.
General Case General Case
------------ ------------
If it's available, by default we use libcurl to provide HTTP tunneling support, libgit2 will default to OpenSSL for HTTPS transport (except on Windows and
which may be linked against a number of cryptographic libraries and has its macOS, as mentioned above). On any system, mbedTLS _may_ be optionally
own enabled as the security provider. OpenSSL is thread-safe starting at
[recommendations for thread safety](https://curl.haxx.se/libcurl/c/threadsafe.html). version 1.1.0. If your copy of libgit2 is linked against that version,
you do not need to take any further steps.
If there are no alternative TLS implementations (currently only
SecureTransport), libgit2 uses OpenSSL in order to use HTTPS as a transport.
OpenSSL is thread-safe starting at version 1.1.0. If your copy of libgit2 is
linked against that version, you do not need to take any further steps.
Older versions of OpenSSL are made to be thread-implementation agnostic, and the Older versions of OpenSSL are made to be thread-implementation agnostic, and the
users of the library must set which locking function it should use. libgit2 users of the library must set which locking function it should use. libgit2
@ -78,10 +70,10 @@ cannot know what to set as the user of libgit2 may also be using OpenSSL indepen
the locking settings must then live outside the lifetime of libgit2. the locking settings must then live outside the lifetime of libgit2.
Even if libgit2 doesn't use OpenSSL directly, OpenSSL can still be used by Even if libgit2 doesn't use OpenSSL directly, OpenSSL can still be used by
libssh2 or libcurl depending on the configuration. If OpenSSL is used by libssh2 depending on the configuration. If OpenSSL is used by
more than one library, you only need to set up threading for OpenSSL once. more than one library, you only need to set up threading for OpenSSL once.
If libgit2 is linked against OpenSSL, it provides a last-resort convenience function If libgit2 is linked against OpenSSL < 1.1.0, it provides a last-resort convenience function
`git_openssl_set_locking()` (available in `sys/openssl.h`) to use the `git_openssl_set_locking()` (available in `sys/openssl.h`) to use the
platform-native mutex mechanisms to perform the locking, which you can use platform-native mutex mechanisms to perform the locking, which you can use
if you do not want to use OpenSSL outside of libgit2, or you if you do not want to use OpenSSL outside of libgit2, or you
@ -89,7 +81,7 @@ know that libgit2 will outlive the rest of the operations. It is then not
safe to use OpenSSL multi-threaded after libgit2's shutdown function safe to use OpenSSL multi-threaded after libgit2's shutdown function
has been called. Note `git_openssl_set_locking()` only works if has been called. Note `git_openssl_set_locking()` only works if
libgit2 uses OpenSSL directly - if OpenSSL is only used as a dependency libgit2 uses OpenSSL directly - if OpenSSL is only used as a dependency
of libssh2 or libcurl as described above, `git_openssl_set_locking()` is a no-op. of libssh2 as described above, `git_openssl_set_locking()` is a no-op.
If your programming language offers a package/bindings for OpenSSL, If your programming language offers a package/bindings for OpenSSL,
you should very strongly prefer to use that in order to set up you should very strongly prefer to use that in order to set up

View File

@ -1,25 +1,15 @@
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES}) INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES}) INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
FILE(GLOB_RECURSE SRC_EXAMPLE_GIT2 network/*.c network/*.h common.?) FILE(GLOB LG2_SOURCES *.c *.h)
ADD_EXECUTABLE(cgit2 ${SRC_EXAMPLE_GIT2}) ADD_EXECUTABLE(lg2 ${LG2_SOURCES})
SET_TARGET_PROPERTIES(cgit2 PROPERTIES C_STANDARD 90) SET_TARGET_PROPERTIES(lg2 PROPERTIES C_STANDARD 90)
# Ensure that we do not use deprecated functions internally # Ensure that we do not use deprecated functions internally
ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD) ADD_DEFINITIONS(-DGIT_DEPRECATE_HARD)
IF(WIN32 OR ANDROID) IF(WIN32 OR ANDROID)
TARGET_LINK_LIBRARIES(cgit2 git2) TARGET_LINK_LIBRARIES(lg2 git2)
ELSE() ELSE()
TARGET_LINK_LIBRARIES(cgit2 git2 pthread) TARGET_LINK_LIBRARIES(lg2 git2 pthread)
ENDIF() 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)
SET_TARGET_PROPERTIES(${app_name} PROPERTIES C_STANDARD 90)
ENDIF()
ENDFOREACH()

View File

@ -13,85 +13,97 @@
*/ */
#include "common.h" #include "common.h"
#include <assert.h>
enum print_options { /**
SKIP = 1, * The following example demonstrates how to add files with libgit2.
VERBOSE = 2, *
UPDATE = 4, * It will use the repository in the current working directory, and act
* on files passed as its parameters.
*
* Recognized options are:
* -v/--verbose: show the file's status after acting on it.
* -n/--dry-run: do not actually change the index.
* -u/--update: update the index instead of adding to it.
*/
enum index_mode {
INDEX_NONE,
INDEX_ADD,
}; };
struct print_payload { struct index_options {
enum print_options options; int dry_run;
int verbose;
git_repository *repo; git_repository *repo;
enum index_mode mode;
int add_update;
}; };
/* Forward declarations for helpers */ /* Forward declarations for helpers */
static void parse_opts(int *options, int *count, int argc, char *argv[]); static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args);
void init_array(git_strarray *array, int argc, char **argv);
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload); int print_matched_cb(const char *path, const char *matched_pathspec, void *payload);
int main (int argc, char** argv) int lg2_add(git_repository *repo, int argc, char **argv)
{ {
git_index_matched_path_cb matched_cb = NULL; git_index_matched_path_cb matched_cb = NULL;
git_repository *repo = NULL;
git_index *index; git_index *index;
git_strarray array = {0}; git_strarray array = {0};
int options = 0, count = 0; struct index_options options;
struct print_payload payload = {0}; struct args_info args = ARGS_INFO_INIT;
git_libgit2_init(); /* Parse the options & arguments. */
parse_opts(NULL, &options, &args);
strarray_from_args(&array, &args);
parse_opts(&options, &count, argc, argv); /* Grab the repository's index. */
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); check_lg2(git_repository_index(&index, repo), "Could not open repository index", NULL);
if (options&VERBOSE || options&SKIP) { /* Setup a callback if the requested options need it */
if (options.verbose || options.dry_run) {
matched_cb = &print_matched_cb; matched_cb = &print_matched_cb;
} }
payload.options = options; options.repo = repo;
payload.repo = repo;
if (options&UPDATE) { /* Perform the requested action with the index and files */
git_index_update_all(index, &array, matched_cb, &payload); if (options.add_update) {
git_index_update_all(index, &array, matched_cb, &options);
} else { } else {
git_index_add_all(index, &array, 0, matched_cb, &payload); git_index_add_all(index, &array, 0, matched_cb, &options);
} }
/* Cleanup memory */
git_index_write(index); git_index_write(index);
git_index_free(index); git_index_free(index);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
/*
* This callback is called for each file under consideration by
* git_index_(update|add)_all above.
* It makes uses of the callback's ability to abort the action.
*/
int print_matched_cb(const char *path, const char *matched_pathspec, void *payload) int print_matched_cb(const char *path, const char *matched_pathspec, void *payload)
{ {
struct print_payload p = *(struct print_payload*)(payload); struct index_options *opts = (struct index_options *)(payload);
int ret; int ret;
unsigned status; unsigned status;
(void)matched_pathspec; (void)matched_pathspec;
if (git_status_file(&status, p.repo, path)) { /* Get the file status */
if (git_status_file(&status, opts->repo, path) < 0)
return -1; return -1;
}
if (status & GIT_STATUS_WT_MODIFIED || status & GIT_STATUS_WT_NEW) { if ((status & GIT_STATUS_WT_MODIFIED) || (status & GIT_STATUS_WT_NEW)) {
printf("add '%s'\n", path); printf("add '%s'\n", path);
ret = 0; ret = 0;
} else { } else {
ret = 1; ret = 1;
} }
if(p.options & SKIP) { if (opts->dry_run)
ret = 1; ret = 1;
}
return ret; return ret;
} }
@ -101,11 +113,11 @@ void init_array(git_strarray *array, int argc, char **argv)
unsigned int i; unsigned int i;
array->count = argc; array->count = argc;
array->strings = malloc(sizeof(char*) * array->count); array->strings = calloc(array->count, sizeof(char *));
assert(array->strings!=NULL); assert(array->strings != NULL);
for(i=0; i<array->count; i++) { for (i = 0; i < array->count; i++) {
array->strings[i]=argv[i]; array->strings[i] = argv[i];
} }
return; return;
@ -120,39 +132,39 @@ void print_usage(void)
exit(1); exit(1);
} }
static void parse_opts(int *options, int *count, int argc, char *argv[]) static void parse_opts(const char **repo_path, struct index_options *opts, struct args_info *args)
{ {
int i; if (args->argc <= 1)
print_usage();
for (i = 1; i < argc; ++i) { for (args->pos = 1; args->pos < args->argc; ++args->pos) {
if (argv[i][0] != '-') { const char *curr = args->argv[args->pos];
break;
} if (curr[0] != '-') {
else if(!strcmp(argv[i], "--verbose") || !strcmp(argv[i], "-v")) { if (!strcmp("add", curr)) {
*options |= VERBOSE; opts->mode = INDEX_ADD;
} continue;
else if(!strcmp(argv[i], "--dry-run") || !strcmp(argv[i], "-n")) { } else if (opts->mode == INDEX_NONE) {
*options |= SKIP; fprintf(stderr, "missing command: %s", curr);
} print_usage();
else if(!strcmp(argv[i], "--update") || !strcmp(argv[i], "-u")) { break;
*options |= UPDATE; } else {
} /* We might be looking at a filename */
else if(!strcmp(argv[i], "-h")) { break;
}
} else if (match_bool_arg(&opts->verbose, args, "--verbose") ||
match_bool_arg(&opts->dry_run, args, "--dry-run") ||
match_str_arg(repo_path, args, "--git-dir") ||
(opts->mode == INDEX_ADD && match_bool_arg(&opts->add_update, args, "--update"))) {
continue;
} else if (match_bool_arg(NULL, args, "--help")) {
print_usage(); print_usage();
break; break;
} } else if (match_arg_separator(args)) {
else if(!strcmp(argv[i], "--")) {
i++;
break; break;
} } else {
else { fprintf(stderr, "Unsupported option %s.\n", curr);
fprintf(stderr, "Unsupported option %s.\n", argv[i]);
print_usage(); print_usage();
} }
} }
if (argc<=i)
print_usage();
*count = i;
} }

197
examples/args.c Normal file
View File

@ -0,0 +1,197 @@
#include "common.h"
#include "args.h"
size_t is_prefixed(const char *str, const char *pfx)
{
size_t len = strlen(pfx);
return strncmp(str, pfx, len) ? 0 : len;
}
int optional_str_arg(
const char **out, struct args_info *args, const char *opt, const char *def)
{
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) {
*out = def;
return 1;
}
args->pos += 1;
*out = args->argv[args->pos];
return 1;
}
if (found[len] == '=') {
*out = found + len + 1;
return 1;
}
return 0;
}
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;
}
int match_uint32_arg(
uint32_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 = (uint32_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 match_bool_arg(int *out, struct args_info *args, const char *opt)
{
const char *found = args->argv[args->pos];
if (!strcmp(found, opt)) {
*out = 1;
return 1;
}
if (!strncmp(found, "--no-", strlen("--no-")) &&
!strcmp(found + strlen("--no-"), opt + 2)) {
*out = 0;
return 1;
}
*out = -1;
return 0;
}
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 match_arg_separator(struct args_info *args)
{
if (args->opts_done)
return 1;
if (strcmp(args->argv[args->pos], "--") != 0)
return 0;
args->opts_done = 1;
args->pos++;
return 1;
}
void strarray_from_args(git_strarray *array, struct args_info *args)
{
size_t i;
array->count = args->argc - args->pos;
array->strings = calloc(array->count, sizeof(char *));
assert(array->strings != NULL);
for (i = 0; args->pos < args->argc; ++args->pos) {
array->strings[i++] = args->argv[args->pos];
}
args->pos = args->argc;
}

90
examples/args.h Normal file
View File

@ -0,0 +1,90 @@
#ifndef INCLUDE_examples_args_h__
#define INCLUDE_examples_args_h__
/**
* Argument-processing helper structure
*/
struct args_info {
int argc;
char **argv;
int pos;
int opts_done : 1; /**< Did we see a -- separator */
};
#define ARGS_INFO_INIT { argc, argv, 0, 0 }
#define ARGS_CURRENT(args) args->argv[args->pos]
/**
* 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);
/**
* 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; if value not supplied,
* default value `def` will be given. otherwise return 0.
*/
extern int optional_str_arg(
const char **out, struct args_info *args, const char *opt, const char *def);
/**
* 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 uint32. 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
* uint32_t value; otherwise return 0.
*/
extern int match_uint32_arg(
uint32_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);
/**
* Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
* If `opt` matches positively, out will be set to 1, or if `opt` matches
* negatively, out will be set to 0, and in both cases 1 will be returned.
* If neither the positive or the negative form of opt matched, out will be -1,
* and 0 will be returned.
*/
extern int match_bool_arg(int *out, struct args_info *args, const char *opt);
/**
* Check if we're processing past the single -- separator
*/
extern int match_arg_separator(struct args_info *args);
/**
* Consume all remaining arguments in a git_strarray
*/
extern void strarray_from_args(git_strarray *array, struct args_info *args);
#endif

View File

@ -14,17 +14,12 @@
#include "common.h" #include "common.h"
#ifdef _MSC_VER
#define snprintf sprintf_s
#define strcasecmp strcmpi
#endif
/** /**
* This example demonstrates how to invoke the libgit2 blame API to roughly * 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. * simulate the output of `git blame` and a few of its command line arguments.
*/ */
struct opts { struct blame_opts {
char *path; char *path;
char *commitspec; char *commitspec;
int C; int C;
@ -33,32 +28,26 @@ struct opts {
int end_line; int end_line;
int F; int F;
}; };
static void parse_opts(struct opts *o, int argc, char *argv[]); static void parse_opts(struct blame_opts *o, int argc, char *argv[]);
int main(int argc, char *argv[]) int lg2_blame(git_repository *repo, int argc, char *argv[])
{ {
int line, break_on_null_hunk; int line, break_on_null_hunk;
size_t i, rawsize; git_object_size_t i, rawsize;
char spec[1024] = {0}; char spec[1024] = {0};
struct opts o = {0}; struct blame_opts o = {0};
const char *rawdata; const char *rawdata;
git_repository *repo = NULL;
git_revspec revspec = {0}; git_revspec revspec = {0};
git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT; git_blame_options blameopts = GIT_BLAME_OPTIONS_INIT;
git_blame *blame = NULL; git_blame *blame = NULL;
git_blob *blob; git_blob *blob;
git_object *obj; git_object *obj;
git_libgit2_init();
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES; if (o.M) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES;
if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES; if (o.C) blameopts.flags |= GIT_BLAME_TRACK_COPIES_SAME_COMMIT_COPIES;
if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT; if (o.F) blameopts.flags |= GIT_BLAME_FIRST_PARENT;
/** 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 * The commit range comes in "commitish" form. Use the rev-parse API to
* nail down the end points. * nail down the end points.
@ -83,7 +72,7 @@ int main(int argc, char *argv[])
* Get the raw data inside the blob for output. We use the * Get the raw data inside the blob for output. We use the
* `commitish:path/to/file.txt` format to find it. * `commitish:path/to/file.txt` format to find it.
*/ */
if (git_oid_iszero(&blameopts.newest_commit)) if (git_oid_is_zero(&blameopts.newest_commit))
strcpy(spec, "HEAD"); strcpy(spec, "HEAD");
else else
git_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit); git_oid_tostr(spec, sizeof(spec), &blameopts.newest_commit);
@ -102,7 +91,7 @@ int main(int argc, char *argv[])
i = 0; i = 0;
break_on_null_hunk = 0; break_on_null_hunk = 0;
while (i < rawsize) { while (i < rawsize) {
const char *eol = memchr(rawdata + i, '\n', rawsize - i); const char *eol = memchr(rawdata + i, '\n', (size_t)(rawsize - i));
char oid[10] = {0}; char oid[10] = {0};
const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line); const git_blame_hunk *hunk = git_blame_get_hunk_byline(blame, line);
@ -112,7 +101,7 @@ int main(int argc, char *argv[])
if (hunk) { if (hunk) {
char sig[128] = {0}; char sig[128] = {0};
break_on_null_hunk = 1; break_on_null_hunk = 1;
git_oid_tostr(oid, 10, &hunk->final_commit_id); git_oid_tostr(oid, 10, &hunk->final_commit_id);
snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email); snprintf(sig, 30, "%s <%s>", hunk->final_signature->name, hunk->final_signature->email);
@ -131,9 +120,6 @@ int main(int argc, char *argv[])
/** Cleanup. */ /** Cleanup. */
git_blob_free(blob); git_blob_free(blob);
git_blame_free(blame); git_blame_free(blame);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -157,7 +143,7 @@ static void usage(const char *msg, const char *arg)
} }
/** Parse the arguments. */ /** Parse the arguments. */
static void parse_opts(struct opts *o, int argc, char *argv[]) static void parse_opts(struct blame_opts *o, int argc, char *argv[])
{ {
int i; int i;
char *bare_args[3] = {0}; char *bare_args[3] = {0};

View File

@ -102,37 +102,33 @@ static void show_tag(const git_tag *tag)
printf("\n%s\n", git_tag_message(tag)); printf("\n%s\n", git_tag_message(tag));
} }
enum { typedef enum {
SHOW_TYPE = 1, SHOW_TYPE = 1,
SHOW_SIZE = 2, SHOW_SIZE = 2,
SHOW_NONE = 3, SHOW_NONE = 3,
SHOW_PRETTY = 4 SHOW_PRETTY = 4
}; } catfile_mode;
/* Forward declarations for option-parsing helper */ /* Forward declarations for option-parsing helper */
struct opts { struct catfile_options {
const char *dir; const char *dir;
const char *rev; const char *rev;
int action; catfile_mode action;
int verbose; int verbose;
}; };
static void parse_opts(struct opts *o, int argc, char *argv[]);
static void parse_opts(struct catfile_options *o, int argc, char *argv[]);
/** Entry point for this command */ /** Entry point for this command */
int main(int argc, char *argv[]) int lg2_cat_file(git_repository *repo, int argc, char *argv[])
{ {
git_repository *repo; struct catfile_options o = { ".", NULL, 0, 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_libgit2_init();
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
check_lg2(git_repository_open_ext(&repo, o.dir, 0, NULL),
"Could not open repository", NULL);
check_lg2(git_revparse_single(&obj, repo, o.rev), check_lg2(git_revparse_single(&obj, repo, o.rev),
"Could not resolve", o.rev); "Could not resolve", o.rev);
@ -188,9 +184,6 @@ int main(int argc, char *argv[])
} }
git_object_free(obj); git_object_free(obj);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -209,7 +202,7 @@ static void usage(const char *message, const char *arg)
} }
/** Parse the command-line options taken from git */ /** Parse the command-line options taken from git */
static void parse_opts(struct opts *o, int argc, char *argv[]) static void parse_opts(struct catfile_options *o, int argc, char *argv[])
{ {
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;

View File

@ -13,7 +13,6 @@
*/ */
#include "common.h" #include "common.h"
#include <assert.h>
/* 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__)
@ -66,7 +65,7 @@ static void parse_options(const char **repo_path, checkout_options *opts, struct
const char *curr = args->argv[args->pos]; const char *curr = args->argv[args->pos];
int bool_arg; int bool_arg;
if (strcmp(curr, "--") == 0) { if (match_arg_separator(args)) {
break; break;
} else if (!strcmp(curr, "--force")) { } else if (!strcmp(curr, "--force")) {
opts->force = 1; opts->force = 1;
@ -112,9 +111,10 @@ static void print_perf_data(const git_checkout_perfdata *perfdata, void *payload
* This is the main "checkout <branch>" function, responsible for performing * This is the main "checkout <branch>" function, responsible for performing
* a branch-based checkout. * a branch-based checkout.
*/ */
static int perform_checkout_ref(git_repository *repo, git_annotated_commit *target, checkout_options *opts) static int perform_checkout_ref(git_repository *repo, git_annotated_commit *target, const char *target_ref, checkout_options *opts)
{ {
git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT; git_checkout_options checkout_opts = GIT_CHECKOUT_OPTIONS_INIT;
git_reference *ref = NULL, *branch = NULL;
git_commit *target_commit = NULL; git_commit *target_commit = NULL;
int err; int err;
@ -156,10 +156,25 @@ static int perform_checkout_ref(git_repository *repo, git_annotated_commit *targ
* we might need to detach HEAD. * we might need to detach HEAD.
*/ */
if (git_annotated_commit_ref(target)) { if (git_annotated_commit_ref(target)) {
err = git_repository_set_head(repo, git_annotated_commit_ref(target)); const char *target_head;
if ((err = git_reference_lookup(&ref, repo, git_annotated_commit_ref(target))) < 0)
goto error;
if (git_reference_is_remote(ref)) {
if ((err = git_branch_create_from_annotated(&branch, repo, target_ref, target, 0)) < 0)
goto error;
target_head = git_reference_name(branch);
} else {
target_head = git_annotated_commit_ref(target);
}
err = git_repository_set_head(repo, target_head);
} else { } else {
err = git_repository_set_head_detached_from_annotated(repo, target); err = git_repository_set_head_detached_from_annotated(repo, target);
} }
error:
if (err != 0) { if (err != 0) {
fprintf(stderr, "failed to update HEAD reference: %s\n", git_error_last()->message); fprintf(stderr, "failed to update HEAD reference: %s\n", git_error_last()->message);
goto cleanup; goto cleanup;
@ -167,14 +182,70 @@ static int perform_checkout_ref(git_repository *repo, git_annotated_commit *targ
cleanup: cleanup:
git_commit_free(target_commit); git_commit_free(target_commit);
git_reference_free(branch);
git_reference_free(ref);
return err; return err;
} }
/** That example's entry point */ /**
int main(int argc, char **argv) * This corresponds to `git switch --guess`: if a given ref does
* not exist, git will by default try to guess the reference by
* seeing whether any remote has a branch called <ref>. If there
* is a single remote only that has it, then it is assumed to be
* the desired reference and a local branch is created for it.
*
* The following is a simplified implementation. It will not try
* to check whether the ref is unique across all remotes.
*/
static int guess_refish(git_annotated_commit **out, git_repository *repo, const char *ref)
{
git_strarray remotes = { NULL, 0 };
git_reference *remote_ref = NULL;
int error;
size_t i;
if ((error = git_remote_list(&remotes, repo)) < 0)
goto out;
for (i = 0; i < remotes.count; i++) {
char *refname = NULL;
size_t reflen;
reflen = snprintf(refname, 0, "refs/remotes/%s/%s", remotes.strings[i], ref);
if ((refname = malloc(reflen + 1)) == NULL) {
error = -1;
goto next;
}
snprintf(refname, reflen + 1, "refs/remotes/%s/%s", remotes.strings[i], ref);
if ((error = git_reference_lookup(&remote_ref, repo, refname)) < 0)
goto next;
break;
next:
free(refname);
if (error < 0 && error != GIT_ENOTFOUND)
break;
}
if (!remote_ref) {
error = GIT_ENOTFOUND;
goto out;
}
if ((error = git_annotated_commit_from_ref(out, repo, remote_ref)) < 0)
goto out;
out:
git_reference_free(remote_ref);
git_strarray_free(&remotes);
return error;
}
/** That example's entry point */
int lg2_checkout(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo = NULL;
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;
checkout_options opts; checkout_options opts;
git_repository_state_t state; git_repository_state_t state;
@ -185,15 +256,6 @@ int main(int argc, char **argv)
/** Parse our command line options */ /** Parse our command line options */
parse_options(&path, &opts, &args); parse_options(&path, &opts, &args);
/** Initialize the library */
err = git_libgit2_init();
if (!err)
check_lg2(err, "Failed to initialize libgit2", NULL);
/** Open the repository corresponding to the options */
check_lg2(git_repository_open_ext(&repo, path, 0, NULL),
"Could not open repository", NULL);
/** Make sure we're not about to checkout while something else is going on */ /** Make sure we're not about to checkout while something else is going on */
state = git_repository_state(repo); state = git_repository_state(repo);
if (state != GIT_REPOSITORY_STATE_NONE) { if (state != GIT_REPOSITORY_STATE_NONE) {
@ -201,11 +263,7 @@ int main(int argc, char **argv)
goto cleanup; goto cleanup;
} }
if (args.pos >= args.argc) { if (match_arg_separator(&args)) {
fprintf(stderr, "unhandled\n");
err = -1;
goto cleanup;
} else if (strcmp("--", args.argv[args.pos])) {
/** /**
* Try to checkout the given path * Try to checkout the given path
*/ */
@ -217,19 +275,16 @@ int main(int argc, char **argv)
/** /**
* Try to resolve a "refish" argument to a target libgit2 can use * Try to resolve a "refish" argument to a target libgit2 can use
*/ */
err = resolve_refish(&checkout_target, repo, args.argv[args.pos]); if ((err = resolve_refish(&checkout_target, repo, args.argv[args.pos])) < 0 &&
if (err != 0) { (err = guess_refish(&checkout_target, repo, args.argv[args.pos])) < 0) {
fprintf(stderr, "failed to resolve %s: %s\n", args.argv[args.pos], git_error_last()->message); fprintf(stderr, "failed to resolve %s: %s\n", args.argv[args.pos], git_error_last()->message);
goto cleanup; goto cleanup;
} }
err = perform_checkout_ref(repo, checkout_target, &opts); err = perform_checkout_ref(repo, checkout_target, args.argv[args.pos], &opts);
} }
cleanup: cleanup:
git_annotated_commit_free(checkout_target); git_annotated_commit_free(checkout_target);
git_repository_free(repo);
git_libgit2_shutdown();
return err; return err;
} }

View File

@ -1,16 +1,7 @@
#include "common.h" #include "common.h"
#include <git2.h>
#include <git2/clone.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
# include <pthread.h>
# include <unistd.h>
#endif
typedef struct progress_data { typedef struct progress_data {
git_transfer_progress fetch_progress; git_indexer_progress fetch_progress;
size_t completed_steps; size_t completed_steps;
size_t total_steps; size_t total_steps;
const char *path; const char *path;
@ -26,17 +17,17 @@ static void print_progress(const progress_data *pd)
0; 0;
int checkout_percent = pd->total_steps > 0 int checkout_percent = pd->total_steps > 0
? (100 * pd->completed_steps) / pd->total_steps ? (int)((100 * pd->completed_steps) / pd->total_steps)
: 0; : 0;
int kbytes = pd->fetch_progress.received_bytes / 1024; size_t kbytes = pd->fetch_progress.received_bytes / 1024;
if (pd->fetch_progress.total_objects && if (pd->fetch_progress.total_objects &&
pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) { pd->fetch_progress.received_objects == pd->fetch_progress.total_objects) {
printf("Resolving deltas %d/%d\r", printf("Resolving deltas %u/%u\r",
pd->fetch_progress.indexed_deltas, pd->fetch_progress.indexed_deltas,
pd->fetch_progress.total_deltas); pd->fetch_progress.total_deltas);
} else { } else {
printf("net %3d%% (%4d kb, %5d/%5d) / idx %3d%% (%5d/%5d) / chk %3d%% (%4" PRIuZ "/%4" PRIuZ ") %s\n", printf("net %3d%% (%4" PRIuZ " kb, %5u/%5u) / idx %3d%% (%5u/%5u) / 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,
@ -55,7 +46,7 @@ static int sideband_progress(const char *str, int len, void *payload)
return 0; return 0;
} }
static int fetch_progress(const git_transfer_progress *stats, void *payload) static int fetch_progress(const git_indexer_progress *stats, void *payload)
{ {
progress_data *pd = (progress_data*)payload; progress_data *pd = (progress_data*)payload;
pd->fetch_progress = *stats; pd->fetch_progress = *stats;
@ -72,7 +63,7 @@ static void checkout_progress(const char *path, size_t cur, size_t tot, void *pa
} }
int do_clone(git_repository *repo, int argc, char **argv) int lg2_clone(git_repository *repo, int argc, char **argv)
{ {
progress_data pd = {{0}}; progress_data pd = {{0}};
git_repository *cloned_repo = NULL; git_repository *cloned_repo = NULL;

View File

@ -12,10 +12,14 @@
* <http://creativecommons.org/publicdomain/zero/1.0/>. * <http://creativecommons.org/publicdomain/zero/1.0/>.
*/ */
#include <assert.h>
#include "common.h" #include "common.h"
#ifndef _WIN32
# include <unistd.h>
#endif
#include <errno.h>
void check_lg2(int error, const char *message, const char *extra) void check_lg2(int error, const char *message, const char *extra)
{ {
const git_error *lg2err; const git_error *lg2err;
@ -49,174 +53,6 @@ void fatal(const char *message, const char *extra)
exit(1); 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 optional_str_arg(
const char **out, struct args_info *args, const char *opt, const char *def)
{
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) {
*out = def;
return 1;
}
args->pos += 1;
*out = args->argv[args->pos];
return 1;
}
if (found[len] == '=') {
*out = found + len + 1;
return 1;
}
return 0;
}
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;
}
int match_uint32_arg(
uint32_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 = (uint32_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 match_bool_arg(int *out, struct args_info *args, const char *opt)
{
const char *found = args->argv[args->pos];
if (!strcmp(found, opt)) {
*out = 1;
return 1;
}
if (!strncmp(found, "--no-", strlen("--no-")) &&
!strcmp(found + strlen("--no-"), opt + 2)) {
*out = 0;
return 1;
}
*out = -1;
return 0;
}
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( int diff_output(
const git_diff_delta *d, const git_diff_delta *d,
const git_diff_hunk *h, const git_diff_hunk *h,
@ -289,3 +125,136 @@ int resolve_refish(git_annotated_commit **commit, git_repository *repo, const ch
return err; return err;
} }
static int readline(char **out)
{
int c, error = 0, length = 0, allocated = 0;
char *line = NULL;
errno = 0;
while ((c = getchar()) != EOF) {
if (length == allocated) {
allocated += 16;
if ((line = realloc(line, allocated)) == NULL) {
error = -1;
goto error;
}
}
if (c == '\n')
break;
line[length++] = c;
}
if (errno != 0) {
error = -1;
goto error;
}
line[length] = '\0';
*out = line;
line = NULL;
error = length;
error:
free(line);
return error;
}
static int ask(char **out, const char *prompt, char optional)
{
printf("%s ", prompt);
fflush(stdout);
if (!readline(out) && !optional) {
fprintf(stderr, "Could not read response: %s", strerror(errno));
return -1;
}
return 0;
}
int cred_acquire_cb(git_credential **out,
const char *url,
const char *username_from_url,
unsigned int allowed_types,
void *payload)
{
char *username = NULL, *password = NULL, *privkey = NULL, *pubkey = NULL;
int error = 1;
UNUSED(url);
UNUSED(payload);
if (username_from_url) {
if ((username = strdup(username_from_url)) == NULL)
goto out;
} else if ((error = ask(&username, "Username:", 0)) < 0) {
goto out;
}
if (allowed_types & GIT_CREDENTIAL_SSH_KEY) {
int n;
if ((error = ask(&privkey, "SSH Key:", 0)) < 0 ||
(error = ask(&password, "Password:", 1)) < 0)
goto out;
if ((n = snprintf(NULL, 0, "%s.pub", privkey)) < 0 ||
(pubkey = malloc(n + 1)) == NULL ||
(n = snprintf(pubkey, n + 1, "%s.pub", privkey)) < 0)
goto out;
error = git_credential_ssh_key_new(out, username, pubkey, privkey, password);
} else if (allowed_types & GIT_CREDENTIAL_USERPASS_PLAINTEXT) {
if ((error = ask(&password, "Password:", 1)) < 0)
goto out;
error = git_credential_userpass_plaintext_new(out, username, password);
} else if (allowed_types & GIT_CREDENTIAL_USERNAME) {
error = git_credential_username_new(out, username);
}
out:
free(username);
free(password);
free(privkey);
free(pubkey);
return error;
}
char *read_file(const char *path)
{
ssize_t total = 0;
char *buf = NULL;
struct stat st;
int fd = -1;
if ((fd = open(path, O_RDONLY)) < 0 || fstat(fd, &st) < 0)
goto out;
if ((buf = malloc(st.st_size + 1)) == NULL)
goto out;
while (total < st.st_size) {
ssize_t bytes = read(fd, buf + total, st.st_size - total);
if (bytes <= 0) {
if (errno == EAGAIN || errno == EINTR)
continue;
free(buf);
buf = NULL;
goto out;
}
total += bytes;
}
buf[total] = '\0';
out:
if (fd >= 0)
close(fd);
return buf;
}

View File

@ -11,11 +11,73 @@
* with this software. If not, see * with this software. If not, see
* <http://creativecommons.org/publicdomain/zero/1.0/>. * <http://creativecommons.org/publicdomain/zero/1.0/>.
*/ */
#ifndef INCLUDE_examples_common_h__
#define INCLUDE_examples_common_h__
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <git2.h> #include <git2.h>
#include <fcntl.h>
#ifdef _WIN32
# include <io.h>
# include <Windows.h>
# define open _open
# define read _read
# define close _close
# define ssize_t int
# define sleep(a) Sleep(a * 1000)
#else
# include <unistd.h>
#endif
#ifndef PRIuZ
/* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__)
# define PRIuZ "Iu"
#else
# define PRIuZ "zu"
#endif
#endif
#ifdef _MSC_VER
#define snprintf sprintf_s
#define strcasecmp strcmpi
#endif
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(*x))
#define UNUSED(x) (void)(x)
#include "args.h"
extern int lg2_add(git_repository *repo, int argc, char **argv);
extern int lg2_blame(git_repository *repo, int argc, char **argv);
extern int lg2_cat_file(git_repository *repo, int argc, char **argv);
extern int lg2_checkout(git_repository *repo, int argc, char **argv);
extern int lg2_clone(git_repository *repo, int argc, char **argv);
extern int lg2_config(git_repository *repo, int argc, char **argv);
extern int lg2_describe(git_repository *repo, int argc, char **argv);
extern int lg2_diff(git_repository *repo, int argc, char **argv);
extern int lg2_fetch(git_repository *repo, int argc, char **argv);
extern int lg2_for_each_ref(git_repository *repo, int argc, char **argv);
extern int lg2_general(git_repository *repo, int argc, char **argv);
extern int lg2_index_pack(git_repository *repo, int argc, char **argv);
extern int lg2_init(git_repository *repo, int argc, char **argv);
extern int lg2_log(git_repository *repo, int argc, char **argv);
extern int lg2_ls_files(git_repository *repo, int argc, char **argv);
extern int lg2_ls_remote(git_repository *repo, int argc, char **argv);
extern int lg2_merge(git_repository *repo, int argc, char **argv);
extern int lg2_remote(git_repository *repo, int argc, char **argv);
extern int lg2_rev_list(git_repository *repo, int argc, char **argv);
extern int lg2_rev_parse(git_repository *repo, int argc, char **argv);
extern int lg2_show_index(git_repository *repo, int argc, char **argv);
extern int lg2_stash(git_repository *repo, int argc, char **argv);
extern int lg2_status(git_repository *repo, int argc, char **argv);
extern int lg2_tag(git_repository *repo, int argc, char **argv);
/** /**
* Check libgit2 error code, printing error to stderr on failure and * Check libgit2 error code, printing error to stderr on failure and
@ -23,82 +85,19 @@
*/ */
extern void check_lg2(int error, const char *message, const char *extra); extern void check_lg2(int error, const char *message, const char *extra);
/**
* Read a file into a buffer
*
* @param path The path to the file that shall be read
* @return NUL-terminated buffer if the file was successfully read, NULL-pointer otherwise
*/
extern char *read_file(const char *path);
/** /**
* Exit the program, printing error to stderr * Exit the program, printing error to stderr
*/ */
extern void fatal(const char *message, const char *extra); 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; if value not supplied,
* default value `def` will be given. otherwise return 0.
*/
extern int optional_str_arg(
const char **out, struct args_info *args, const char *opt, const char *def);
/**
* 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 uint32. 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
* uint32_t value; otherwise return 0.
*/
extern int match_uint32_arg(
uint32_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);
/**
* Check current `args` entry against a "bool" `opt` (ie. --[no-]progress).
* If `opt` matches positively, out will be set to 1, or if `opt` matches
* negatively, out will be set to 0, and in both cases 1 will be returned.
* If neither the positive or the negative form of opt matched, out will be -1,
* and 0 will be returned.
*/
extern int match_bool_arg(int *out, struct args_info *args, const char *opt);
/** /**
* Basic output function for plain text diff output * Basic output function for plain text diff output
* Pass `FILE*` such as `stdout` or `stderr` as payload (or NULL == `stdout`) * Pass `FILE*` such as `stdout` or `stderr` as payload (or NULL == `stdout`)
@ -122,3 +121,14 @@ extern void *xrealloc(void *oldp, size_t newsz);
* Convert a refish to an annotated commit. * Convert a refish to an annotated commit.
*/ */
extern int resolve_refish(git_annotated_commit **commit, git_repository *repo, const char *refish); extern int resolve_refish(git_annotated_commit **commit, git_repository *repo, const char *refish);
/**
* Acquire credentials via command line
*/
extern int cred_acquire_cb(git_credential **out,
const char *url,
const char *username_from_url,
unsigned int allowed_types,
void *payload);
#endif

62
examples/config.c Normal file
View File

@ -0,0 +1,62 @@
/*
* libgit2 "config" example - shows how to use the config 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"
static int config_get(git_config *cfg, const char *key)
{
git_config_entry *entry;
int error;
if ((error = git_config_get_entry(&entry, cfg, key)) < 0) {
if (error != GIT_ENOTFOUND)
printf("Unable to get configuration: %s\n", git_error_last()->message);
return 1;
}
puts(entry->value);
return 0;
}
static int config_set(git_config *cfg, const char *key, const char *value)
{
if (git_config_set_string(cfg, key, value) < 0) {
printf("Unable to set configuration: %s\n", git_error_last()->message);
return 1;
}
return 0;
}
int lg2_config(git_repository *repo, int argc, char **argv)
{
git_config *cfg;
int error;
if ((error = git_repository_config(&cfg, repo)) < 0) {
printf("Unable to obtain repository config: %s\n", git_error_last()->message);
goto out;
}
if (argc == 2) {
error = config_get(cfg, argv[1]);
} else if (argc == 3) {
error = config_set(cfg, argv[1], argv[2]);
} else {
printf("USAGE: %s config <KEY> [<VALUE>]\n", argv[0]);
error = 1;
}
out:
return error;
}

View File

@ -13,7 +13,6 @@
*/ */
#include "common.h" #include "common.h"
#include <assert.h>
/** /**
* The following example partially reimplements the `git describe` command * The following example partially reimplements the `git describe` command
@ -38,32 +37,30 @@
*/ */
/** describe_options represents the parsed command line options */ /** describe_options represents the parsed command line options */
typedef struct { struct describe_options {
const char **commits; const char **commits;
size_t commit_count; size_t commit_count;
git_describe_options describe_options; git_describe_options describe_options;
git_describe_format_options format_options; git_describe_format_options format_options;
} describe_options; };
typedef struct args_info args_info; static void opts_add_commit(struct describe_options *opts, const char *commit)
static void opts_add_commit(describe_options *opts, const char *commit)
{ {
size_t sz; size_t sz;
assert(opts != NULL); assert(opts != NULL);
sz = ++opts->commit_count * sizeof(opts->commits[0]); sz = ++opts->commit_count * sizeof(opts->commits[0]);
opts->commits = xrealloc(opts->commits, sz); opts->commits = xrealloc((void *) opts->commits, sz);
opts->commits[opts->commit_count - 1] = commit; opts->commits[opts->commit_count - 1] = commit;
} }
static void do_describe_single(git_repository *repo, describe_options *opts, const char *rev) static void do_describe_single(git_repository *repo, struct describe_options *opts, const char *rev)
{ {
git_object *commit; git_object *commit;
git_describe_result *describe_result; git_describe_result *describe_result;
git_buf buf = { 0 }; git_buf buf = { 0 };
if (rev) { if (rev) {
check_lg2(git_revparse_single(&commit, repo, rev), check_lg2(git_revparse_single(&commit, repo, rev),
"Failed to lookup rev", rev); "Failed to lookup rev", rev);
@ -81,7 +78,7 @@ static void do_describe_single(git_repository *repo, describe_options *opts, con
printf("%s\n", buf.ptr); printf("%s\n", buf.ptr);
} }
static void do_describe(git_repository *repo, describe_options *opts) static void do_describe(git_repository *repo, struct describe_options *opts)
{ {
if (opts->commit_count == 0) if (opts->commit_count == 0)
do_describe_single(repo, opts, NULL); do_describe_single(repo, opts, NULL);
@ -100,9 +97,9 @@ static void print_usage(void)
} }
/** Parse command line arguments */ /** Parse command line arguments */
static void parse_options(describe_options *opts, int argc, char **argv) static void parse_options(struct describe_options *opts, int argc, char **argv)
{ {
args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;
for (args.pos = 1; args.pos < argc; ++args.pos) { for (args.pos = 1; args.pos < argc; ++args.pos) {
const char *curr = argv[args.pos]; const char *curr = argv[args.pos];
@ -142,33 +139,24 @@ static void parse_options(describe_options *opts, int argc, char **argv)
} }
/** Initialize describe_options struct */ /** Initialize describe_options struct */
static void describe_options_init(describe_options *opts) static void describe_options_init(struct describe_options *opts)
{ {
memset(opts, 0, sizeof(*opts)); memset(opts, 0, sizeof(*opts));
opts->commits = NULL; opts->commits = NULL;
opts->commit_count = 0; opts->commit_count = 0;
git_describe_init_options(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION); git_describe_options_init(&opts->describe_options, GIT_DESCRIBE_OPTIONS_VERSION);
git_describe_init_format_options(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION); git_describe_format_options_init(&opts->format_options, GIT_DESCRIBE_FORMAT_OPTIONS_VERSION);
} }
int main(int argc, char **argv) int lg2_describe(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo; struct describe_options opts;
describe_options opts;
git_libgit2_init();
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
"Could not open repository", NULL);
describe_options_init(&opts); describe_options_init(&opts);
parse_options(&opts, argc, argv); parse_options(&opts, argc, argv);
do_describe(repo, &opts); do_describe(repo, &opts);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }

View File

@ -47,11 +47,12 @@ enum {
CACHE_NONE = 2 CACHE_NONE = 2
}; };
/** The 'opts' struct captures all the various parsed command line options. */ /** The 'diff_options' struct captures all the various parsed command line options. */
struct opts { struct diff_options {
git_diff_options diffopts; git_diff_options diffopts;
git_diff_find_options findopts; git_diff_find_options findopts;
int color; int color;
int no_index;
int cache; int cache;
int output; int output;
git_diff_format_t format; git_diff_format_t format;
@ -62,28 +63,23 @@ struct opts {
/** These functions are implemented at the end */ /** These functions are implemented at the end */
static void usage(const char *message, const char *arg); static void usage(const char *message, const char *arg);
static void parse_opts(struct opts *o, int argc, char *argv[]); static void parse_opts(struct diff_options *o, int argc, char *argv[]);
static int color_printer( static int color_printer(
const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*); const git_diff_delta*, const git_diff_hunk*, const git_diff_line*, void*);
static void diff_print_stats(git_diff *diff, struct opts *o); static void diff_print_stats(git_diff *diff, struct diff_options *o);
static void compute_diff_no_index(git_diff **diff, struct diff_options *o);
int main(int argc, char *argv[]) int lg2_diff(git_repository *repo, int argc, char *argv[])
{ {
git_repository *repo = NULL;
git_tree *t1 = NULL, *t2 = NULL; git_tree *t1 = NULL, *t2 = NULL;
git_diff *diff; git_diff *diff;
struct opts o = { struct diff_options o = {
GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT, GIT_DIFF_OPTIONS_INIT, GIT_DIFF_FIND_OPTIONS_INIT,
-1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "." -1, -1, 0, 0, GIT_DIFF_FORMAT_PATCH, NULL, NULL, "."
}; };
git_libgit2_init();
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
check_lg2(git_repository_open_ext(&repo, o.dir, 0, NULL),
"Could not open repository", o.dir);
/** /**
* Possible argument patterns: * Possible argument patterns:
* *
@ -92,49 +88,54 @@ int main(int argc, char *argv[])
* * &lt;sha1&gt; * * &lt;sha1&gt;
* * --cached * * --cached
* * --nocache (don't use index data in diff at all) * * --nocache (don't use index data in diff at all)
* * --no-index &lt;file1&gt; &lt;file2&gt;
* * nothing * * nothing
* *
* Currently ranged arguments like &lt;sha1&gt;..&lt;sha2&gt; and &lt;sha1&gt;...&lt;sha2&gt; * Currently ranged arguments like &lt;sha1&gt;..&lt;sha2&gt; and &lt;sha1&gt;...&lt;sha2&gt;
* are not supported in this example * are not supported in this example
*/ */
if (o.treeish1) if (o.no_index >= 0) {
treeish_to_tree(&t1, repo, o.treeish1); compute_diff_no_index(&diff, &o);
if (o.treeish2) } else {
treeish_to_tree(&t2, repo, o.treeish2); if (o.treeish1)
treeish_to_tree(&t1, repo, o.treeish1);
if (o.treeish2)
treeish_to_tree(&t2, repo, o.treeish2);
if (t1 && t2) if (t1 && t2)
check_lg2(
git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
"diff trees", NULL);
else if (o.cache != CACHE_NORMAL) {
if (!t1)
treeish_to_tree(&t1, repo, "HEAD");
if (o.cache == CACHE_NONE)
check_lg2( check_lg2(
git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts), git_diff_tree_to_tree(&diff, repo, t1, t2, &o.diffopts),
"diff trees", NULL);
else if (o.cache != CACHE_NORMAL) {
if (!t1)
treeish_to_tree(&t1, repo, "HEAD");
if (o.cache == CACHE_NONE)
check_lg2(
git_diff_tree_to_workdir(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL);
else
check_lg2(
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts),
"diff tree to index", NULL);
}
else if (t1)
check_lg2(
git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL); "diff tree to working directory", NULL);
else else
check_lg2( check_lg2(
git_diff_tree_to_index(&diff, repo, t1, NULL, &o.diffopts), git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
"diff tree to index", NULL); "diff index to working directory", NULL);
/** Apply rename and copy detection if requested. */
if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0)
check_lg2(
git_diff_find_similar(diff, &o.findopts),
"finding renames and copies", NULL);
} }
else if (t1)
check_lg2(
git_diff_tree_to_workdir_with_index(&diff, repo, t1, &o.diffopts),
"diff tree to working directory", NULL);
else
check_lg2(
git_diff_index_to_workdir(&diff, repo, NULL, &o.diffopts),
"diff index to working directory", NULL);
/** Apply rename and copy detection if requested. */
if ((o.findopts.flags & GIT_DIFF_FIND_ALL) != 0)
check_lg2(
git_diff_find_similar(diff, &o.findopts),
"finding renames and copies", NULL);
/** Generate simple output using libgit2 display helper. */ /** Generate simple output using libgit2 display helper. */
@ -157,17 +158,45 @@ int main(int argc, char *argv[])
} }
/** Cleanup before exiting. */ /** Cleanup before exiting. */
git_diff_free(diff); git_diff_free(diff);
git_tree_free(t1); git_tree_free(t1);
git_tree_free(t2); git_tree_free(t2);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
static void compute_diff_no_index(git_diff **diff, struct diff_options *o) {
git_patch *patch = NULL;
char *file1_str = NULL;
char *file2_str = NULL;
git_buf buf = {0};
if (!o->treeish1 || !o->treeish2) {
usage("two files should be provided as arguments", NULL);
}
file1_str = read_file(o->treeish1);
if (file1_str == NULL) {
usage("file cannot be read", o->treeish1);
}
file2_str = read_file(o->treeish2);
if (file2_str == NULL) {
usage("file cannot be read", o->treeish2);
}
check_lg2(
git_patch_from_buffers(&patch, file1_str, strlen(file1_str), o->treeish1, file2_str, strlen(file2_str), o->treeish2, &o->diffopts),
"patch buffers", NULL);
check_lg2(
git_patch_to_buf(&buf, patch),
"patch to buf", NULL);
check_lg2(
git_diff_from_buffer(diff, buf.ptr, buf.size),
"diff from patch", NULL);
git_patch_free(patch);
git_buf_dispose(&buf);
free(file1_str);
free(file2_str);
}
static void usage(const char *message, const char *arg) static void usage(const char *message, const char *arg)
{ {
if (message && arg) if (message && arg)
@ -212,11 +241,10 @@ static int color_printer(
} }
/** Parse arguments as copied from git-diff. */ /** Parse arguments as copied from git-diff. */
static void parse_opts(struct opts *o, int argc, char *argv[]) static void parse_opts(struct diff_options *o, int argc, char *argv[])
{ {
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;
for (args.pos = 1; args.pos < argc; ++args.pos) { for (args.pos = 1; args.pos < argc; ++args.pos) {
const char *a = argv[args.pos]; const char *a = argv[args.pos];
@ -233,9 +261,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
o->output |= OUTPUT_DIFF; o->output |= OUTPUT_DIFF;
o->format = GIT_DIFF_FORMAT_PATCH; o->format = GIT_DIFF_FORMAT_PATCH;
} }
else if (!strcmp(a, "--cached")) else if (!strcmp(a, "--cached")) {
o->cache = CACHE_ONLY; o->cache = CACHE_ONLY;
else if (!strcmp(a, "--nocache")) if (o->no_index >= 0) usage("--cached and --no-index are incompatible", NULL);
} else if (!strcmp(a, "--nocache"))
o->cache = CACHE_NONE; o->cache = CACHE_NONE;
else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name")) else if (!strcmp(a, "--name-only") || !strcmp(a, "--format=name"))
o->format = GIT_DIFF_FORMAT_NAME_ONLY; o->format = GIT_DIFF_FORMAT_NAME_ONLY;
@ -248,7 +277,10 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
o->format = GIT_DIFF_FORMAT_RAW; o->format = GIT_DIFF_FORMAT_RAW;
o->diffopts.id_abbrev = 40; o->diffopts.id_abbrev = 40;
} }
else if (!strcmp(a, "--color")) else if (!strcmp(a, "--no-index")) {
o->no_index = 0;
if (o->cache == CACHE_ONLY) usage("--cached and --no-index are incompatible", NULL);
} else if (!strcmp(a, "--color"))
o->color = 0; o->color = 0;
else if (!strcmp(a, "--no-color")) else if (!strcmp(a, "--no-color"))
o->color = -1; o->color = -1;
@ -309,7 +341,7 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
} }
/** Display diff output with "--stat", "--numstat", or "--shortstat" */ /** Display diff output with "--stat", "--numstat", or "--shortstat" */
static void diff_print_stats(git_diff *diff, struct opts *o) static void diff_print_stats(git_diff *diff, struct diff_options *o)
{ {
git_diff_stats *stats; git_diff_stats *stats;
git_buf b = GIT_BUF_INIT_CONST(NULL, 0); git_buf b = GIT_BUF_INIT_CONST(NULL, 0);

View File

@ -1,12 +1,4 @@
#include "common.h" #include "common.h"
#include <git2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _WIN32
# include <pthread.h>
# include <unistd.h>
#endif
static int progress_cb(const char *str, int len, void *data) static int progress_cb(const char *str, int len, void *data)
{ {
@ -29,7 +21,7 @@ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, vo
git_oid_fmt(b_str, b); git_oid_fmt(b_str, b);
b_str[GIT_OID_HEXSZ] = '\0'; b_str[GIT_OID_HEXSZ] = '\0';
if (git_oid_iszero(a)) { if (git_oid_is_zero(a)) {
printf("[new] %.20s %s\n", b_str, refname); printf("[new] %.20s %s\n", b_str, refname);
} else { } else {
git_oid_fmt(a_str, a); git_oid_fmt(a_str, a);
@ -46,15 +38,15 @@ static int update_cb(const char *refname, const git_oid *a, const git_oid *b, vo
* data. Most frontends will probably want to show a percentage and * data. Most frontends will probably want to show a percentage and
* the download rate. * the download rate.
*/ */
static int transfer_progress_cb(const git_transfer_progress *stats, void *payload) static int transfer_progress_cb(const git_indexer_progress *stats, void *payload)
{ {
(void)payload; (void)payload;
if (stats->received_objects == stats->total_objects) { if (stats->received_objects == stats->total_objects) {
printf("Resolving deltas %d/%d\r", printf("Resolving deltas %u/%u\r",
stats->indexed_deltas, stats->total_deltas); stats->indexed_deltas, stats->total_deltas);
} else if (stats->total_objects > 0) { } else if (stats->total_objects > 0) {
printf("Received %d/%d objects (%d) in %" PRIuZ " bytes\r", printf("Received %u/%u objects (%u) 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);
} }
@ -62,10 +54,10 @@ static int transfer_progress_cb(const git_transfer_progress *stats, void *payloa
} }
/** Entry point for this command */ /** Entry point for this command */
int fetch(git_repository *repo, int argc, char **argv) int lg2_fetch(git_repository *repo, int argc, char **argv)
{ {
git_remote *remote = NULL; git_remote *remote = NULL;
const git_transfer_progress *stats; const git_indexer_progress *stats;
git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
if (argc < 2) { if (argc < 2) {
@ -100,10 +92,10 @@ int fetch(git_repository *repo, int argc, char **argv)
*/ */
stats = git_remote_stats(remote); stats = git_remote_stats(remote);
if (stats->local_objects > 0) { if (stats->local_objects > 0) {
printf("\rReceived %d/%d objects in %" PRIuZ " bytes (used %d local objects)\n", printf("\rReceived %u/%u objects in %" PRIuZ " bytes (used %u local objects)\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects); stats->indexed_objects, stats->total_objects, stats->received_bytes, stats->local_objects);
} else{ } else{
printf("\rReceived %d/%d objects in %" PRIuZ "bytes\n", printf("\rReceived %u/%u objects in %" PRIuZ "bytes\n",
stats->indexed_objects, stats->total_objects, stats->received_bytes); stats->indexed_objects, stats->total_objects, stats->received_bytes);
} }

View File

@ -1,49 +1,44 @@
#include <git2.h> #include <git2.h>
#include <stdio.h>
#include "common.h" #include "common.h"
static int show_ref(git_reference *ref, void *data) static int show_ref(git_reference *ref, void *data)
{ {
git_repository *repo = data; git_repository *repo = data;
git_reference *resolved = NULL; git_reference *resolved = NULL;
char hex[GIT_OID_HEXSZ+1]; char hex[GIT_OID_HEXSZ+1];
const git_oid *oid; const git_oid *oid;
git_object *obj; git_object *obj;
if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC)
check_lg2(git_reference_resolve(&resolved, ref), check_lg2(git_reference_resolve(&resolved, ref),
"Unable to resolve symbolic reference", "Unable to resolve symbolic reference",
git_reference_name(ref)); git_reference_name(ref));
oid = git_reference_target(resolved ? resolved : ref); oid = git_reference_target(resolved ? resolved : ref);
git_oid_fmt(hex, oid); git_oid_fmt(hex, oid);
hex[GIT_OID_HEXSZ] = 0; hex[GIT_OID_HEXSZ] = 0;
check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJECT_ANY), check_lg2(git_object_lookup(&obj, repo, oid, GIT_OBJECT_ANY),
"Unable to lookup object", hex); "Unable to lookup object", hex);
printf("%s %-6s\t%s\n", printf("%s %-6s\t%s\n",
hex, hex,
git_object_type2string(git_object_type(obj)), git_object_type2string(git_object_type(obj)),
git_reference_name(ref)); git_reference_name(ref));
if (resolved) if (resolved)
git_reference_free(resolved); git_reference_free(resolved);
return 0; return 0;
} }
int main(int argc, char **argv) int lg2_for_each_ref(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo; UNUSED(argv);
git_libgit2_init();
if (argc != 1)
if (argc != 1 || argv[1] /* silence -Wunused-parameter */) fatal("Sorry, no for-each-ref options supported yet", NULL);
fatal("Sorry, no for-each-ref options supported yet", NULL);
check_lg2(git_reference_foreach(repo, show_ref, repo),
check_lg2(git_repository_open(&repo, "."), "Could not iterate over references", NULL);
"Could not open repository", NULL);
check_lg2(git_reference_foreach(repo, show_ref, repo), return 0;
"Could not iterate over references", NULL);
git_libgit2_shutdown();
return 0;
} }

View File

@ -36,6 +36,8 @@
* [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain * [pg]: https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain
*/ */
#include "common.h"
/** /**
* ### Includes * ### Includes
* *
@ -43,9 +45,7 @@
* that you need. It should be the only thing you need to include in order * that you need. It should be the only thing you need to include in order
* to compile properly and get all the libgit2 API. * to compile properly and get all the libgit2 API.
*/ */
#include <git2.h> #include "git2.h"
#include <stdio.h>
#include <string.h>
static void oid_parsing(git_oid *out); static void oid_parsing(git_oid *out);
static void object_database(git_repository *repo, git_oid *oid); static void object_database(git_repository *repo, git_oid *oid);
@ -76,12 +76,11 @@ static void check_error(int error_code, const char *action)
exit(1); exit(1);
} }
int main (int argc, char** argv) int lg2_general(git_repository *repo, int argc, char** argv)
{ {
int error; int error;
git_oid oid; git_oid oid;
char *repo_path; char *repo_path;
git_repository *repo;
/** /**
* Initialize the library, this will set up any global state which libgit2 needs * Initialize the library, this will set up any global state which libgit2 needs
@ -625,7 +624,7 @@ static void revwalking(git_repository *repo)
static void index_walking(git_repository *repo) static void index_walking(git_repository *repo)
{ {
git_index *index; git_index *index;
unsigned int i, ecount; size_t i, ecount;
printf("\n*Index Walking*\n"); printf("\n*Index Walking*\n");

View File

@ -1,40 +1,21 @@
#include <git2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#ifdef _WIN32
# include <io.h>
# include <Windows.h>
# define open _open
# define read _read
# define close _close
#define ssize_t unsigned int
#else
# include <unistd.h>
#endif
#include "common.h" #include "common.h"
/* /*
* This could be run in the main loop whilst the application waits for * This could be run in the main loop whilst the application waits for
* the indexing to finish in a worker thread * the indexing to finish in a worker thread
*/ */
static int index_cb(const git_transfer_progress *stats, void *data) static int index_cb(const git_indexer_progress *stats, void *data)
{ {
(void)data; (void)data;
printf("\rProcessing %d of %d", stats->indexed_objects, stats->total_objects); printf("\rProcessing %u of %u", stats->indexed_objects, stats->total_objects);
return 0; return 0;
} }
int index_pack(git_repository *repo, int argc, char **argv) int lg2_index_pack(git_repository *repo, int argc, char **argv)
{ {
git_indexer *idx; git_indexer *idx;
git_transfer_progress stats = {0, 0}; git_indexer_progress stats = {0, 0};
int error; int error;
char hash[GIT_OID_HEXSZ + 1] = {0}; char hash[GIT_OID_HEXSZ + 1] = {0};
int fd; int fd;
@ -78,7 +59,7 @@ int index_pack(git_repository *repo, int argc, char **argv)
if ((error = git_indexer_commit(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 %u of %u\n", stats.indexed_objects, stats.total_objects);
git_oid_fmt(hash, git_indexer_hash(idx)); git_oid_fmt(hash, git_indexer_hash(idx));
puts(hash); puts(hash);

View File

@ -27,7 +27,7 @@
*/ */
/** Forward declarations of helpers */ /** Forward declarations of helpers */
struct opts { struct init_opts {
int no_options; int no_options;
int quiet; int quiet;
int bare; int bare;
@ -38,15 +38,11 @@ struct opts {
const char *dir; const char *dir;
}; };
static void create_initial_commit(git_repository *repo); static void create_initial_commit(git_repository *repo);
static void parse_opts(struct opts *o, int argc, char *argv[]); static void parse_opts(struct init_opts *o, int argc, char *argv[]);
int lg2_init(git_repository *repo, int argc, char *argv[])
int main(int argc, char *argv[])
{ {
git_repository *repo = NULL; struct init_opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
struct opts o = { 1, 0, 0, 0, GIT_REPOSITORY_INIT_SHARED_UMASK, 0, 0, 0 };
git_libgit2_init();
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
@ -116,7 +112,6 @@ int main(int argc, char *argv[])
} }
git_repository_free(repo); git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -215,7 +210,7 @@ static uint32_t parse_shared(const char *shared)
return 0; return 0;
} }
static void parse_opts(struct opts *o, int argc, char *argv[]) static void parse_opts(struct init_opts *o, int argc, char *argv[])
{ {
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;
const char *sharedarg; const char *sharedarg;
@ -249,5 +244,5 @@ static void parse_opts(struct opts *o, int argc, char *argv[])
} }
if (!o->dir) if (!o->dir)
usage("must specify directory to init", NULL); usage("must specify directory to init", "");
} }

122
examples/lg2.c Normal file
View File

@ -0,0 +1,122 @@
#include "common.h"
/* This part is not strictly libgit2-dependent, but you can use this
* as a starting point for a git-like tool */
typedef int (*git_command_fn)(git_repository *, int , char **);
struct {
char *name;
git_command_fn fn;
char requires_repo;
} commands[] = {
{ "add", lg2_add, 1 },
{ "blame", lg2_blame, 1 },
{ "cat-file", lg2_cat_file, 1 },
{ "checkout", lg2_checkout, 1 },
{ "clone", lg2_clone, 0 },
{ "config", lg2_config, 1 },
{ "describe", lg2_describe, 1 },
{ "diff", lg2_diff, 1 },
{ "fetch", lg2_fetch, 1 },
{ "for-each-ref", lg2_for_each_ref, 1 },
{ "general", lg2_general, 0 },
{ "index-pack", lg2_index_pack, 1 },
{ "init", lg2_init, 0 },
{ "log", lg2_log, 1 },
{ "ls-files", lg2_ls_files, 1 },
{ "ls-remote", lg2_ls_remote, 1 },
{ "merge", lg2_merge, 1 },
{ "remote", lg2_remote, 1 },
{ "rev-list", lg2_rev_list, 1 },
{ "rev-parse", lg2_rev_parse, 1 },
{ "show-index", lg2_show_index, 0 },
{ "stash", lg2_stash, 1 },
{ "status", lg2_status, 1 },
{ "tag", lg2_tag, 1 },
};
static int run_command(git_command_fn fn, git_repository *repo, struct args_info args)
{
int error;
/* Run the command. If something goes wrong, print the error message to stderr */
error = fn(repo, args.argc - args.pos, &args.argv[args.pos]);
if (error < 0) {
if (git_error_last() == NULL)
fprintf(stderr, "Error without message");
else
fprintf(stderr, "Bad news:\n %s\n", git_error_last()->message);
}
return !!error;
}
static int usage(const char *prog)
{
size_t i;
fprintf(stderr, "usage: %s <cmd>...\n\nAvailable commands:\n\n", prog);
for (i = 0; i < ARRAY_SIZE(commands); i++)
fprintf(stderr, "\t%s\n", commands[i].name);
exit(EXIT_FAILURE);
}
int main(int argc, char **argv)
{
struct args_info args = ARGS_INFO_INIT;
git_repository *repo = NULL;
const char *git_dir = NULL;
int return_code = 1;
size_t i;
if (argc < 2)
usage(argv[0]);
git_libgit2_init();
for (args.pos = 1; args.pos < args.argc; ++args.pos) {
char *a = args.argv[args.pos];
if (a[0] != '-') {
/* non-arg */
break;
} else if (optional_str_arg(&git_dir, &args, "--git-dir", ".git")) {
continue;
} else if (match_arg_separator(&args)) {
break;
}
}
if (args.pos == args.argc)
usage(argv[0]);
if (!git_dir)
git_dir = ".";
for (i = 0; i < ARRAY_SIZE(commands); ++i) {
if (strcmp(args.argv[args.pos], commands[i].name))
continue;
/*
* Before running the actual command, create an instance
* of the local repository and pass it to the function.
* */
if (commands[i].requires_repo) {
check_lg2(git_repository_open_ext(&repo, git_dir, 0, NULL),
"Unable to open repository '%s'", git_dir);
}
return_code = run_command(commands[i].fn, repo, args);
goto shutdown;
}
fprintf(stderr, "Command not found: %s\n", argv[1]);
shutdown:
git_repository_free(repo);
git_libgit2_shutdown();
return return_code;
}

View File

@ -71,7 +71,7 @@ static int match_with_parent(git_commit *commit, int i, git_diff_options *);
static int signature_matches(const git_signature *sig, const char *filter); static int signature_matches(const git_signature *sig, const char *filter);
static int log_message_matches(const git_commit *commit, const char *filter); static int log_message_matches(const git_commit *commit, const char *filter);
int main(int argc, char *argv[]) int lg2_log(git_repository *repo, int argc, char *argv[])
{ {
int i, count = 0, printed = 0, parents, last_arg; int i, count = 0, printed = 0, parents, last_arg;
struct log_state s; struct log_state s;
@ -81,11 +81,9 @@ int main(int argc, char *argv[])
git_commit *commit = NULL; git_commit *commit = NULL;
git_pathspec *ps = NULL; git_pathspec *ps = NULL;
git_libgit2_init();
/** Parse arguments and set up revwalker. */ /** Parse arguments and set up revwalker. */
last_arg = parse_options(&s, &opt, argc, argv); last_arg = parse_options(&s, &opt, argc, argv);
s.repo = repo;
diffopts.pathspec.strings = &argv[last_arg]; diffopts.pathspec.strings = &argv[last_arg];
diffopts.pathspec.count = argc - last_arg; diffopts.pathspec.count = argc - last_arg;
@ -180,8 +178,6 @@ int main(int argc, char *argv[])
git_pathspec_free(ps); git_pathspec_free(ps);
git_revwalk_free(s.walker); git_revwalk_free(s.walker);
git_repository_free(s.repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -243,13 +239,6 @@ static int add_revision(struct log_state *s, const char *revstr)
git_revspec revs; git_revspec revs;
int hide = 0; int hide = 0;
/** Open repo on demand if it isn't already open. */
if (!s->repo) {
if (!s->repodir) s->repodir = ".";
check_lg2(git_repository_open_ext(&s->repo, s->repodir, 0, NULL),
"Could not open repository", s->repodir);
}
if (!revstr) { if (!revstr) {
push_rev(s, NULL, hide); push_rev(s, NULL, hide);
return 0; return 0;
@ -435,8 +424,7 @@ static int parse_options(
else else
/** Try failed revision parse as filename. */ /** Try failed revision parse as filename. */
break; break;
} else if (!strcmp(a, "--")) { } else if (!match_arg_separator(&args)) {
++args.pos;
break; break;
} }
else if (!strcmp(a, "--date-order")) else if (!strcmp(a, "--date-order"))

View File

@ -13,7 +13,6 @@
*/ */
#include "common.h" #include "common.h"
#include "array.h"
/** /**
* This example demonstrates the libgit2 index APIs to roughly * This example demonstrates the libgit2 index APIs to roughly
@ -26,11 +25,11 @@
* This currently supports the default behavior and the `--error-unmatch` option. * This currently supports the default behavior and the `--error-unmatch` option.
*/ */
typedef struct { struct ls_options {
int error_unmatch; int error_unmatch;
char *files[1024]; char *files[1024];
size_t file_count; size_t file_count;
} ls_options; };
static void usage(const char *message, const char *arg) static void usage(const char *message, const char *arg)
{ {
@ -42,12 +41,12 @@ static void usage(const char *message, const char *arg)
exit(1); exit(1);
} }
static int parse_options(ls_options *opts, int argc, char *argv[]) static int parse_options(struct ls_options *opts, int argc, char *argv[])
{ {
int parsing_files = 0; int parsing_files = 0;
int i; int i;
memset(opts, 0, sizeof(ls_options)); memset(opts, 0, sizeof(struct ls_options));
if (argc < 2) if (argc < 2)
return 0; return 0;
@ -79,7 +78,7 @@ static int parse_options(ls_options *opts, int argc, char *argv[])
return 0; return 0;
} }
static int print_paths(ls_options *opts, git_index *index) static int print_paths(struct ls_options *opts, git_index *index)
{ {
size_t i; size_t i;
const git_index_entry *entry; const git_index_entry *entry;
@ -111,21 +110,15 @@ static int print_paths(ls_options *opts, git_index *index)
return 0; return 0;
} }
int main(int argc, char *argv[]) int lg2_ls_files(git_repository *repo, int argc, char *argv[])
{ {
ls_options opts;
git_repository *repo = NULL;
git_index *index = NULL; git_index *index = NULL;
struct ls_options opts;
int error; int error;
if ((error = parse_options(&opts, argc, argv)) < 0) if ((error = parse_options(&opts, argc, argv)) < 0)
return error; return error;
git_libgit2_init();
if ((error = git_repository_open_ext(&repo, ".", 0, NULL)) < 0)
goto cleanup;
if ((error = git_repository_index(&index, repo)) < 0) if ((error = git_repository_index(&index, repo)) < 0)
goto cleanup; goto cleanup;
@ -133,8 +126,6 @@ int main(int argc, char *argv[])
cleanup: cleanup:
git_index_free(index); git_index_free(index);
git_repository_free(repo);
git_libgit2_shutdown();
return error; return error;
} }

View File

@ -1,7 +1,3 @@
#include <git2.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "common.h" #include "common.h"
static int use_remote(git_repository *repo, char *name) static int use_remote(git_repository *repo, char *name)
@ -49,7 +45,7 @@ cleanup:
} }
/** Entry point for this command */ /** Entry point for this command */
int ls_remote(git_repository *repo, int argc, char **argv) int lg2_ls_remote(git_repository *repo, int argc, char **argv)
{ {
int error; int error;

View File

@ -13,11 +13,6 @@
*/ */
#include "common.h" #include "common.h"
#include <assert.h>
#ifdef _MSC_VER
#define snprintf sprintf_s
#endif
/** The following example demonstrates how to do merges with libgit2. /** The following example demonstrates how to do merges with libgit2.
* *
@ -28,7 +23,7 @@
* *
*/ */
typedef struct { struct merge_options {
const char **heads; const char **heads;
size_t heads_count; size_t heads_count;
@ -36,7 +31,7 @@ typedef struct {
size_t annotated_count; size_t annotated_count;
int no_commit : 1; int no_commit : 1;
} merge_options; };
static void print_usage(void) static void print_usage(void)
{ {
@ -44,7 +39,7 @@ static void print_usage(void)
exit(1); exit(1);
} }
static void merge_options_init(merge_options *opts) static void merge_options_init(struct merge_options *opts)
{ {
memset(opts, 0, sizeof(*opts)); memset(opts, 0, sizeof(*opts));
@ -54,18 +49,18 @@ static void merge_options_init(merge_options *opts)
opts->annotated_count = 0; opts->annotated_count = 0;
} }
static void opts_add_refish(merge_options *opts, const char *refish) static void opts_add_refish(struct merge_options *opts, const char *refish)
{ {
size_t sz; size_t sz;
assert(opts != NULL); assert(opts != NULL);
sz = ++opts->heads_count * sizeof(opts->heads[0]); sz = ++opts->heads_count * sizeof(opts->heads[0]);
opts->heads = xrealloc(opts->heads, sz); opts->heads = xrealloc((void *) opts->heads, sz);
opts->heads[opts->heads_count - 1] = refish; opts->heads[opts->heads_count - 1] = refish;
} }
static void parse_options(const char **repo_path, merge_options *opts, int argc, char **argv) static void parse_options(const char **repo_path, struct merge_options *opts, int argc, char **argv)
{ {
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;
@ -87,7 +82,7 @@ static void parse_options(const char **repo_path, merge_options *opts, int argc,
} }
} }
static int resolve_heads(git_repository *repo, merge_options *opts) static int resolve_heads(git_repository *repo, struct merge_options *opts)
{ {
git_annotated_commit **annotated = calloc(opts->heads_count, sizeof(git_annotated_commit *)); git_annotated_commit **annotated = calloc(opts->heads_count, sizeof(git_annotated_commit *));
size_t annotated_count = 0, i; size_t annotated_count = 0, i;
@ -205,7 +200,7 @@ static void output_conflicts(git_index *index)
git_index_conflict_iterator_free(conflicts); git_index_conflict_iterator_free(conflicts);
} }
static int create_merge_commit(git_repository *repo, git_index *index, merge_options *opts) static int create_merge_commit(git_repository *repo, git_index *index, struct merge_options *opts)
{ {
git_oid tree_oid, commit_oid; git_oid tree_oid, commit_oid;
git_tree *tree; git_tree *tree;
@ -224,6 +219,7 @@ static int create_merge_commit(git_repository *repo, git_index *index, merge_opt
check_lg2(git_repository_head(&head_ref, repo), "failed to get repo HEAD", NULL); check_lg2(git_repository_head(&head_ref, repo), "failed to get repo HEAD", NULL);
if (resolve_refish(&merge_commit, repo, opts->heads[0])) { if (resolve_refish(&merge_commit, repo, opts->heads[0])) {
fprintf(stderr, "failed to resolve refish %s", opts->heads[0]); fprintf(stderr, "failed to resolve refish %s", opts->heads[0]);
free(parents);
return -1; return -1;
} }
@ -278,10 +274,9 @@ cleanup:
return err; return err;
} }
int main(int argc, char **argv) int lg2_merge(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo = NULL; struct merge_options opts;
merge_options opts;
git_index *index; git_index *index;
git_repository_state_t state; git_repository_state_t state;
git_merge_analysis_t analysis; git_merge_analysis_t analysis;
@ -292,11 +287,6 @@ int main(int argc, char **argv)
merge_options_init(&opts); merge_options_init(&opts);
parse_options(&path, &opts, argc, argv); parse_options(&path, &opts, argc, argv);
git_libgit2_init();
check_lg2(git_repository_open_ext(&repo, path, 0, NULL),
"Could not open repository", NULL);
state = git_repository_state(repo); state = git_repository_state(repo);
if (state != GIT_REPOSITORY_STATE_NONE) { if (state != GIT_REPOSITORY_STATE_NONE) {
fprintf(stderr, "repository is in unexpected state %d\n", state); fprintf(stderr, "repository is in unexpected state %d\n", state);
@ -364,10 +354,8 @@ int main(int argc, char **argv)
} }
cleanup: cleanup:
free(opts.heads); free((char **)opts.heads);
free(opts.annotated); free(opts.annotated);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }

View File

@ -1 +0,0 @@
/git2

View File

@ -1,22 +0,0 @@
default: all
CC = gcc
CFLAGS += -g
CFLAGS += -I../../include
LDFLAGS += -L../../build -L../..
LIBRARIES += -lgit2 -lpthread
OBJECTS = \
git2.o \
ls-remote.o \
fetch.o \
clone.o \
index-pack.o \
common.o
all: $(OBJECTS)
$(CC) $(CFLAGS) $(LDFLAGS) -o git2 $(OBJECTS) $(LIBRARIES)
clean:
$(RM) $(OBJECTS)
$(RM) git2

View File

@ -1,85 +0,0 @@
#include "common.h"
#include <stdio.h>
#include <string.h>
#include <errno.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
static int readline(char **out)
{
int c, error = 0, length = 0, allocated = 0;
char *line = NULL;
errno = 0;
while ((c = getchar()) != EOF) {
if (length == allocated) {
allocated += 16;
if ((line = realloc(line, allocated)) == NULL) {
error = -1;
goto error;
}
}
if (c == '\n')
break;
line[length++] = c;
}
if (errno != 0) {
error = -1;
goto error;
}
line[length] = '\0';
*out = line;
line = NULL;
error = length;
error:
free(line);
return error;
}
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 = NULL, *password = NULL;
int error;
printf("Username: ");
if (readline(&username) < 0) {
fprintf(stderr, "Unable to read username: %s", strerror(errno));
return -1;
}
/* Yup. Right there on your terminal. Careful where you copy/paste output. */
printf("Password: ");
if (readline(&password) < 0) {
fprintf(stderr, "Unable to read password: %s", strerror(errno));
free(username);
return -1;
}
error = git_cred_userpass_plaintext_new(out, username, password);
free(username);
free(password);
return error;
}

View File

@ -1,30 +0,0 @@
#ifndef __COMMON_H__
#define __COMMON_H__
#include <git2.h>
typedef int (*git_cb)(git_repository *, int , char **);
int ls_remote(git_repository *repo, int argc, char **argv);
int parse_pkt_line(git_repository *repo, int argc, char **argv);
int show_remote(git_repository *repo, int argc, char **argv);
int fetch(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 cred_acquire_cb(git_cred **out,
const char * url,
const char * username_from_url,
unsigned int allowed_types,
void *payload);
#ifndef PRIuZ
/* Define the printf format specifer to use for size_t output */
#if defined(_MSC_VER) || defined(__MINGW32__)
# define PRIuZ "Iu"
#else
# define PRIuZ "zu"
#endif
#endif
#endif /* __COMMON_H__ */

View File

@ -1,90 +0,0 @@
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "../common.h"
#include "common.h"
/* This part is not strictly libgit2-dependent, but you can use this
* as a starting point for a git-like tool */
struct {
char *name;
git_cb fn;
} commands[] = {
{"ls-remote", ls_remote},
{"fetch", fetch},
{"clone", do_clone},
{"index-pack", index_pack},
{ NULL, NULL}
};
static int run_command(git_cb fn, git_repository *repo, struct args_info args)
{
int error;
/* Run the command. If something goes wrong, print the error message to stderr */
error = fn(repo, args.argc - args.pos, &args.argv[args.pos]);
if (error < 0) {
if (git_error_last() == NULL)
fprintf(stderr, "Error without message");
else
fprintf(stderr, "Bad news:\n %s\n", git_error_last()->message);
}
return !!error;
}
int main(int argc, char **argv)
{
int i;
int return_code = 1;
int error;
git_repository *repo;
struct args_info args = ARGS_INFO_INIT;
const char *git_dir = NULL;
if (argc < 2) {
fprintf(stderr, "usage: %s <cmd> [repo]\n", argv[0]);
exit(EXIT_FAILURE);
}
git_libgit2_init();
for (args.pos = 1; args.pos < args.argc; ++args.pos) {
char *a = args.argv[args.pos];
if (a[0] != '-') {
/* non-arg */
break;
} else if (optional_str_arg(&git_dir, &args, "--git-dir", ".git")) {
continue;
} else if (!strcmp(a, "--")) {
/* arg separator */
break;
}
}
/* Before running the actual command, create an instance of the local
* repository and pass it to the function. */
error = git_repository_open(&repo, git_dir);
if (error < 0)
repo = NULL;
for (i = 0; commands[i].name != NULL; ++i) {
if (!strcmp(args.argv[args.pos], commands[i].name)) {
return_code = run_command(commands[i].fn, repo, args);
goto shutdown;
}
}
fprintf(stderr, "Command not found: %s\n", argv[1]);
shutdown:
git_repository_free(repo);
git_libgit2_shutdown();
return return_code;
}

View File

@ -30,7 +30,7 @@ enum subcmd {
subcmd_show, subcmd_show,
}; };
struct opts { struct remote_opts {
enum subcmd cmd; enum subcmd cmd;
/* for command-specific args */ /* for command-specific args */
@ -38,34 +38,23 @@ struct opts {
char **argv; char **argv;
}; };
static int cmd_add(git_repository *repo, struct opts *o); static int cmd_add(git_repository *repo, struct remote_opts *o);
static int cmd_remove(git_repository *repo, struct opts *o); static int cmd_remove(git_repository *repo, struct remote_opts *o);
static int cmd_rename(git_repository *repo, struct opts *o); static int cmd_rename(git_repository *repo, struct remote_opts *o);
static int cmd_seturl(git_repository *repo, struct opts *o); static int cmd_seturl(git_repository *repo, struct remote_opts *o);
static int cmd_show(git_repository *repo, struct opts *o); static int cmd_show(git_repository *repo, struct remote_opts *o);
static void parse_subcmd( static void parse_subcmd(
struct opts *opt, int argc, char **argv); struct remote_opts *opt, int argc, char **argv);
static void usage(const char *msg, const char *arg); static void usage(const char *msg, const char *arg);
int main(int argc, char *argv[]) int lg2_remote(git_repository *repo, int argc, char *argv[])
{ {
int retval = 0; int retval = 0;
struct opts opt = {0}; struct remote_opts opt = {0};
git_buf buf = GIT_BUF_INIT_CONST(NULL, 0);
git_repository *repo = NULL;
parse_subcmd(&opt, argc, argv); parse_subcmd(&opt, argc, argv);
git_libgit2_init();
check_lg2(git_repository_discover(&buf, ".", 0, NULL),
"Could not find repository", NULL);
check_lg2(git_repository_open(&repo, buf.ptr),
"Could not open repository", NULL);
git_buf_dispose(&buf);
switch (opt.cmd) switch (opt.cmd)
{ {
case subcmd_add: case subcmd_add:
@ -85,12 +74,10 @@ int main(int argc, char *argv[])
break; break;
} }
git_libgit2_shutdown();
return retval; return retval;
} }
static int cmd_add(git_repository *repo, struct opts *o) static int cmd_add(git_repository *repo, struct remote_opts *o)
{ {
char *name, *url; char *name, *url;
git_remote *remote = {0}; git_remote *remote = {0};
@ -107,7 +94,7 @@ static int cmd_add(git_repository *repo, struct opts *o)
return 0; return 0;
} }
static int cmd_remove(git_repository *repo, struct opts *o) static int cmd_remove(git_repository *repo, struct remote_opts *o)
{ {
char *name; char *name;
@ -122,7 +109,7 @@ static int cmd_remove(git_repository *repo, struct opts *o)
return 0; return 0;
} }
static int cmd_rename(git_repository *repo, struct opts *o) static int cmd_rename(git_repository *repo, struct remote_opts *o)
{ {
int i, retval; int i, retval;
char *old, *new; char *old, *new;
@ -147,7 +134,7 @@ static int cmd_rename(git_repository *repo, struct opts *o)
return retval; return retval;
} }
static int cmd_seturl(git_repository *repo, struct opts *o) static int cmd_seturl(git_repository *repo, struct remote_opts *o)
{ {
int i, retval, push = 0; int i, retval, push = 0;
char *name = NULL, *url = NULL; char *name = NULL, *url = NULL;
@ -179,7 +166,7 @@ static int cmd_seturl(git_repository *repo, struct opts *o)
return 0; return 0;
} }
static int cmd_show(git_repository *repo, struct opts *o) static int cmd_show(git_repository *repo, struct remote_opts *o)
{ {
int i; int i;
const char *arg, *name, *fetch, *push; const char *arg, *name, *fetch, *push;
@ -226,7 +213,7 @@ static int cmd_show(git_repository *repo, struct opts *o)
} }
static void parse_subcmd( static void parse_subcmd(
struct opts *opt, int argc, char **argv) struct remote_opts *opt, int argc, char **argv)
{ {
char *arg = argv[1]; char *arg = argv[1];
enum subcmd cmd = 0; enum subcmd cmd = 0;

View File

@ -15,20 +15,24 @@
#include "common.h" #include "common.h"
static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts); #include <assert.h>
int main (int argc, char **argv) static int revwalk_parse_options(git_sort_t *sort, struct args_info *args);
static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args);
int lg2_rev_list(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo; struct args_info args = ARGS_INFO_INIT;
git_revwalk *walk; git_revwalk *walk;
git_oid oid; git_oid oid;
git_sort_t sort;
char buf[GIT_OID_HEXSZ+1]; char buf[GIT_OID_HEXSZ+1];
git_libgit2_init(); check_lg2(revwalk_parse_options(&sort, &args), "parsing options", NULL);
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL), "opening repository", NULL);
check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL); check_lg2(git_revwalk_new(&walk, repo), "allocating revwalk", NULL);
check_lg2(revwalk_parseopts(repo, walk, argc-1, argv+1), "parsing options", NULL); git_revwalk_sorting(walk, sort);
check_lg2(revwalk_parse_revs(repo, walk, &args), "parsing revs", NULL);
while (!git_revwalk_next(&oid, walk)) { while (!git_revwalk_next(&oid, walk)) {
git_oid_fmt(buf, &oid); git_oid_fmt(buf, &oid);
@ -36,7 +40,7 @@ int main (int argc, char **argv)
printf("%s\n", buf); printf("%s\n", buf);
} }
git_libgit2_shutdown(); git_revwalk_free(walk);
return 0; return 0;
} }
@ -85,33 +89,60 @@ out:
return error; return error;
} }
static int revwalk_parseopts(git_repository *repo, git_revwalk *walk, int nopts, char **opts) static void print_usage(void)
{ {
int hide, i, error; fprintf(stderr, "rev-list [--git-dir=dir] [--topo-order|--date-order] [--reverse] <revspec>\n");
unsigned int sorting = GIT_SORT_NONE; exit(-1);
}
static int revwalk_parse_options(git_sort_t *sort, struct args_info *args)
{
assert(sort && args);
*sort = GIT_SORT_NONE;
if (args->argc < 1)
print_usage();
for (args->pos = 1; args->pos < args->argc; ++args->pos) {
const char *curr = args->argv[args->pos];
if (!strcmp(curr, "--topo-order")) {
*sort |= GIT_SORT_TOPOLOGICAL;
} else if (!strcmp(curr, "--date-order")) {
*sort |= GIT_SORT_TIME;
} else if (!strcmp(curr, "--reverse")) {
*sort |= (*sort & ~GIT_SORT_REVERSE) ^ GIT_SORT_REVERSE;
} else {
break;
}
}
return 0;
}
static int revwalk_parse_revs(git_repository *repo, git_revwalk *walk, struct args_info *args)
{
int hide, error;
git_oid oid;
hide = 0; hide = 0;
for (i = 0; i < nopts; i++) { for (; args->pos < args->argc; ++args->pos) {
if (!strcmp(opts[i], "--topo-order")) { const char *curr = args->argv[args->pos];
sorting = GIT_SORT_TOPOLOGICAL | (sorting & GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting); if (!strcmp(curr, "--not")) {
} else if (!strcmp(opts[i], "--date-order")) {
sorting = GIT_SORT_TIME | (sorting & GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting);
} else if (!strcmp(opts[i], "--reverse")) {
sorting = (sorting & ~GIT_SORT_REVERSE)
| ((sorting & GIT_SORT_REVERSE) ? 0 : GIT_SORT_REVERSE);
git_revwalk_sorting(walk, sorting);
} else if (!strcmp(opts[i], "--not")) {
hide = !hide; hide = !hide;
} else if (opts[i][0] == '^') { } else if (curr[0] == '^') {
if ((error = push_spec(repo, walk, opts[i] + 1, !hide))) if ((error = push_spec(repo, walk, curr + 1, !hide)))
return error; return error;
} else if (strstr(opts[i], "..")) { } else if (strstr(curr, "..")) {
if ((error = push_range(repo, walk, opts[i], hide))) if ((error = push_range(repo, walk, curr, hide)))
return error; return error;
} else { } else {
if ((error = push_spec(repo, walk, opts[i], hide))) if (push_spec(repo, walk, curr, hide) == 0)
continue;
if ((error = git_oid_fromstr(&oid, curr)))
return error;
if ((error = push_commit(walk, &oid, hide)))
return error; return error;
} }
} }

View File

@ -16,26 +16,20 @@
/** Forward declarations for helpers. */ /** Forward declarations for helpers. */
struct parse_state { struct parse_state {
git_repository *repo;
const char *repodir; const char *repodir;
const char *spec; const char *spec;
int not; int not;
}; };
static void parse_opts(struct parse_state *ps, int argc, char *argv[]); static void parse_opts(struct parse_state *ps, int argc, char *argv[]);
static int parse_revision(struct parse_state *ps); static int parse_revision(git_repository *repo, struct parse_state *ps);
int lg2_rev_parse(git_repository *repo, int argc, char *argv[])
int main(int argc, char *argv[])
{ {
struct parse_state ps = {0}; struct parse_state ps = {0};
git_libgit2_init();
parse_opts(&ps, argc, argv); parse_opts(&ps, argc, argv);
check_lg2(parse_revision(&ps), "Parsing", NULL); check_lg2(parse_revision(repo, &ps), "Parsing", NULL);
git_repository_free(ps.repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -68,19 +62,12 @@ static void parse_opts(struct parse_state *ps, int argc, char *argv[])
} }
} }
static int parse_revision(struct parse_state *ps) static int parse_revision(git_repository *repo, struct parse_state *ps)
{ {
git_revspec rs; git_revspec rs;
char str[GIT_OID_HEXSZ + 1]; char str[GIT_OID_HEXSZ + 1];
if (!ps->repo) { check_lg2(git_revparse(&rs, repo, ps->spec), "Could not parse", ps->spec);
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) { if ((rs.flags & GIT_REVPARSE_SINGLE) != 0) {
git_oid_tostr(str, sizeof(str), git_object_id(rs.from)); git_oid_tostr(str, sizeof(str), git_object_id(rs.from));
@ -94,7 +81,7 @@ static int parse_revision(struct parse_state *ps)
if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) { if ((rs.flags & GIT_REVPARSE_MERGE_BASE) != 0) {
git_oid base; git_oid base;
check_lg2(git_merge_base(&base, ps->repo, check_lg2(git_merge_base(&base, repo,
git_object_id(rs.from), git_object_id(rs.to)), git_object_id(rs.from), git_object_id(rs.to)),
"Could not find merge base", ps->spec); "Could not find merge base", ps->spec);

View File

@ -14,17 +14,15 @@
#include "common.h" #include "common.h"
int main (int argc, char** argv) int lg2_show_index(git_repository *repo, int argc, char **argv)
{ {
git_index *index; git_index *index;
unsigned int i, ecount; size_t i, ecount;
char *dir = "."; char *dir = ".";
size_t dirlen; size_t dirlen;
char out[GIT_OID_HEXSZ+1]; char out[GIT_OID_HEXSZ+1];
out[GIT_OID_HEXSZ] = '\0'; out[GIT_OID_HEXSZ] = '\0';
git_libgit2_init();
if (argc > 2) if (argc > 2)
fatal("usage: showindex [<repo-dir>]", NULL); fatal("usage: showindex [<repo-dir>]", NULL);
if (argc > 1) if (argc > 1)
@ -34,7 +32,6 @@ int main (int argc, char** argv)
if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) { if (dirlen > 5 && strcmp(dir + dirlen - 5, "index") == 0) {
check_lg2(git_index_open(&index, dir), "could not open index", dir); check_lg2(git_index_open(&index, dir), "could not open index", dir);
} else { } else {
git_repository *repo;
check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir); check_lg2(git_repository_open_ext(&repo, dir, 0, NULL), "could not open repository", dir);
check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL); check_lg2(git_repository_index(&index, repo), "could not open repository index", NULL);
git_repository_free(repo); git_repository_free(repo);
@ -64,7 +61,6 @@ int main (int argc, char** argv)
} }
git_index_free(index); git_index_free(index);
git_libgit2_shutdown();
return 0; return 0;
} }

157
examples/stash.c Normal file
View File

@ -0,0 +1,157 @@
/*
* libgit2 "stash" example - shows how to use the stash 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 <stdarg.h>
#include "common.h"
enum subcmd {
SUBCMD_APPLY,
SUBCMD_LIST,
SUBCMD_POP,
SUBCMD_PUSH
};
struct opts {
enum subcmd cmd;
int argc;
char **argv;
};
static void usage(const char *fmt, ...)
{
va_list ap;
fputs("usage: git stash list\n", stderr);
fputs(" or: git stash ( pop | apply )\n", stderr);
fputs(" or: git stash [push]\n", stderr);
fputs("\n", stderr);
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(1);
}
static void parse_subcommand(struct opts *opts, int argc, char *argv[])
{
char *arg = (argc < 2) ? "push" : argv[1];
enum subcmd cmd;
if (!strcmp(arg, "apply")) {
cmd = SUBCMD_APPLY;
} else if (!strcmp(arg, "list")) {
cmd = SUBCMD_LIST;
} else if (!strcmp(arg, "pop")) {
cmd = SUBCMD_POP;
} else if (!strcmp(arg, "push")) {
cmd = SUBCMD_PUSH;
} else {
usage("invalid command %s", arg);
return;
}
opts->cmd = cmd;
opts->argc = (argc < 2) ? argc - 1 : argc - 2;
opts->argv = argv;
}
static int cmd_apply(git_repository *repo, struct opts *opts)
{
if (opts->argc)
usage("apply does not accept any parameters");
check_lg2(git_stash_apply(repo, 0, NULL),
"Unable to apply stash", NULL);
return 0;
}
static int list_stash_cb(size_t index, const char *message,
const git_oid *stash_id, void *payload)
{
UNUSED(stash_id);
UNUSED(payload);
printf("stash@{%"PRIuZ"}: %s\n", index, message);
return 0;
}
static int cmd_list(git_repository *repo, struct opts *opts)
{
if (opts->argc)
usage("list does not accept any parameters");
check_lg2(git_stash_foreach(repo, list_stash_cb, NULL),
"Unable to list stashes", NULL);
return 0;
}
static int cmd_push(git_repository *repo, struct opts *opts)
{
git_signature *signature;
git_commit *stash;
git_oid stashid;
if (opts->argc)
usage("push does not accept any parameters");
check_lg2(git_signature_default(&signature, repo),
"Unable to get signature", NULL);
check_lg2(git_stash_save(&stashid, repo, signature, NULL, GIT_STASH_DEFAULT),
"Unable to save stash", NULL);
check_lg2(git_commit_lookup(&stash, repo, &stashid),
"Unable to lookup stash commit", NULL);
printf("Saved working directory %s\n", git_commit_summary(stash));
git_signature_free(signature);
git_commit_free(stash);
return 0;
}
static int cmd_pop(git_repository *repo, struct opts *opts)
{
if (opts->argc)
usage("pop does not accept any parameters");
check_lg2(git_stash_pop(repo, 0, NULL),
"Unable to pop stash", NULL);
printf("Dropped refs/stash@{0}\n");
return 0;
}
int lg2_stash(git_repository *repo, int argc, char *argv[])
{
struct opts opts = { 0 };
parse_subcommand(&opts, argc, argv);
switch (opts.cmd) {
case SUBCMD_APPLY:
return cmd_apply(repo, &opts);
case SUBCMD_LIST:
return cmd_list(repo, &opts);
case SUBCMD_PUSH:
return cmd_push(repo, &opts);
case SUBCMD_POP:
return cmd_pop(repo, &opts);
}
return -1;
}

View File

@ -13,12 +13,6 @@
*/ */
#include "common.h" #include "common.h"
#ifdef _WIN32
# include <Windows.h>
# define sleep(a) Sleep(a * 1000)
#else
# include <unistd.h>
#endif
/** /**
* This example demonstrates the use of the libgit2 status APIs, * This example demonstrates the use of the libgit2 status APIs,
@ -49,7 +43,7 @@ enum {
#define MAX_PATHSPEC 8 #define MAX_PATHSPEC 8
struct opts { struct status_opts {
git_status_options statusopt; git_status_options statusopt;
char *repodir; char *repodir;
char *pathspec[MAX_PATHSPEC]; char *pathspec[MAX_PATHSPEC];
@ -61,19 +55,16 @@ struct opts {
int repeat; int repeat;
}; };
static void parse_opts(struct opts *o, int argc, char *argv[]); static void parse_opts(struct status_opts *o, int argc, char *argv[]);
static void show_branch(git_repository *repo, int format); static void show_branch(git_repository *repo, int format);
static void print_long(git_status_list *status); static void print_long(git_status_list *status);
static void print_short(git_repository *repo, git_status_list *status); static void print_short(git_repository *repo, git_status_list *status);
static int print_submod(git_submodule *sm, const char *name, void *payload); static int print_submod(git_submodule *sm, const char *name, void *payload);
int main(int argc, char *argv[]) int lg2_status(git_repository *repo, int argc, char *argv[])
{ {
git_repository *repo = NULL;
git_status_list *status; git_status_list *status;
struct opts o = { GIT_STATUS_OPTIONS_INIT, "." }; struct status_opts o = { GIT_STATUS_OPTIONS_INIT, "." };
git_libgit2_init();
o.statusopt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR; o.statusopt.show = GIT_STATUS_SHOW_INDEX_AND_WORKDIR;
o.statusopt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED | o.statusopt.flags = GIT_STATUS_OPT_INCLUDE_UNTRACKED |
@ -82,13 +73,6 @@ int main(int argc, char *argv[])
parse_opts(&o, argc, argv); parse_opts(&o, argc, argv);
/**
* Try to open the repository at the given path (or at the current
* directory if none was given).
*/
check_lg2(git_repository_open_ext(&repo, o.repodir, 0, NULL),
"Could not open repository", o.repodir);
if (git_repository_is_bare(repo)) if (git_repository_is_bare(repo))
fatal("Cannot report status on bare repository", fatal("Cannot report status on bare repository",
git_repository_path(repo)); git_repository_path(repo));
@ -134,9 +118,6 @@ show_status:
goto show_status; goto show_status;
} }
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }
@ -454,7 +435,7 @@ static int print_submod(git_submodule *sm, const char *name, void *payload)
/** /**
* Parse options that git's status command supports. * Parse options that git's status command supports.
*/ */
static void parse_opts(struct opts *o, int argc, char *argv[]) static void parse_opts(struct status_opts *o, int argc, char *argv[])
{ {
struct args_info args = ARGS_INFO_INIT; struct args_info args = ARGS_INFO_INIT;

View File

@ -31,19 +31,19 @@
*/ */
/** tag_options represents the parsed command line options */ /** tag_options represents the parsed command line options */
typedef struct { struct tag_options {
const char *message; const char *message;
const char *pattern; const char *pattern;
const char *tag_name; const char *tag_name;
const char *target; const char *target;
int num_lines; int num_lines;
int force; int force;
} tag_options; };
/** tag_state represents the current program state for dragging around */ /** tag_state represents the current program state for dragging around */
typedef struct { typedef struct {
git_repository *repo; git_repository *repo;
tag_options *opts; struct tag_options *opts;
} tag_state; } tag_state;
/** An action to execute based on the command line arguments */ /** An action to execute based on the command line arguments */
@ -167,7 +167,7 @@ static void action_list_tags(tag_state *state)
static void action_delete_tag(tag_state *state) static void action_delete_tag(tag_state *state)
{ {
tag_options *opts = state->opts; struct tag_options *opts = state->opts;
git_object *obj; git_object *obj;
git_buf abbrev_oid = {0}; git_buf abbrev_oid = {0};
@ -191,7 +191,7 @@ static void action_delete_tag(tag_state *state)
static void action_create_lighweight_tag(tag_state *state) static void action_create_lighweight_tag(tag_state *state)
{ {
git_repository *repo = state->repo; git_repository *repo = state->repo;
tag_options *opts = state->opts; struct tag_options *opts = state->opts;
git_oid oid; git_oid oid;
git_object *target; git_object *target;
@ -213,7 +213,7 @@ static void action_create_lighweight_tag(tag_state *state)
static void action_create_tag(tag_state *state) static void action_create_tag(tag_state *state)
{ {
git_repository *repo = state->repo; git_repository *repo = state->repo;
tag_options *opts = state->opts; struct tag_options *opts = state->opts;
git_signature *tagger; git_signature *tagger;
git_oid oid; git_oid oid;
git_object *target; git_object *target;
@ -243,7 +243,7 @@ static void print_usage(void)
} }
/** Parse command line arguments and choose action to run when done */ /** Parse command line arguments and choose action to run when done */
static void parse_options(tag_action *action, tag_options *opts, int argc, char **argv) static void parse_options(tag_action *action, struct tag_options *opts, int argc, char **argv)
{ {
args_info args = ARGS_INFO_INIT; args_info args = ARGS_INFO_INIT;
*action = &action_list_tags; *action = &action_list_tags;
@ -281,7 +281,7 @@ static void parse_options(tag_action *action, tag_options *opts, int argc, char
} }
/** Initialize tag_options struct */ /** Initialize tag_options struct */
static void tag_options_init(tag_options *opts) static void tag_options_init(struct tag_options *opts)
{ {
memset(opts, 0, sizeof(*opts)); memset(opts, 0, sizeof(*opts));
@ -293,18 +293,12 @@ static void tag_options_init(tag_options *opts)
opts->force = 0; opts->force = 0;
} }
int main(int argc, char **argv) int lg2_tag(git_repository *repo, int argc, char **argv)
{ {
git_repository *repo; struct tag_options opts;
tag_options opts;
tag_action action; tag_action action;
tag_state state; tag_state state;
git_libgit2_init();
check_lg2(git_repository_open_ext(&repo, ".", 0, NULL),
"Could not open repository", NULL);
tag_options_init(&opts); tag_options_init(&opts);
parse_options(&action, &opts, argc, argv); parse_options(&action, &opts, argc, argv);
@ -312,8 +306,5 @@ int main(int argc, char **argv)
state.opts = &opts; state.opts = &opts;
action(&state); action(&state);
git_repository_free(repo);
git_libgit2_shutdown();
return 0; return 0;
} }

View File

@ -1,95 +0,0 @@
#!/bin/bash
THIS_FILE="$(readlink -f "$0")"
ROOT="$(dirname "$(dirname "$(dirname "$THIS_FILE")")")"
PROGRAM="$ROOT"/examples/rev-list
LIBDIR="$ROOT"/build
REPO="$ROOT"/tests/resources/testrepo.git
cd "$REPO"
run () {
LD_LIBRARY_PATH="$LIBDIR" "$PROGRAM" "$@"
}
diff -u - <(run --date-order a4a7dce) <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
out="$(run --topo-order a4a7dce)"
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(echo "$out") <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
c47800c7266a2be04c571c04d5a6614691ea99bd
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(run --date-order --reverse a4a7dce) <<EOF
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
c47800c7266a2be04c571c04d5a6614691ea99bd
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
out=$(run --topo-order --reverse a4a7dce)
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
c47800c7266a2be04c571c04d5a6614691ea99bd
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
diff -u - <(echo "$out") <<EOF
8496071c1b46c854b31185ea97743be6a8774479
5b5b025afb0b4c913b4c338a42934a3863bf3644
c47800c7266a2be04c571c04d5a6614691ea99bd
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
9fd738e8f7967c078dceed8190330fc8648ee56a
a4a7dce85cf63874e984719f4fdd239f5145052f
EOF
out="$(run --date-order --topo-order --reverse --reverse a4a7dce)"
diff -q - <(echo -n "$out") <<EOF >/dev/null ||
a4a7dce85cf63874e984719f4fdd239f5145052f
c47800c7266a2be04c571c04d5a6614691ea99bd
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(echo "$out") <<EOF
a4a7dce85cf63874e984719f4fdd239f5145052f
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
c47800c7266a2be04c571c04d5a6614691ea99bd
5b5b025afb0b4c913b4c338a42934a3863bf3644
8496071c1b46c854b31185ea97743be6a8774479
EOF
diff -u - <(run ^9fd738e~2 9fd738e) <<EOF
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
EOF
diff -u - <(run --not 9fd738e..9fd738e~2) <<EOF
9fd738e8f7967c078dceed8190330fc8648ee56a
4a202b346bb0fb0db7eff3cffeb3c70babbd2045
EOF

View File

@ -1,5 +1,6 @@
LINK_DIRECTORIES(${LIBGIT2_LIBDIRS}) LINK_DIRECTORIES(${LIBGIT2_LIBDIRS})
INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES}) INCLUDE_DIRECTORIES(${LIBGIT2_INCLUDES})
INCLUDE_DIRECTORIES(SYSTEM ${LIBGIT2_SYSTEM_INCLUDES})
IF(BUILD_FUZZERS AND NOT USE_STANDALONE_FUZZERS) IF(BUILD_FUZZERS AND NOT USE_STANDALONE_FUZZERS)
ADD_C_FLAG(-fsanitize=fuzzer) ADD_C_FLAG(-fsanitize=fuzzer)
@ -8,6 +9,8 @@ ENDIF ()
FILE(GLOB SRC_FUZZ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *_fuzzer.c) FILE(GLOB SRC_FUZZ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *_fuzzer.c)
FOREACH(fuzz_target_src ${SRC_FUZZ}) FOREACH(fuzz_target_src ${SRC_FUZZ})
STRING(REPLACE ".c" "" fuzz_target_name ${fuzz_target_src}) STRING(REPLACE ".c" "" fuzz_target_name ${fuzz_target_src})
STRING(REPLACE "_fuzzer" "" fuzz_name ${fuzz_target_name})
SET(${fuzz_target_name}_SOURCES ${fuzz_target_src} ${LIBGIT2_OBJECTS}) SET(${fuzz_target_name}_SOURCES ${fuzz_target_src} ${LIBGIT2_OBJECTS})
IF(USE_STANDALONE_FUZZERS) IF(USE_STANDALONE_FUZZERS)
LIST(APPEND ${fuzz_target_name}_SOURCES "standalone_driver.c") LIST(APPEND ${fuzz_target_name}_SOURCES "standalone_driver.c")
@ -15,4 +18,6 @@ FOREACH(fuzz_target_src ${SRC_FUZZ})
ADD_EXECUTABLE(${fuzz_target_name} ${${fuzz_target_name}_SOURCES}) ADD_EXECUTABLE(${fuzz_target_name} ${${fuzz_target_name}_SOURCES})
SET_TARGET_PROPERTIES(${fuzz_target_name} PROPERTIES C_STANDARD 90) SET_TARGET_PROPERTIES(${fuzz_target_name} PROPERTIES C_STANDARD 90)
TARGET_LINK_LIBRARIES(${fuzz_target_name} ${LIBGIT2_LIBS}) TARGET_LINK_LIBRARIES(${fuzz_target_name} ${LIBGIT2_LIBS})
ADD_TEST(${fuzz_target_name} "${CMAKE_CURRENT_BINARY_DIR}/${fuzz_target_name}" "${CMAKE_CURRENT_SOURCE_DIR}/corpora/${fuzz_name}")
ENDFOREACH() ENDFOREACH()

View File

@ -7,15 +7,9 @@
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#include <git2.h> #include "git2.h"
#include "config_backend.h" #include "config_backend.h"
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
int foreach_cb(const git_config_entry *entry, void *payload) int foreach_cb(const git_config_entry *entry, void *payload)

View File

@ -0,0 +1,13 @@
diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c
index 76186b6fb..f7ce73ac8 100644
--- a/fuzzers/patch_fuzzer.c
+++ b/fuzzers/patch_fuzzer.c
@@ -32,7 +32,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
git_patch* patch;
git_patch_options opts = {(uint32_t)data[0]};
int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts);
- if (status == 0 && patch) {
+ if (patch) {
git_patch_free(patch);
}
return 0;

View File

@ -0,0 +1,45 @@
diff --git a/fuzzers/patch_fuzzer.c b/fuzzers/patch_fuzzer.c
new file mode 100644
index 000000000..76186b6fb
--- /dev/null
+++ b/fuzzers/patch_fuzzer.c
@@ -0,0 +1,39 @@
+/*
+ * libgit2 patch fuzzer target.
+ *
+ * Copyright (C) the libgit2 contributors. All rights reserved.
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "git2.h"
+#include "patch.h"
+#include "patch_parse.h"
+
+#define UNUSED(x) (void)(x)
+
+int LLVMFuzzerInitialize(int *argc, char ***argv)
+{
+ UNUSED(argc);
+ UNUSED(argv);
+
+ if (git_libgit2_init() < 0)
+ abort();
+
+ return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ if (size < 1) {
+ return 0;
+ }
+ git_patch* patch;
+ git_patch_options opts = {(uint32_t)data[0]};
+ int status = git_patch_from_buffer(&patch, (const char*)data+1, size-1, &opts);
+ if (status == 0 && patch) {
+ git_patch_free(patch);
+ }
+ return 0;
+}

View File

@ -7,14 +7,13 @@
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#include <string.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#include <unistd.h>
#include "git2.h" #include "git2.h"
#include "git2/sys/transport.h" #include "git2/sys/transport.h"
#include "futils.h"
#define UNUSED(x) (void)(x) #define UNUSED(x) (void)(x)
@ -166,10 +165,23 @@ void fuzzer_git_abort(const char *op)
int LLVMFuzzerInitialize(int *argc, char ***argv) int LLVMFuzzerInitialize(int *argc, char ***argv)
{ {
char tmp[] = "/tmp/git2.XXXXXX"; #if defined(_WIN32)
char tmpdir[MAX_PATH], path[MAX_PATH];
UNUSED(argc); if (GetTempPath((DWORD)sizeof(tmpdir), tmpdir) == 0)
UNUSED(argv); abort();
if (GetTempFileName(tmpdir, "lg2", 1, path) == 0)
abort();
if (git_futils_mkdir(path, 0700, 0) < 0)
abort();
#else
char path[] = "/tmp/git2.XXXXXX";
if (mkdtemp(path) != path)
abort();
#endif
if (git_libgit2_init() < 0) if (git_libgit2_init() < 0)
abort(); abort();
@ -177,10 +189,10 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0) if (git_libgit2_opts(GIT_OPT_SET_PACK_MAX_OBJECTS, 10000000) < 0)
abort(); abort();
if (mkdtemp(tmp) != tmp) UNUSED(argc);
abort(); UNUSED(argv);
if (git_repository_init(&repo, tmp, 1) < 0) if (git_repository_init(&repo, path, 1) < 0)
fuzzer_git_abort("git_repository_init"); fuzzer_git_abort("git_repository_init");
return 0; return 0;

View File

@ -7,16 +7,12 @@
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h> #include <stdio.h>
#include <limits.h>
#include <unistd.h>
#include "git2.h" #include "git2.h"
#include "git2/sys/mempack.h" #include "git2/sys/mempack.h"
#include "common.h"
#define UNUSED(x) (void)(x) #include "buffer.h"
static git_odb *odb = NULL; static git_odb *odb = NULL;
static git_odb_backend *mempack = NULL; static git_odb_backend *mempack = NULL;
@ -27,8 +23,9 @@ static const unsigned int base_obj_len = 2;
int LLVMFuzzerInitialize(int *argc, char ***argv) int LLVMFuzzerInitialize(int *argc, char ***argv)
{ {
UNUSED(argc); GIT_UNUSED(argc);
UNUSED(argv); GIT_UNUSED(argv);
if (git_libgit2_init() < 0) { if (git_libgit2_init() < 0) {
fprintf(stderr, "Failed to initialize libgit2\n"); fprintf(stderr, "Failed to initialize libgit2\n");
abort(); abort();
@ -54,12 +51,11 @@ int LLVMFuzzerInitialize(int *argc, char ***argv)
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
git_indexer_progress stats = {0, 0};
git_indexer *indexer = NULL; git_indexer *indexer = NULL;
git_transfer_progress stats = {0, 0}; git_buf path = GIT_BUF_INIT;
git_oid oid;
bool append_hash = false; bool append_hash = false;
git_oid id;
char hash[GIT_OID_HEXSZ + 1] = {0};
char path[PATH_MAX];
if (size == 0) if (size == 0)
return 0; return 0;
@ -70,7 +66,7 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
} }
git_mempack_reset(mempack); git_mempack_reset(mempack);
if (git_odb_write(&id, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB) < 0) { if (git_odb_write(&oid, odb, base_obj, base_obj_len, GIT_OBJECT_BLOB) < 0) {
fprintf(stderr, "Failed to add an object to the odb\n"); fprintf(stderr, "Failed to add an object to the odb\n");
abort(); abort();
} }
@ -92,7 +88,6 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (git_indexer_append(indexer, data, size, &stats) < 0) if (git_indexer_append(indexer, data, size, &stats) < 0)
goto cleanup; goto cleanup;
if (append_hash) { if (append_hash) {
git_oid oid;
if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB) < 0) { if (git_odb_hash(&oid, data, size, GIT_OBJECT_BLOB) < 0) {
fprintf(stderr, "Failed to compute the SHA1 hash\n"); fprintf(stderr, "Failed to compute the SHA1 hash\n");
abort(); abort();
@ -104,19 +99,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (git_indexer_commit(indexer, &stats) < 0) if (git_indexer_commit(indexer, &stats) < 0)
goto cleanup; goto cleanup;
/* if (git_buf_printf(&path, "pack-%s.idx", git_oid_tostr_s(git_indexer_hash(indexer))) < 0)
* We made it! We managed to produce a valid packfile. goto cleanup;
* Let's clean it up. p_unlink(git_buf_cstr(&path));
*/
git_oid_fmt(hash, git_indexer_hash(indexer)); git_buf_clear(&path);
printf("Generated packfile %s\n", hash);
snprintf(path, sizeof(path), "pack-%s.idx", hash); if (git_buf_printf(&path, "pack-%s.pack", git_oid_tostr_s(git_indexer_hash(indexer))) < 0)
unlink(path); goto cleanup;
snprintf(path, sizeof(path), "pack-%s.pack", hash); p_unlink(git_buf_cstr(&path));
unlink(path);
cleanup: cleanup:
git_mempack_reset(mempack); git_mempack_reset(mempack);
git_indexer_free(indexer); git_indexer_free(indexer);
git_buf_dispose(&path);
return 0; return 0;
} }

View File

@ -0,0 +1,38 @@
/*
* libgit2 patch parser fuzzer target.
*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "git2.h"
#include "patch.h"
#include "patch_parse.h"
#define UNUSED(x) (void)(x)
int LLVMFuzzerInitialize(int *argc, char ***argv)
{
UNUSED(argc);
UNUSED(argv);
if (git_libgit2_init() < 0)
abort();
return 0;
}
int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{
if (size) {
git_patch *patch = NULL;
git_patch_options opts = GIT_PATCH_OPTIONS_INIT;
opts.prefix_len = (uint32_t)data[0];
git_patch_from_buffer(&patch, (const char *)data + 1, size - 1,
&opts);
git_patch_free(patch);
}
return 0;
}

View File

@ -5,14 +5,10 @@
* a Linking Exception. For full terms see the included COPYING file. * a Linking Exception. For full terms see the included COPYING file.
*/ */
#include <assert.h>
#include <dirent.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include "git2.h" #include "git2.h"
#include "fileops.h" #include "futils.h"
#include "path.h" #include "path.h"
extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size); extern int LLVMFuzzerTestOneInput(const unsigned char *data, size_t size);
@ -24,7 +20,7 @@ static int run_one_file(const char *filename)
int error = 0; int error = 0;
if (git_futils_readbuffer(&buf, filename) < 0) { if (git_futils_readbuffer(&buf, filename) < 0) {
fprintf(stderr, "Failed to read %s: %m\n", filename); fprintf(stderr, "Failed to read %s: %s\n", filename, git_error_last()->message);
error = -1; error = -1;
goto exit; goto exit;
} }
@ -57,7 +53,8 @@ int main(int argc, char **argv)
LLVMFuzzerInitialize(&argc, &argv); LLVMFuzzerInitialize(&argc, &argv);
if (git_path_dirload(&corpus_files, argv[1], 0, 0x0) < 0) { if (git_path_dirload(&corpus_files, argv[1], 0, 0x0) < 0) {
fprintf(stderr, "Failed to scan corpus directory: %m\n"); fprintf(stderr, "Failed to scan corpus directory '%s': %s\n",
argv[1], git_error_last()->message);
error = -1; error = -1;
goto exit; goto exit;
} }

View File

@ -15,12 +15,14 @@
#include "git2/blame.h" #include "git2/blame.h"
#include "git2/branch.h" #include "git2/branch.h"
#include "git2/buffer.h" #include "git2/buffer.h"
#include "git2/cert.h"
#include "git2/checkout.h" #include "git2/checkout.h"
#include "git2/cherrypick.h" #include "git2/cherrypick.h"
#include "git2/clone.h" #include "git2/clone.h"
#include "git2/commit.h" #include "git2/commit.h"
#include "git2/common.h" #include "git2/common.h"
#include "git2/config.h" #include "git2/config.h"
#include "git2/credential.h"
#include "git2/deprecated.h" #include "git2/deprecated.h"
#include "git2/describe.h" #include "git2/describe.h"
#include "git2/diff.h" #include "git2/diff.h"

View File

@ -53,25 +53,44 @@ typedef int GIT_CALLBACK(git_apply_hunk_cb)(
const git_diff_hunk *hunk, const git_diff_hunk *hunk,
void *payload); void *payload);
/** Flags controlling the behavior of git_apply */
typedef enum {
/**
* Don't actually make changes, just test that the patch applies.
* This is the equivalent of `git apply --check`.
*/
GIT_APPLY_CHECK = (1 << 0),
} git_apply_flags_t;
/** /**
* Apply options structure * Apply options structure
* *
* Initialize with `GIT_APPLY_OPTIONS_INIT`. Alternatively, you can * Initialize with `GIT_APPLY_OPTIONS_INIT`. Alternatively, you can
* use `git_apply_init_options`. * use `git_apply_options_init`.
* *
* @see git_apply_to_tree, git_apply * @see git_apply_to_tree, git_apply
*/ */
typedef struct { typedef struct {
unsigned int version; unsigned int version; /**< The version */
/** When applying a patch, callback that will be made per delta (file). */
git_apply_delta_cb delta_cb; git_apply_delta_cb delta_cb;
/** When applying a patch, callback that will be made per hunk. */
git_apply_hunk_cb hunk_cb; git_apply_hunk_cb hunk_cb;
/** Payload passed to both delta_cb & hunk_cb. */
void *payload; void *payload;
/** Bitmask of git_apply_flags_t */
unsigned int flags;
} git_apply_options; } git_apply_options;
#define GIT_APPLY_OPTIONS_VERSION 1 #define GIT_APPLY_OPTIONS_VERSION 1
#define GIT_APPLY_OPTIONS_INIT {GIT_APPLY_OPTIONS_VERSION} #define GIT_APPLY_OPTIONS_INIT {GIT_APPLY_OPTIONS_VERSION}
GIT_EXTERN(int) git_apply_options_init(git_apply_options *opts, unsigned int version);
/** /**
* Apply a `git_diff` to a `git_tree`, and return the resulting image * Apply a `git_diff` to a `git_tree`, and return the resulting image
* as an index. * as an index.
@ -89,6 +108,7 @@ GIT_EXTERN(int) git_apply_to_tree(
git_diff *diff, git_diff *diff,
const git_apply_options *options); const git_apply_options *options);
/** Possible application locations for git_apply */
typedef enum { typedef enum {
/** /**
* Apply the patch to the workdir, leaving the index untouched. * Apply the patch to the workdir, leaving the index untouched.

View File

@ -30,7 +30,7 @@ GIT_BEGIN_DECL
* Then for file `xyz.c` looking up attribute "foo" gives a value for * Then for file `xyz.c` looking up attribute "foo" gives a value for
* which `GIT_ATTR_TRUE(value)` is true. * which `GIT_ATTR_TRUE(value)` is true.
*/ */
#define GIT_ATTR_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_TRUE_T) #define GIT_ATTR_IS_TRUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_TRUE)
/** /**
* GIT_ATTR_FALSE checks if an attribute is set off. In core git * GIT_ATTR_FALSE checks if an attribute is set off. In core git
@ -44,7 +44,7 @@ GIT_BEGIN_DECL
* Then for file `zyx.h` looking up attribute "foo" gives a value for * Then for file `zyx.h` looking up attribute "foo" gives a value for
* which `GIT_ATTR_FALSE(value)` is true. * which `GIT_ATTR_FALSE(value)` is true.
*/ */
#define GIT_ATTR_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_FALSE_T) #define GIT_ATTR_IS_FALSE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_FALSE)
/** /**
* GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This * GIT_ATTR_UNSPECIFIED checks if an attribute is unspecified. This
@ -62,7 +62,7 @@ GIT_BEGIN_DECL
* file `onefile.rb` or looking up "bar" on any file will all give * file `onefile.rb` or looking up "bar" on any file will all give
* `GIT_ATTR_UNSPECIFIED(value)` of true. * `GIT_ATTR_UNSPECIFIED(value)` of true.
*/ */
#define GIT_ATTR_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_UNSPECIFIED_T) #define GIT_ATTR_IS_UNSPECIFIED(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_UNSPECIFIED)
/** /**
* GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as * GIT_ATTR_HAS_VALUE checks if an attribute is set to a value (as
@ -74,17 +74,17 @@ GIT_BEGIN_DECL
* Given this, looking up "eol" for `onefile.txt` will give back the * Given this, looking up "eol" for `onefile.txt` will give back the
* string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true. * string "lf" and `GIT_ATTR_SET_TO_VALUE(attr)` will return true.
*/ */
#define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_T) #define GIT_ATTR_HAS_VALUE(attr) (git_attr_value(attr) == GIT_ATTR_VALUE_STRING)
/** /**
* Possible states for an attribute * Possible states for an attribute
*/ */
typedef enum { typedef enum {
GIT_ATTR_UNSPECIFIED_T = 0, /**< The attribute has been left unspecified */ GIT_ATTR_VALUE_UNSPECIFIED = 0, /**< The attribute has been left unspecified */
GIT_ATTR_TRUE_T, /**< The attribute has been set */ GIT_ATTR_VALUE_TRUE, /**< The attribute has been set */
GIT_ATTR_FALSE_T, /**< The attribute has been unset */ GIT_ATTR_VALUE_FALSE, /**< The attribute has been unset */
GIT_ATTR_VALUE_T, /**< This attribute has a value */ GIT_ATTR_VALUE_STRING, /**< This attribute has a value */
} git_attr_t; } git_attr_value_t;
/** /**
* Return the value type for a given attribute. * Return the value type for a given attribute.
@ -99,7 +99,7 @@ typedef enum {
* @param attr The attribute * @param attr The attribute
* @return the value type for the attribute * @return the value type for the attribute
*/ */
GIT_EXTERN(git_attr_t) git_attr_value(const char *attr); GIT_EXTERN(git_attr_value_t) git_attr_value(const char *attr);
/** /**
* Check attribute flags: Reading values from index and working directory. * Check attribute flags: Reading values from index and working directory.
@ -119,13 +119,20 @@ GIT_EXTERN(git_attr_t) git_attr_value(const char *attr);
#define GIT_ATTR_CHECK_INDEX_ONLY 2 #define GIT_ATTR_CHECK_INDEX_ONLY 2
/** /**
* Check attribute flags: Using the system attributes file. * Check attribute flags: controlling extended attribute behavior.
* *
* Normally, attribute checks include looking in the /etc (or system * Normally, attribute checks include looking in the /etc (or system
* equivalent) directory for a `gitattributes` file. Passing this * equivalent) directory for a `gitattributes` file. Passing this
* flag will cause attribute checks to ignore that file. * flag will cause attribute checks to ignore that file.
* equivalent) directory for a `gitattributes` file. Passing the
* `GIT_ATTR_CHECK_NO_SYSTEM` flag will cause attribute checks to
* ignore that file.
*
* Passing the `GIT_ATTR_CHECK_INCLUDE_HEAD` flag will use attributes
* from a `.gitattributes` file in the repository at the HEAD revision.
*/ */
#define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2) #define GIT_ATTR_CHECK_NO_SYSTEM (1 << 2)
#define GIT_ATTR_CHECK_INCLUDE_HEAD (1 << 3)
/** /**
* Look up the value of one git attribute for path. * Look up the value of one git attribute for path.
@ -231,8 +238,11 @@ GIT_EXTERN(int) git_attr_foreach(
* disk no longer match the cached contents of memory. This will cause * disk no longer match the cached contents of memory. This will cause
* the attributes files to be reloaded the next time that an attribute * the attributes files to be reloaded the next time that an attribute
* access function is called. * access function is called.
*
* @param repo The repository containing the gitattributes cache
* @return 0 on success, or an error code
*/ */
GIT_EXTERN(void) git_attr_cache_flush( GIT_EXTERN(int) git_attr_cache_flush(
git_repository *repo); git_repository *repo);
/** /**

View File

@ -53,7 +53,7 @@ typedef enum {
* Blame options structure * Blame options structure
* *
* Initialize with `GIT_BLAME_OPTIONS_INIT`. Alternatively, you can * Initialize with `GIT_BLAME_OPTIONS_INIT`. Alternatively, you can
* use `git_blame_init_options`. * use `git_blame_options_init`.
* *
*/ */
typedef struct git_blame_options { typedef struct git_blame_options {
@ -100,7 +100,7 @@ typedef struct git_blame_options {
* @param version The struct version; pass `GIT_BLAME_OPTIONS_VERSION`. * @param version The struct version; pass `GIT_BLAME_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure. * @return Zero on success; -1 on failure.
*/ */
GIT_EXTERN(int) git_blame_init_options( GIT_EXTERN(int) git_blame_options_init(
git_blame_options *opts, git_blame_options *opts,
unsigned int version); unsigned int version);

View File

@ -94,7 +94,40 @@ GIT_EXTERN(const void *) git_blob_rawcontent(const git_blob *blob);
* @param blob pointer to the blob * @param blob pointer to the blob
* @return size on bytes * @return size on bytes
*/ */
GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob); GIT_EXTERN(git_object_size_t) git_blob_rawsize(const git_blob *blob);
/**
* Flags to control the functionality of `git_blob_filter`.
*/
typedef enum {
/** When set, filters will not be applied to binary files. */
GIT_BLOB_FILTER_CHECK_FOR_BINARY = (1 << 0),
/**
* When set, filters will not load configuration from the
* system-wide `gitattributes` in `/etc` (or system equivalent).
*/
GIT_BLOB_FILTER_NO_SYSTEM_ATTRIBUTES = (1 << 1),
/**
* When set, filters will be loaded from a `.gitattributes` file
* in the HEAD commit.
*/
GIT_BLOB_FILTER_ATTTRIBUTES_FROM_HEAD = (1 << 2),
} git_blob_filter_flag_t;
/**
* The options used when applying filter options to a file.
*/
typedef struct {
int version;
/** Flags to control the filtering process, see `git_blob_filter_flag_t` above */
uint32_t flags;
} git_blob_filter_options;
#define GIT_BLOB_FILTER_OPTIONS_VERSION 1
#define GIT_BLOB_FILTER_OPTIONS_INIT {GIT_BLOB_FILTER_OPTIONS_VERSION, GIT_BLOB_FILTER_CHECK_FOR_BINARY}
/** /**
* Get a buffer with the filtered content of a blob. * Get a buffer with the filtered content of a blob.
@ -115,15 +148,14 @@ GIT_EXTERN(git_off_t) git_blob_rawsize(const git_blob *blob);
* @param out The git_buf to be filled in * @param out The git_buf to be filled in
* @param blob Pointer to the blob * @param blob Pointer to the blob
* @param as_path Path used for file attribute lookups, etc. * @param as_path Path used for file attribute lookups, etc.
* @param check_for_binary_data Should this test if blob content contains * @param opts Options to use for filtering the blob
* NUL bytes / looks like binary data before applying filters?
* @return 0 on success or an error code * @return 0 on success or an error code
*/ */
GIT_EXTERN(int) git_blob_filtered_content( GIT_EXTERN(int) git_blob_filter(
git_buf *out, git_buf *out,
git_blob *blob, git_blob *blob,
const char *as_path, const char *as_path,
int check_for_binary_data); git_blob_filter_options *opts);
/** /**
* Read a file from the working folder of a repository * Read a file from the working folder of a repository
@ -136,7 +168,7 @@ GIT_EXTERN(int) git_blob_filtered_content(
* relative to the repository's working dir * relative to the repository's working dir
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, const char *relative_path); GIT_EXTERN(int) git_blob_create_from_workdir(git_oid *id, git_repository *repo, const char *relative_path);
/** /**
* Read a file from the filesystem and write its content * Read a file from the filesystem and write its content
@ -148,7 +180,7 @@ GIT_EXTERN(int) git_blob_create_fromworkdir(git_oid *id, git_repository *repo, c
* @param path file from which the blob will be created * @param path file from which the blob will be created
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, const char *path); GIT_EXTERN(int) git_blob_create_from_disk(git_oid *id, git_repository *repo, const char *path);
/** /**
* Create a stream to write a new blob into the object db * Create a stream to write a new blob into the object db
@ -156,12 +188,12 @@ GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, cons
* This function may need to buffer the data on disk and will in * This function may need to buffer the data on disk and will in
* general not be the right choice if you know the size of the data * general not be the right choice if you know the size of the data
* to write. If you have data in memory, use * to write. If you have data in memory, use
* `git_blob_create_frombuffer()`. If you do not, but know the size of * `git_blob_create_from_buffer()`. If you do not, but know the size of
* the contents (and don't want/need to perform filtering), use * the contents (and don't want/need to perform filtering), use
* `git_odb_open_wstream()`. * `git_odb_open_wstream()`.
* *
* Don't close this stream yourself but pass it to * Don't close this stream yourself but pass it to
* `git_blob_create_fromstream_commit()` to commit the write to the * `git_blob_create_from_stream_commit()` to commit the write to the
* object db and get the object id. * object db and get the object id.
* *
* If the `hintpath` parameter is filled, it will be used to determine * If the `hintpath` parameter is filled, it will be used to determine
@ -175,7 +207,7 @@ GIT_EXTERN(int) git_blob_create_fromdisk(git_oid *id, git_repository *repo, cons
* to apply onto the content of the blob to be created. * to apply onto the content of the blob to be created.
* @return 0 or error code * @return 0 or error code
*/ */
GIT_EXTERN(int) git_blob_create_fromstream( GIT_EXTERN(int) git_blob_create_from_stream(
git_writestream **out, git_writestream **out,
git_repository *repo, git_repository *repo,
const char *hintpath); const char *hintpath);
@ -189,7 +221,7 @@ GIT_EXTERN(int) git_blob_create_fromstream(
* @param stream the stream to close * @param stream the stream to close
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_blob_create_fromstream_commit( GIT_EXTERN(int) git_blob_create_from_stream_commit(
git_oid *out, git_oid *out,
git_writestream *stream); git_writestream *stream);
@ -202,7 +234,7 @@ GIT_EXTERN(int) git_blob_create_fromstream_commit(
* @param len length of the data * @param len length of the data
* @return 0 or an error code * @return 0 or an error code
*/ */
GIT_EXTERN(int) git_blob_create_frombuffer( GIT_EXTERN(int) git_blob_create_from_buffer(
git_oid *id, git_repository *repo, const void *buffer, size_t len); git_oid *id, git_repository *repo, const void *buffer, size_t len);
/** /**

View File

@ -75,9 +75,9 @@ GIT_EXTERN(int) git_branch_create_from_annotated(
/** /**
* Delete an existing branch reference. * Delete an existing branch reference.
* *
* If the branch is successfully deleted, the passed reference * Note that if the deletion succeeds, the reference object will not
* object will be invalidated. The reference must be freed manually * be valid anymore, and should be freed immediately by the user using
* by the user. * `git_reference_free()`.
* *
* @param branch A valid reference representing a branch * @param branch A valid reference representing a branch
* @return 0 on success, or an error code. * @return 0 on success, or an error code.
@ -126,6 +126,12 @@ GIT_EXTERN(void) git_branch_iterator_free(git_branch_iterator *iter);
* The new branch name will be checked for validity. * The new branch name will be checked for validity.
* See `git_tag_create()` for rules about valid names. * See `git_tag_create()` for rules about valid names.
* *
* Note that if the move succeeds, the old reference object will not
+ be valid anymore, and should be freed immediately by the user using
+ `git_reference_free()`.
*
* @param out New reference object for the updated name.
*
* @param branch Current underlying reference of the branch. * @param branch Current underlying reference of the branch.
* *
* @param new_branch_name Target name of the branch once the move * @param new_branch_name Target name of the branch once the move
@ -145,17 +151,14 @@ GIT_EXTERN(int) git_branch_move(
* Lookup a branch by its name in a repository. * Lookup a branch by its name in a repository.
* *
* The generated reference must be freed by the user. * The generated reference must be freed by the user.
*
* The branch name will be checked for validity. * The branch name will be checked for validity.
* See `git_tag_create()` for rules about valid names. *
* @see git_tag_create for rules about valid names.
* *
* @param out pointer to the looked-up branch reference * @param out pointer to the looked-up branch reference
*
* @param repo the repository to look up the branch * @param repo the repository to look up the branch
*
* @param branch_name Name of the branch to be looked-up; * @param branch_name Name of the branch to be looked-up;
* this name is validated for consistency. * this name is validated for consistency.
*
* @param branch_type Type of the considered branch. This should * @param branch_type Type of the considered branch. This should
* be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE. * be valued with either GIT_BRANCH_LOCAL or GIT_BRANCH_REMOTE.
* *
@ -169,65 +172,74 @@ GIT_EXTERN(int) git_branch_lookup(
git_branch_t branch_type); git_branch_t branch_type);
/** /**
* Return the name of the given local or remote branch. * Get the branch name
* *
* The name of the branch matches the definition of the name * Given a reference object, this will check that it really is a branch (ie.
* for git_branch_lookup. That is, if the returned name is given * it lives under "refs/heads/" or "refs/remotes/"), and return the branch part
* to git_branch_lookup() then the reference is returned that * of it.
* was given to this function.
* *
* @param out where the pointer of branch name is stored; * @param out Pointer to the abbreviated reference name.
* this is valid as long as the ref is not freed. * Owned by ref, do not free.
* @param ref the reference ideally pointing to a branch
* *
* @return 0 on success; otherwise an error code (e.g., if the * @param ref A reference object, ideally pointing to a branch
* ref is no local or remote branch). *
* @return 0 on success; GIT_EINVALID if the reference isn't either a local or
* remote branch, otherwise an error code.
*/ */
GIT_EXTERN(int) git_branch_name( GIT_EXTERN(int) git_branch_name(
const char **out, const char **out,
const git_reference *ref); const git_reference *ref);
/** /**
* Return the reference supporting the remote tracking branch, * Get the upstream of a branch
* given a local branch reference.
* *
* @param out Pointer where to store the retrieved * Given a reference, this will return a new reference object corresponding
* reference. * to its remote tracking branch. The reference must be a local branch.
* *
* @see git_branch_upstream_name for details on the resolution.
*
* @param out Pointer where to store the retrieved reference.
* @param branch Current underlying reference of the branch. * @param branch Current underlying reference of the branch.
* *
* @return 0 on success; GIT_ENOTFOUND when no remote tracking * @return 0 on success; GIT_ENOTFOUND when no remote tracking
* reference exists, otherwise an error code. * reference exists, otherwise an error code.
*/ */
GIT_EXTERN(int) git_branch_upstream( GIT_EXTERN(int) git_branch_upstream(
git_reference **out, git_reference **out,
const git_reference *branch); const git_reference *branch);
/** /**
* Set the upstream configuration for a given local branch * Set a branch's upstream branch
*
* This will update the configuration to set the branch named `branch_name` as the upstream of `branch`.
* Pass a NULL name to unset the upstream information.
*
* @note the actual tracking reference must have been already created for the
* operation to succeed.
* *
* @param branch the branch to configure * @param branch the branch to configure
* @param branch_name remote-tracking or local branch to set as upstream.
* *
* @param upstream_name remote-tracking or local branch to set as * @return 0 on success; GIT_ENOTFOUND if there's no branch named `branch_name`
* upstream. Pass NULL to unset. * or an error code
*
* @return 0 or an error code
*/ */
GIT_EXTERN(int) git_branch_set_upstream(git_reference *branch, const char *upstream_name); GIT_EXTERN(int) git_branch_set_upstream(
git_reference *branch,
const char *branch_name);
/** /**
* Return the name of the reference supporting the remote tracking branch, * Get the upstream name of a branch
* given the name of a local branch reference.
* *
* @param out Pointer to the user-allocated git_buf which will be * Given a local branch, this will return its remote-tracking branch information,
* filled with the name of the reference. * as a full reference name, ie. "feature/nice" would become
* * "refs/remote/origin/feature/nice", depending on that branch's configuration.
* @param repo the repository where the branches live
* *
* @param out the buffer into which the name will be written.
* @param repo the repository where the branches live.
* @param refname reference name of the local branch. * @param refname reference name of the local branch.
* *
* @return 0, GIT_ENOTFOUND when no remote tracking reference exists, * @return 0 on success, GIT_ENOTFOUND when no remote tracking reference exists,
* otherwise an error code. * or an error code.
*/ */
GIT_EXTERN(int) git_branch_upstream_name( GIT_EXTERN(int) git_branch_upstream_name(
git_buf *out, git_buf *out,
@ -235,50 +247,55 @@ GIT_EXTERN(int) git_branch_upstream_name(
const char *refname); const char *refname);
/** /**
* Determine if the current local branch is pointed at by HEAD. * Determine if HEAD points to the given branch
* *
* @param branch Current underlying reference of the branch. * @param branch A reference to a local branch.
* *
* @return 1 if HEAD points at the branch, 0 if it isn't, * @return 1 if HEAD points at the branch, 0 if it isn't, or a negative value
* error code otherwise. * as an error code.
*/ */
GIT_EXTERN(int) git_branch_is_head( GIT_EXTERN(int) git_branch_is_head(
const git_reference *branch); const git_reference *branch);
/** /**
* Determine if the current branch is checked out in any linked * Determine if any HEAD points to the current branch
* repository.
* *
* @param branch Reference to the branch. * This will iterate over all known linked repositories (usually in the form of
* worktrees) and report whether any HEAD is pointing at the current branch.
* *
* @return 1 if branch is checked out, 0 if it isn't, * @param branch A reference to a local branch.
* error code otherwise. *
* @return 1 if branch is checked out, 0 if it isn't, an error code otherwise.
*/ */
GIT_EXTERN(int) git_branch_is_checked_out( GIT_EXTERN(int) git_branch_is_checked_out(
const git_reference *branch); const git_reference *branch);
/** /**
* Return the name of remote that the remote tracking branch belongs to. * Find the remote name of a remote-tracking branch
* *
* @param out Pointer to the user-allocated git_buf which will be filled with the name of the remote. * This will return the name of the remote whose fetch refspec is matching
* the given branch. E.g. given a branch "refs/remotes/test/master", it will
* extract the "test" part. If refspecs from multiple remotes match,
* the function will return GIT_EAMBIGUOUS.
* *
* @param out The buffer into which the name will be written.
* @param repo The repository where the branch lives. * @param repo The repository where the branch lives.
* @param refname complete name of the remote tracking branch.
* *
* @param canonical_branch_name name of the remote tracking branch. * @return 0 on success, GIT_ENOTFOUND when no matching remote was found,
* * GIT_EAMBIGUOUS when the branch maps to several remotes,
* @return 0, GIT_ENOTFOUND * otherwise an error code.
* when no remote matching remote was found,
* GIT_EAMBIGUOUS when the branch maps to several remotes,
* otherwise an error code.
*/ */
GIT_EXTERN(int) git_branch_remote_name( GIT_EXTERN(int) git_branch_remote_name(
git_buf *out, git_buf *out,
git_repository *repo, git_repository *repo,
const char *canonical_branch_name); const char *refname);
/** /**
* Retrieve the name of the upstream remote of a local branch * Retrieve the upstream remote of a local branch
*
* This will return the currently configured "branch.*.remote" for a given
* branch. This branch must be local.
* *
* @param buf the buffer into which to write the name * @param buf the buffer into which to write the name
* @param repo the repository in which to look * @param repo the repository in which to look

View File

@ -32,26 +32,32 @@ GIT_BEGIN_DECL
* a block of memory they hold. In this case, libgit2 will not resize or * a block of memory they hold. In this case, libgit2 will not resize or
* free the memory, but will read from it as needed. * 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, * 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 * 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. * those cases, the behavior will be clearly documented by the API.
*/ */
typedef struct { typedef struct {
/**
* The buffer contents.
*
* `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.
*/
char *ptr; char *ptr;
size_t asize, size;
/**
* `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.
*/
size_t asize;
/**
* `size` holds the size (in bytes) of the data that is actually used.
*/
size_t size;
} git_buf; } git_buf;
/** /**

135
include/git2/cert.h Normal file
View File

@ -0,0 +1,135 @@
/*
* 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_cert_h__
#define INCLUDE_git_cert_h__
#include "common.h"
/**
* @file git2/cert.h
* @brief Git certificate objects
* @defgroup git_cert Certificate objects
* @ingroup Git
* @{
*/
GIT_BEGIN_DECL
/**
* Type of host certificate structure that is passed to the check callback
*/
typedef enum git_cert_t {
/**
* No information about the certificate is available. This may
* happen when using curl.
*/
GIT_CERT_NONE,
/**
* The `data` argument to the callback will be a pointer to
* the DER-encoded data.
*/
GIT_CERT_X509,
/**
* The `data` argument to the callback will be a pointer to a
* `git_cert_hostkey` structure.
*/
GIT_CERT_HOSTKEY_LIBSSH2,
/**
* The `data` argument to the callback will be a pointer to a
* `git_strarray` with `name:content` strings containing
* information about the certificate. This is used when using
* curl.
*/
GIT_CERT_STRARRAY,
} git_cert_t;
/**
* Parent type for `git_cert_hostkey` and `git_cert_x509`.
*/
struct git_cert {
/**
* Type of certificate. A `GIT_CERT_` value.
*/
git_cert_t cert_type;
};
/**
* Callback for the user's custom certificate checks.
*
* @param cert The host certificate
* @param valid Whether the libgit2 checks (OpenSSL or WinHTTP) think
* this certificate is valid
* @param host Hostname of the host libgit2 connected to
* @param payload Payload provided by the caller
* @return 0 to proceed with the connection, < 0 to fail the connection
* or > 0 to indicate that the callback refused to act and that
* the existing validity determination should be honored
*/
typedef int GIT_CALLBACK(git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
/**
* Type of SSH host fingerprint
*/
typedef enum {
/** MD5 is available */
GIT_CERT_SSH_MD5 = (1 << 0),
/** SHA-1 is available */
GIT_CERT_SSH_SHA1 = (1 << 1),
/** SHA-256 is available */
GIT_CERT_SSH_SHA256 = (1 << 2),
} git_cert_ssh_t;
/**
* Hostkey information taken from libssh2
*/
typedef struct {
git_cert parent; /**< The parent cert */
/**
* A hostkey type from libssh2, either
* `GIT_CERT_SSH_MD5` or `GIT_CERT_SSH_SHA1`
*/
git_cert_ssh_t type;
/**
* Hostkey hash. If type has `GIT_CERT_SSH_MD5` set, this will
* have the MD5 hash of the hostkey.
*/
unsigned char hash_md5[16];
/**
* Hostkey hash. If type has `GIT_CERT_SSH_SHA1` set, this will
* have the SHA-1 hash of the hostkey.
*/
unsigned char hash_sha1[20];
/**
* Hostkey hash. If type has `GIT_CERT_SSH_SHA256` set, this will
* have the SHA-256 hash of the hostkey.
*/
unsigned char hash_sha256[32];
} git_cert_hostkey;
/**
* X.509 certificate information
*/
typedef struct {
git_cert parent; /**< The parent cert */
/**
* Pointer to the X.509 certificate data
*/
void *data;
/**
* Length of the memory block pointed to by `data`.
*/
size_t len;
} git_cert_x509;
/** @} */
GIT_END_DECL
#endif

View File

@ -106,10 +106,22 @@ GIT_BEGIN_DECL
typedef enum { typedef enum {
GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */ GIT_CHECKOUT_NONE = 0, /**< default is a dry run, no actual updates */
/** Allow safe updates that cannot overwrite uncommitted data */ /**
* Allow safe updates that cannot overwrite uncommitted data.
* If the uncommitted changes don't conflict with the checked out files,
* the checkout will still proceed, leaving the changes intact.
*
* Mutually exclusive with GIT_CHECKOUT_FORCE.
* GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
*/
GIT_CHECKOUT_SAFE = (1u << 0), GIT_CHECKOUT_SAFE = (1u << 0),
/** Allow all updates to force working directory to look like index */ /**
* Allow all updates to force working directory to look like index.
*
* Mutually exclusive with GIT_CHECKOUT_SAFE.
* GIT_CHECKOUT_FORCE takes precedence over GIT_CHECKOUT_SAFE.
*/
GIT_CHECKOUT_FORCE = (1u << 1), GIT_CHECKOUT_FORCE = (1u << 1),
@ -213,6 +225,7 @@ typedef enum {
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFFu
} git_checkout_notify_t; } git_checkout_notify_t;
/** Checkout performance-reporting structure */
typedef struct { typedef struct {
size_t mkdir_calls; size_t mkdir_calls;
size_t stat_calls; size_t stat_calls;
@ -244,11 +257,11 @@ typedef void GIT_CALLBACK(git_checkout_perfdata_cb)(
* Checkout options structure * Checkout options structure
* *
* Initialize with `GIT_CHECKOUT_OPTIONS_INIT`. Alternatively, you can * Initialize with `GIT_CHECKOUT_OPTIONS_INIT`. Alternatively, you can
* use `git_checkout_init_options`. * use `git_checkout_options_init`.
* *
*/ */
typedef struct git_checkout_options { typedef struct git_checkout_options {
unsigned int version; unsigned int version; /**< The version */
unsigned int checkout_strategy; /**< default will be a safe checkout */ unsigned int checkout_strategy; /**< default will be a safe checkout */
@ -258,29 +271,46 @@ typedef struct git_checkout_options {
int file_open_flags; /**< default is O_CREAT | O_TRUNC | O_WRONLY */ int file_open_flags; /**< default is O_CREAT | O_TRUNC | O_WRONLY */
unsigned int notify_flags; /**< see `git_checkout_notify_t` above */ unsigned int notify_flags; /**< see `git_checkout_notify_t` above */
/**
* Optional callback to get notifications on specific file states.
* @see git_checkout_notify_t
*/
git_checkout_notify_cb notify_cb; git_checkout_notify_cb notify_cb;
/** Payload passed to notify_cb */
void *notify_payload; void *notify_payload;
/** Optional callback to notify the consumer of checkout progress. */ /** Optional callback to notify the consumer of checkout progress. */
git_checkout_progress_cb progress_cb; git_checkout_progress_cb progress_cb;
/** Payload passed to progress_cb */
void *progress_payload; void *progress_payload;
/** When not zeroed out, array of fnmatch patterns specifying which /**
* paths should be taken into account, otherwise all files. Use * A list of wildmatch patterns or paths.
* GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as simple list. *
* By default, all paths are processed. If you pass an array of wildmatch
* patterns, those will be used to filter which paths should be taken into
* account.
*
* Use GIT_CHECKOUT_DISABLE_PATHSPEC_MATCH to treat as a simple list.
*/ */
git_strarray paths; git_strarray paths;
/** The expected content of the working directory; defaults to HEAD. /**
* If the working directory does not match this baseline information, * The expected content of the working directory; defaults to HEAD.
* that will produce a checkout conflict. *
* If the working directory does not match this baseline information,
* that will produce a checkout conflict.
*/ */
git_tree *baseline; git_tree *baseline;
/** Like `baseline` above, though expressed as an index. This /**
* option overrides `baseline`. * Like `baseline` above, though expressed as an index. This
* option overrides `baseline`.
*/ */
git_index *baseline_index; /**< expected content of workdir, expressed as an index. */ git_index *baseline_index;
const char *target_directory; /**< alternative checkout path to workdir */ const char *target_directory; /**< alternative checkout path to workdir */
@ -290,6 +320,8 @@ typedef struct git_checkout_options {
/** Optional callback to notify the consumer of performance data. */ /** Optional callback to notify the consumer of performance data. */
git_checkout_perfdata_cb perfdata_cb; git_checkout_perfdata_cb perfdata_cb;
/** Payload passed to perfdata_cb */
void *perfdata_payload; void *perfdata_payload;
} git_checkout_options; } git_checkout_options;
@ -306,7 +338,7 @@ typedef struct git_checkout_options {
* @param version The struct version; pass `GIT_CHECKOUT_OPTIONS_VERSION`. * @param version The struct version; pass `GIT_CHECKOUT_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure. * @return Zero on success; -1 on failure.
*/ */
GIT_EXTERN(int) git_checkout_init_options( GIT_EXTERN(int) git_checkout_options_init(
git_checkout_options *opts, git_checkout_options *opts,
unsigned int version); unsigned int version);

View File

@ -46,7 +46,7 @@ typedef struct {
* @param version The struct version; pass `GIT_CHERRYPICK_OPTIONS_VERSION`. * @param version The struct version; pass `GIT_CHERRYPICK_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure. * @return Zero on success; -1 on failure.
*/ */
GIT_EXTERN(int) git_cherrypick_init_options( GIT_EXTERN(int) git_cherrypick_options_init(
git_cherrypick_options *opts, git_cherrypick_options *opts,
unsigned int version); unsigned int version);
@ -59,8 +59,8 @@ GIT_EXTERN(int) git_cherrypick_init_options(
* @param out pointer to store the index result in * @param out pointer to store the index result in
* @param repo the repository that contains the given commits * @param repo the repository that contains the given commits
* @param cherrypick_commit the commit to cherry-pick * @param cherrypick_commit the commit to cherry-pick
* @param our_commit the commit to revert against (eg, HEAD) * @param our_commit the commit to cherry-pick against (eg, HEAD)
* @param mainline the parent of the revert commit, if it is a merge * @param mainline the parent of the `cherrypick_commit`, if it is a merge
* @param merge_options the merge options (or null for defaults) * @param merge_options the merge options (or null for defaults)
* @return zero on success, -1 on failure. * @return zero on success, -1 on failure.
*/ */

View File

@ -97,7 +97,7 @@ typedef int GIT_CALLBACK(git_repository_create_cb)(
* Clone options structure * Clone options structure
* *
* Initialize with `GIT_CLONE_OPTIONS_INIT`. Alternatively, you can * Initialize with `GIT_CLONE_OPTIONS_INIT`. Alternatively, you can
* use `git_clone_init_options`. * use `git_clone_options_init`.
* *
*/ */
typedef struct git_clone_options { typedef struct git_clone_options {
@ -178,7 +178,7 @@ typedef struct git_clone_options {
* @param version The struct version; pass `GIT_CLONE_OPTIONS_VERSION`. * @param version The struct version; pass `GIT_CLONE_OPTIONS_VERSION`.
* @return Zero on success; -1 on failure. * @return Zero on success; -1 on failure.
*/ */
GIT_EXTERN(int) git_clone_init_options( GIT_EXTERN(int) git_clone_options_init(
git_clone_options *opts, git_clone_options *opts,
unsigned int version); unsigned int version);

View File

@ -480,7 +480,8 @@ GIT_EXTERN(int) git_commit_create_buffer(
* *
* @param out the resulting commit id * @param out the resulting commit id
* @param commit_content the content of the unsigned commit object * @param commit_content the content of the unsigned commit object
* @param signature the signature to add to the commit * @param signature the signature to add to the commit. Leave `NULL`
* to create a commit without adding a signature field.
* @param signature_field which header field should contain this * @param signature_field which header field should contain this
* signature. Leave `NULL` for the default of "gpgsig" * signature. Leave `NULL` for the default of "gpgsig"
* @return 0 or an error code * @return 0 or an error code
@ -501,6 +502,27 @@ GIT_EXTERN(int) git_commit_create_with_signature(
*/ */
GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source); GIT_EXTERN(int) git_commit_dup(git_commit **out, git_commit *source);
/**
* Commit signing callback.
*
* The callback will be called with the commit content, giving a user an
* opportunity to sign the commit content. The signature_field
* buf may be left empty to specify the default field "gpgsig".
*
* Signatures can take the form of any string, and can be created on an arbitrary
* header field. Signatures are most commonly used for verifying authorship of a
* commit using GPG or a similar cryptographically secure signing algorithm.
* See https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work for more
* details.
*
* When the callback:
* - returns GIT_PASSTHROUGH, no signature will be added to the commit.
* - returns < 0, commit creation will be aborted.
* - returns GIT_OK, the signature parameter is expected to be filled.
*/
typedef int (*git_commit_signing_cb)(
git_buf *signature, git_buf *signature_field, const char *commit_content, void *payload);
/** @} */ /** @} */
GIT_END_DECL GIT_END_DECL
#endif #endif

Some files were not shown because too many files have changed in this diff Show More