Skip to content

Create LibGit2Sharp.NativeBinaries package #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
*.nupkg
*.dll
*.pdb
*.dylib
*.so
*.zip

# nuget package placeholder
*.here

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an actual file extension?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, at the moment it is. If you look at buildpackage.ps1 I need to create the NuGet package folder structure, including empty folders for the linux and osx binaries, which have to be added later.

I couldn't find a way to actually convince nuget to add an empty folder to the package, so I ended up going with an empty placeholder file called addbinaries.here

I wanted something that would be easy to include in .gitignore, but I'm open to suggestions if my current choice doesn't work. 😄

3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "libgit2"]
path = libgit2
url = https://github.com/libgit2/libgit2.git
19 changes: 19 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
language: c

os:
- osx
- linux

env:
- secure: "oHrjeGkWTUiPLsdYGb4n4lI37EURXVDT1bJ4a4CXfwnFlxXjWF3ixaYqg88o5weT/L/OPhjRdf3GVqmdxPeUYNeF8ImdewcFwJ4C3jLtl2G9CGAP0xVsbyQHxjDi07MHcSbnNorQI0QSEta9bdP6EprNcoEwd/Vi1u14f5g40tk="

before_install:
- date -u
- uname -a
- env | grep -v "BINTRAY_API_KEY" | sort

install: true

script: ./build.libgit2.sh

after_success: ./uploadbinaries.sh
Binary file added NuGet.exe
Binary file not shown.
129 changes: 129 additions & 0 deletions UpdateLibgit2ToSha.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<#
.SYNOPSIS
Updates the libgit2 submodule to the specified commit and updates libgit2_hash.txt and NativeBinaries.props with the new hash value.
.PARAMETER sha
Desired libgit2 version. This is run through `git rev-parse`, so branch names are okay too.
#>

Param(
[string]$sha = 'HEAD'
)

Set-StrictMode -Version Latest

$self = Split-Path -Leaf $MyInvocation.MyCommand.Path
$projectDirectory = Split-Path $MyInvocation.MyCommand.Path
$libgit2Directory = Join-Path $projectDirectory "libgit2"

function Run-Command([scriptblock]$Command, [switch]$Fatal, [switch]$Quiet) {
$output = ""
if ($Quiet) {
$output = & $Command 2>&1
} else {
& $Command
}

if (!$Fatal) {
return
}

$exitCode = 0
if ($LastExitCode -ne 0) {
$exitCode = $LastExitCode
} elseif (!$?) {
$exitCode = 1
} else {
return
}

$error = "``$Command`` failed"
if ($output) {
Write-Host -ForegroundColor yellow $output
$error += ". See output above."
}
Throw $error
}

function Find-Git {
$git = @(Get-Command git)[0] 2>$null
if ($git) {
$git = $git.Definition
Write-Host -ForegroundColor Gray "Using git: $git"
& $git --version | write-host -ForegroundColor Gray
return $git
}
throw "Error: Can't find git"
}

Push-Location $libgit2Directory

& {
trap {
Pop-Location
break
}

$git = Find-Git

Write-Output "Fetching..."
Run-Command -Quiet { & $git fetch }

Write-Output "Verifying $sha..."
$sha = & $git rev-parse $sha
if ($LASTEXITCODE -ne 0) {
write-host -foregroundcolor red "Error: invalid SHA. USAGE: $self <SHA>"
popd
break
}

Write-Output "Checking out $sha..."
Run-Command -Quiet -Fatal { & $git checkout $sha }

Pop-Location

sc -Encoding ASCII (Join-Path $projectDirectory "nuget.package\libgit2\libgit2_hash.txt") $sha

$binaryFilename = "git2-" + $sha.Substring(0,7)

$buildProperties = @"
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<EmbeddedResource Include="`$(MSBuildThisFileDirectory)\..\libgit2\libgit2_hash.txt" />
</ItemGroup>
<ItemGroup Condition=" '`$(OS)' == 'Windows_NT' ">
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\windows\amd64\$binaryFilename.dll">
<Link>NativeBinaries\amd64\$binaryFilename.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\windows\amd64\$binaryFilename.pdb">
<Link>NativeBinaries\amd64\$binaryFilename.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\windows\x86\$binaryFilename.dll">
<Link>NativeBinaries\x86\$binaryFilename.dll</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\windows\x86\$binaryFilename.pdb">
<Link>NativeBinaries\x86\$binaryFilename.pdb</Link>
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup Condition=" '`$(OS)' == 'Unix' And Exists('/Library/Frameworks') ">
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\osx\lib$binaryFilename.dylib">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup Condition=" '`$(OS)' == 'Unix' And !Exists('/Library/Frameworks') ">
<None Include="`$(MSBuildThisFileDirectory)\..\libgit2\linux\amd64\lib$binaryFilename.so">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
"@

sc -Encoding UTF8 (Join-Path $projectDirectory "nuget.package\build\LibGit2Sharp.NativeBinaries.props") $buildProperties

Write-Output "Done!"
}
exit
26 changes: 26 additions & 0 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
version: '{build}'

skip_tags: true

environment:
version : 0.22.0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what we should use here. This should be independent from the LibGit2Sharp version number. However, I don't know how we can provide a meaningful version number that would mean something wrt libgit2


install:
- git submodule update --init --recursive

build_script:
- ps: .\build.libgit2.ps1 -vs 12

after_build:
- ps: |
$pre = $true
if (($env:APPVEYOR_PULL_REQUEST_NUMBER -eq $null) -and ($env:APPVEYOR_REPO_BRANCH -eq "master"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we mostly build unstable version of libgit2, maybe should we always use the "-pre" syntax for naming?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with giving a nuget package a prerelease version is that any packages that depend on it also become prerelease.

If we are trying to version this package to match up with the actual libgit2 versions, then yes we'd probably want these to be -pre most of the time.

However, that would force the LibGit2Sharp package to be prerelease whenever it was using one of the native binary prerelease packages.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmrpf.. I didn't know about this pre-release viral chaining.
How sneaky would it be to use the build timestamp as the patch version (eg. 0.22.20150320121314)?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we could do that, though that does seem to be disregarding any notion of SemVer-style versioning for the package.

Obviously, if we just stuck to the officially versioned releases of libgit2, we could just use their version numbers. However, I'm assuming we want/need to be able to ship any random commit from the libgit2 repo as part of an official, non-prerelease version of the libgit2sharp package?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, we could do that, though that does seem to be disregarding any notion of SemVer-style versioning for the package.

We would still be SemVer compliant. We would however abuse the patch number usage 😉

I'm assuming we want/need to be able to ship any random commit from the libgit2 repo as part of an official, non-prerelease version of the libgit2sharp package?

Indeed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We would still be SemVer compliant. We would however abuse the patch number usage

yeah, that's sort of what I meant. 😄 Using that would definitely not be the intended usage for the patch number!

Regardless, it doesn't look like an option. I gave it a try, and using a value as long as the timestamp appears not to be a valid version number.

If we just want an ever increasing number, maybe we could just use the AppVeyor build number?

One thing to keep in mind with this, if we are making non-prerelease packages and putting them up on nuget.org, then there's a better chance of people seeing that as a newer package and upgrading to it. Of course that would instantly break them since it would have the wrong native binary names, and they could just revert back.

The only other thing I could think would be to make prerelease packages up until we want to push out a new official libgit2sharp package, then you could publish a non-prerelease nativebinaries package as part of that. You could just take the latest package, open it up with Package Explorer, change the version number, and then publish it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about actually using the AppVeyor build number as the major version (eg. 245.0.0)? Shouldn't this prevent the native package from being upgraded by the user?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A larger version number, even if it's a major version will still show up as an upgrade in the NuGet dialog, or if updated from the commandline.

If we want non-prerelease version numbers for the binaries package, then I think I'm going to have to change the LibGit2Sharp nuspec file. Right now I have it automatically including the dependency.

That's useful because the file doesn't need to be updated when the nativebinaries package gets updated, but nuget puts a versioning rule in there that allows for upgraded packages.

I'm going to look and see if there is some way to alter what it includes by default, but if there isn't a way, we could change to explicitly listing the dependency in the nuspec file, and giving it a more restrictive version rule:

http://docs.nuget.org/create/versioning#Specifying-Version-Ranges-in-.nuspec-Files

That won't prevent the "newer" nativebinaries packages from showing up as an upgrade, but it will cause and error when trying to upgrade and stop it from happening.

Seems like the best way forward, but that is likely going to mean there is one more manual step to remember when upgrading the nativebinaries package in the main repo. 😦

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, so it looks like this will be a bit easy to manage then I was originally thinking. Take a look at my latest commit on the main PR. It added an allowedVersions property to the packages.config file, which constrains the version to the one listed in the file.

When the package is built, that same version constraint is used for the native binaries dependency!

That means we can version the native binaries package however we want, and upgrading to a newer version would be prevented, and it only means making a change to a single file (packages.config) to make it all work!

{
$pre = $false
}
.\buildpackage.ps1 $env:VERSION -pre:$pre

test: off

artifacts:
- path: '*.nupkg'
135 changes: 135 additions & 0 deletions build.libgit2.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
<#
.SYNOPSIS
Builds a version of libgit2 and copies it to the nuget packaging directory.
.PARAMETER vs
Version of Visual Studio project files to generate. Cmake supports "10" (default), "11" and "12".
.PARAMETER test
If set, run the libgit2 tests on the desired version.
.PARAMETER debug
If set, build the "Debug" configuration of libgit2, rather than "RelWithDebInfo" (default).
#>

Param(
[string]$vs = '10',
[switch]$test,
[switch]$debug
)

Set-StrictMode -Version Latest

$projectDirectory = Split-Path $MyInvocation.MyCommand.Path
$libgit2Directory = Join-Path $projectDirectory "libgit2"
$x86Directory = Join-Path $projectDirectory "nuget.package\libgit2\windows\x86"
$x64Directory = Join-Path $projectDirectory "nuget.package\libgit2\windows\amd64"
$hashFile = Join-Path $projectDirectory "nuget.package\libgit2\libgit2_hash.txt"
$sha = Get-Content $hashFile
$binaryFilename = "git2-" + $sha.Substring(0,7)

$build_clar = 'OFF'
if ($test.IsPresent) { $build_clar = 'ON' }

$configuration = "RelWithDebInfo"
if ($debug.IsPresent) { $configuration = "Debug" }

function Run-Command([scriptblock]$Command, [switch]$Fatal, [switch]$Quiet) {
$output = ""
if ($Quiet) {
$output = & $Command 2>&1
} else {
& $Command
}

if (!$Fatal) {
return
}

$exitCode = 0
if ($LastExitCode -ne 0) {
$exitCode = $LastExitCode
} elseif (!$?) {
$exitCode = 1
} else {
return
}

$error = "``$Command`` failed"
if ($output) {
Write-Host -ForegroundColor yellow $output
$error += ". See output above."
}
Throw $error
}

function Find-CMake {
# Look for cmake.exe in $Env:PATH.
$cmake = @(Get-Command cmake.exe)[0] 2>$null
if ($cmake) {
$cmake = $cmake.Definition
} else {
# Look for the highest-versioned cmake.exe in its default location.
$cmake = @(Resolve-Path (Join-Path ${Env:ProgramFiles(x86)} "CMake *\bin\cmake.exe"))
if ($cmake) {
$cmake = $cmake[-1].Path
}
}
if (!$cmake) {
throw "Error: Can't find cmake.exe"
}
$cmake
}

function Ensure-Property($expected, $propertyValue, $propertyName, $path) {
if ($propertyValue -eq $expected) {
return
}

throw "Error: Invalid '$propertyName' property in generated '$path' (Expected: $expected - Actual: $propertyValue)"
}

function Assert-Consistent-Naming($expected, $path) {
$dll = get-item $path

Ensure-Property $expected $dll.Name "Name" $dll.Fullname
Ensure-Property $expected $dll.VersionInfo.InternalName "VersionInfo.InternalName" $dll.Fullname
Ensure-Property $expected $dll.VersionInfo.OriginalFilename "VersionInfo.OriginalFilename" $dll.Fullname
}

try {
Push-Location $libgit2Directory

$cmake = Find-CMake
$ctest = Join-Path (Split-Path -Parent $cmake) "ctest.exe"

Write-Output "Building 32-bit..."
Run-Command -Quiet { & remove-item build -recurse -force }
Run-Command -Quiet { & mkdir build }
cd build
Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs" -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON .. }
Run-Command -Quiet -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
Assert-Consistent-Naming "$binaryFilename.dll" "*.dll"
Run-Command -Quiet { & rm *.exp }
Run-Command -Quiet { & rm $x86Directory\* }
Run-Command -Quiet { & mkdir -fo $x86Directory }
Run-Command -Quiet -Fatal { & copy -fo * $x86Directory -Exclude *.lib }

Write-Output "Building 64-bit..."
cd ..
Run-Command -Quiet { & mkdir build64 }
cd build64
Run-Command -Quiet -Fatal { & $cmake -G "Visual Studio $vs Win64" -D THREADSAFE=ON -D ENABLE_TRACE=ON -D "BUILD_CLAR=$build_clar" -D "LIBGIT2_FILENAME=$binaryFilename" -DSTDCALL=ON ../.. }
Run-Command -Quiet -Fatal { & $cmake --build . --config $configuration }
if ($test.IsPresent) { Run-Command -Quiet -Fatal { & $ctest -V . } }
cd $configuration
Assert-Consistent-Naming "$binaryFilename.dll" "*.dll"
Run-Command -Quiet { & rm *.exp }
Run-Command -Quiet { & rm $x64Directory\* }
Run-Command -Quiet { & mkdir -fo $x64Directory }
Run-Command -Quiet -Fatal { & copy -fo * $x64Directory -Exclude *.lib }

Write-Output "Done!"
}
finally {
Pop-Location
}
46 changes: 46 additions & 0 deletions build.libgit2.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash

LIBGIT2SHA=`cat ./nuget.package/libgit2/libgit2_hash.txt`
SHORTSHA=${LIBGIT2SHA:0:7}

rm -rf libgit2/build
mkdir libgit2/build
pushd libgit2/build

export _BINPATH=`pwd`

cmake -DCMAKE_BUILD_TYPE:STRING=Release \
-DBUILD_CLAR:BOOL=OFF \
-DUSE_SSH=OFF \
-DENABLE_TRACE=ON \
-DLIBGIT2_FILENAME=git2-$SHORTSHA \
-DCMAKE_OSX_ARCHITECTURES="i386;x86_64" \
..
cmake --build .

popd

OS=`uname`
ARCH=`uname -m`

PACKAGEPATH="nuget.package/libgit2"
LIBEXT="so"

if [ $OS == "Linux" ]; then
OSPATH="/linux"
if [ $ARCH == "x86_64" ]; then
ARCHPATH="/amd64"
fi
elif [ $OS == "Darwin" ]; then
OSPATH="/osx"
LIBEXT="dylib"
else
OSPATH="/unix"
fi

rm -rf $PACKAGEPATH$OSPATH
mkdir -p $PACKAGEPATH$OSPATH$ARCHPATH

cp libgit2/build/libgit2-$SHORTSHA.$LIBEXT $PACKAGEPATH$OSPATH$ARCHPATH

exit $?
Loading