diff --git a/.gitmodules b/.gitmodules index d20b45000..007c6113b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "vendor/libgit2"] path = vendor/libgit2 url = git://github.com/libgit2/libgit2.git +[submodule "example/stress/jquery"] + path = example/stress/jquery + url = https://github.com/jquery/jquery.git diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md deleted file mode 100644 index 07a409052..000000000 --- a/CONTRIBUTORS.md +++ /dev/null @@ -1,22 +0,0 @@ -nodegit2 contributors (sorted alphabeticaly) -============================================ -* **[Ben Alman](https://github.com/cowboy)** - - * JS API suggestions - -* **[inimino](https://github.com/inimino)** - - * JS API suggestions - -* **[Rick Waldron](https://github.com/rwldrn)** - - * JS API suggestions - -* **[Tim Branyen](https://github.com/tbranyen)** - - * Project creator - -* **[Timothy J Fontaine](https://github.com/tjfontaine)** - - * Created influencial base project - * Provided numerous tips and suggestions diff --git a/Makefile b/Makefile index 8680c6a8e..e43af0a40 100644 --- a/Makefile +++ b/Makefile @@ -17,6 +17,9 @@ config: build: @@$(NODE_BLD) build +debug: + @@$(NODE_BLD) debug + install: @@mkdir -p $(INSTALL_PATH) @@mkdir -p $(INSTALL_PATH)/build/default diff --git a/README.md b/README.md index ca83b4fd5..5f1ee04a8 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ This will install and configure everything you need to use `nodegit`. $ sudo npm install nodegit +To update an existing installation, run + $ sudo npm update nodegit ### Mac OS X/Linux/Unix ### @@ -66,7 +68,8 @@ API Example Usage // Iterate over the revision history var history = branch.history(); - history.on( 'commit', function( err, commit ) { + // Commit event is emitted with index 0,n... and commit object + history.on( 'commit', function( idx, commit ) { // Print out `git log` emulation console.log( 'commit ' + commit.sha ); console.log( commit.author.name + '<' + commit.author.email + '>' ); @@ -196,6 +199,11 @@ Release information __Can keep track of current method coverage at: [http://bit.ly/tb_methods](http://bit.ly/tb_methods)__ +### v0.0.4: ### + * Many fixes! + * Blob raw write supported added, no convenience methods yet... + * Updated libgit2 to version 0.12.0 + ### v0.0.3: ### * More documented native source code * Updated convenience api code diff --git a/example/apps/git_profanity_check.js b/example/apps/git_profanity_check.js new file mode 100644 index 000000000..3031f4186 --- /dev/null +++ b/example/apps/git_profanity_check.js @@ -0,0 +1,54 @@ +#!/usr/bin/env node + +// Copyright 2011, Tim Branyen @tbranyen +// Dual licensed under the MIT and GPL licenses. +// Script to detect cursewords in commit messages and provide the +// offending commit sha's. +// vim: ft=javascript +var git = require( 'nodegit' ); + +var curses = [ 'add', 'swears', 'here' ] + , path = './.git' + , branch = 'master' + , reCurse = new RegExp('\\b(?:' + curses.join('|') + ')\\b', 'gi'); + + +// Set git path +if ( process.argv.length < 3 ) { + console.log( 'No path passed as argument, defaulting to ./.git' ); +} +else { + path = process.argv[2]; + + // Set repo branch + if ( process.argv.length < 4 ) { + console.log( 'No branch passed as argument, defaulting to master' ); + } + else { + branch = process.argv[3]; + } +} + +// Open repository +git.repo( path, function( err, repo ) { + if ( err ) { + throw new Error( err ); + } + + // Open branch + repo.branch( branch, function( err, branch ) { + if ( err ) { + throw new Error( err ); + } + + // Iterate history + var history = branch.history(); + history.on( 'commit', function( idx, commit ) { + // Check commit messages first + if ( reCurse.test(commit.message) ) { + console.log( 'Curse detected in commit', commit.sha, 'message' ); + return; + } + }); + }); +}); diff --git a/example/convenience-repo.js b/example/convenience-repo.js index 9794bb784..e641fe880 100644 --- a/example/convenience-repo.js +++ b/example/convenience-repo.js @@ -8,7 +8,7 @@ git.repo( '../.git', function( err, repo ) { repo.branch( 'master', function( err, branch ) { if( err ) { throw err; } // Iterate over the revision history - branch.history.each( function( i, commit ) { + branch.history().on( 'commit', function( err, commit ) { // Print out `git log` emulation console.log( 'commit ' + commit.sha ); console.log( commit.author.name + ' <' + commit.author.email + '>' ); diff --git a/example/convenience-tree.js b/example/convenience-tree.js index fa8ba24df..bcdf7ef5d 100644 --- a/example/convenience-tree.js +++ b/example/convenience-tree.js @@ -6,10 +6,9 @@ git.repo( '../.git', function( err, repo ) { repo.branch( 'master', function( err, branch ) { if( err ) { throw err; } - branch.tree().each( function( i, entry ) { + branch.tree().walk( function( idx, entry ) { console.log( entry.name ); - console.log( entry.contents ); - + console.log( entry.content ); }); }); }); diff --git a/example/readme-example.js b/example/readme-example.js new file mode 100644 index 000000000..6ca62d8ca --- /dev/null +++ b/example/readme-example.js @@ -0,0 +1,14 @@ +var git = require( 'nodegit' ); + +git.repo( 'jquery/.git', function() { + console.log( 'Repo opened' ); + + this.branch( 'master', function() { + console.log( 'Branch opened' ); + + this.history().on( 'commit', function( i, commit ) { + console.log( commit.id.toString(40) ); + }); + + }); +}); diff --git a/example/stress/commit.js b/example/stress/commit.js index c067c9e80..d1dd0b2a6 100644 --- a/example/stress/commit.js +++ b/example/stress/commit.js @@ -8,10 +8,10 @@ var git = require( '../../' ).raw; var start = new Date; var repo = new git.Repo(); - repo.open( '/home/tim/git/nodegit/.git', function() { + repo.open( 'jquery/.git', function() { var commit = new git.Commit(); - console.log( 'Time taken: ' + (+new Date-start) + 'ms' ); + //console.log( 'Time taken: ' + (+new Date-start) + 'ms' ); }); })(); @@ -27,13 +27,13 @@ var git = require( '../../' ).raw; var start = new Date; var repo = new git.Repo(); - repo.open( '/home/tim/git/nodegit/.git', function() { + repo.open( 'jquery/.git', function() { var oid = new git.Oid(); - oid.mkstr( 'cb76e3c030ab29db332aff3b297dc39451a84762' ); + oid.mkstr( 'cf702496ee28830f3488ed3f1c3940cfbb2dfa8f' ); var commit = new git.Commit(); commit.lookup( repo, oid, function( err ) { - console.log( 'Time taken: ' + (+new Date-start) + 'ms' ); + //console.log( 'Time taken: ' + (+new Date-start) + 'ms' ); }); }); diff --git a/example/stress/jquery b/example/stress/jquery new file mode 160000 index 000000000..cf702496e --- /dev/null +++ b/example/stress/jquery @@ -0,0 +1 @@ +Subproject commit cf702496ee28830f3488ed3f1c3940cfbb2dfa8f diff --git a/example/stress/repo.js b/example/stress/repo.js index f016ed6cb..d32ed765a 100644 --- a/example/stress/repo.js +++ b/example/stress/repo.js @@ -23,7 +23,7 @@ var git = require( 'nodegit' ).raw; (function() { var start = new Date; var repo = new git.Repo(); - repo.open( '/home/tim/git/nodegit/.git', function() { + repo.open( 'jquery/.git', function() { //console.log( 'Time taken: ' + (+new Date-start) + 'ms' ); }); diff --git a/example/stress/revwalk.js b/example/stress/revwalk.js index 81a57c281..081f59832 100644 --- a/example/stress/revwalk.js +++ b/example/stress/revwalk.js @@ -1,37 +1,58 @@ -var git = require( '../../' ).raw; +//var git = require( '../../' ).raw; +var git = require( 'nodegit' ); + //* Stress test revision walking - setInterval(function() { + //setInterval(function() { for(var i=0; i<10000; i++) { (function() { - var start = new Date; - - var repo = new git.Repo(); - repo.open( '/home/tim/git/nodegit/.git', function() { - var oid = new git.Oid(); - oid.mkstr( 'cb76e3c030ab29db332aff3b297dc39451a84762' ); - - var commit = new git.Commit( repo ); - commit.lookup( repo, oid, function( err ) { - var revwalk = new git.RevWalk( repo ); - revwalk.push( commit ); - - function walk() { - var oid = new git.Oid(); - revwalk.next( oid, function( err ) { - if( !err ) { - walk(); - } - }); - } - - walk(); - } ); + + git.repo( 'jquery/.git', function() { + //console.log( 'Repo opened' ); + + this.branch( 'master', function() { + this.history().on( 'commit', function( i, commit ) { + //console.log( commit.id.toString(40) ); + }); + }); }); + //var repo = new git.Repo(); + //repo.open( 'jquery/.git', function( err ) { + + // var commit = new git.Commit( repo ) + // , ref = new git.Ref( repo ); + + // ref.lookup( repo, '/refs/heads/master', function( err ) { + // if( err ) { throw new Error( err ); } + + // var oid = new git.Oid(); + // ref.oid( oid ); + + + //commit.lookup( repo, oid, function( err ) { + + // var revwalk = new git.RevWalk( repo ); + // revwalk.push( commit ); + + // function walk() { + // var _oid = new git.Oid(); + // revwalk.next( _oid, function( err ) { + // if( !err ) { + // walk(); + // } + // }); + // } + + // walk(); + + //}); + // }); + //}); + })(); } - }, 0); + //}, 0); //*/ diff --git a/include/blob.h b/include/blob.h index 60354168a..5e7243c7b 100755 --- a/include/blob.h +++ b/include/blob.h @@ -8,7 +8,6 @@ #include #include -#include #include "../vendor/libgit2/include/git2.h" @@ -98,7 +97,7 @@ class GitBlob : public ObjectWrap { * Returns: * 0 on success, error code otherwise */ - int CreateFromFile(git_oid* oid, git_repository* repo, const void* buffer, size_t len); + int CreateFromBuffer(git_oid* oid, git_repository* repo, const void* buffer, size_t len); protected: /** diff --git a/include/oid.h b/include/oid.h index 513e362e4..6fd23c937 100755 --- a/include/oid.h +++ b/include/oid.h @@ -24,7 +24,7 @@ class GitOid : public EventEmitter { int Mkstr(const char* str); void Mkraw(const unsigned char* raw); - char* Fmt(char* buffer); + void Fmt(char* buffer); void PathFmt(char *str); char* AllocFmt(); char* ToString(char* buffer, size_t bufferSize); diff --git a/include/tree_entry.h b/include/tree_entry.h index 3d7379bfd..cc871ad7b 100755 --- a/include/tree_entry.h +++ b/include/tree_entry.h @@ -50,12 +50,14 @@ class GitTreeEntry : EventEmitter { */ void SetValue(git_tree_entry* tree); const char* Name(); + int Attributes(); const git_oid* Id(); int ToObject(git_repository* repo, git_object** obj); protected: static Handle New(const Arguments& args); static Handle Name(const Arguments& args); + static Handle Attributes(const Arguments& args); static Handle Id(const Arguments& args); static Handle ToObject(const Arguments& args); diff --git a/lib/index.js b/lib/index.js index 1c2bc17c6..90028ae8e 100755 --- a/lib/index.js +++ b/lib/index.js @@ -8,7 +8,7 @@ var util = require( './util.js' ).util, error = require( './error.js' ).error, sig = require( './sig.js' ).sig, oid = require( './oid.js' ).oid, - obj = require( './obj.js' ).obj, + object = require( './object.js' ).object, ref = require( './ref.js' ).ref, revwalk = require( './revwalk.js' ).revwalk, commit = require( './commit.js' ).commit, @@ -30,7 +30,7 @@ exports.util = util; exports.repo = repo; exports.ref = ref; exports.oid = oid; -exports.obj = obj; +exports.object = object; exports.sig = sig; exports.error = error; exports.revwalk = revwalk; diff --git a/lib/obj.js b/lib/object.js similarity index 65% rename from lib/obj.js rename to lib/object.js index 163b02600..1c99d9fa7 100644 --- a/lib/obj.js +++ b/lib/object.js @@ -3,11 +3,11 @@ var git = require( '../' ); var _Object = function( obj ) { var self = {}; - if( obj instanceof git.raw.Object ) { - self.obj = obj; + if( object instanceof git.raw.Object ) { + self.object = obj; } else { - self.obj = new git.raw.Object(); + self.object = new git.raw.Object(); } Object.defineProperty( self, 'id', { @@ -18,21 +18,21 @@ var _Object = function( obj ) { Object.defineProperty( self, 'type', { get: function() { - return self.obj.type(); + return self.object.type(); }, enumerable: true }); Object.defineProperty( self, 'length', { get: function() { - return self.obj.size(); + return self.object.size(); }, enumerable: true }); Object.defineProperty( self, 'isLoose', { get: function() { - return self.obj.typeIsLoose(); + return self.object.typeIsLoose(); }, enumerable: true }); @@ -40,7 +40,7 @@ var _Object = function( obj ) { self.id = function() { var oid = git.oid(); - self.obj.id( oid.oid ); + self.object.id( oid.oid ); return oid; }; @@ -48,24 +48,24 @@ var _Object = function( obj ) { self.owner = function() { var repo = git.repo(); - self.obj.owner( repo.repo ); + self.object.owner( repo.repo ); return repo; }; self.toString = function() { - return self.obj.type2String(); + return self.object.type2String(); }; self.toType = function( type ) { - return self.obj.toType( type ); + return self.object.toType( type ); }; self.free = function() { - return self.obj.free(); + return self.object.free(); }; return self; }; -exports.obj = _Object; +exports.object = _Object; diff --git a/lib/repo.js b/lib/repo.js index 6cfc0d0d1..785bef8b8 100644 --- a/lib/repo.js +++ b/lib/repo.js @@ -34,7 +34,7 @@ var _Repo = function( dir, callback ) { callback.apply( this, args.concat( this ) ); } - git.commit( self.repo ).lookup( ref.oid().oid, function() { + git.commit( self.repo ).lookup( self.repo, ref.oid().oid, function() { var args = Array.prototype.slice.call( arguments ); args[0] = git.util().error( args[0] ); diff --git a/lib/tree_entry.js b/lib/tree_entry.js index 36c8542d9..4b67289b7 100644 --- a/lib/tree_entry.js +++ b/lib/tree_entry.js @@ -18,17 +18,43 @@ var _TreeEntry = function( obj ) { enumerable: true }); + Object.defineProperty( self, 'attributes', { + get: function() { + return self.entry.attributes(); + }, + enumerable: true + }); + + Object.defineProperty( self, 'object', { + get: function() { + return self.entry.toObject(); + }, + enumerable: true + }); + Object.defineProperty( self, 'content', { get: function() { - var blob = git.blob( self.repo ); + if( self.isFile() ) { + var blob = git.blob( self.repo ); - self.entry.toObject( self.repo, blob.blob ); + self.entry.toObject( self.repo, blob.blob ); - return blob.raw; + return blob.raw; + } + + return null; }, enumerable: true }); + self.isFile = function() { + return self.attributes === 33188; + }; + + self.isDir = function() { + return self.attributes === 16384; + }; + return self; }; diff --git a/package.json b/package.json index 9853a8222..8b697f1db 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nodegit", - "description": "NodeJS libgit2 asynchronous native bindings", - "version": "0.0.3", + "description": "Node.js libgit2 asynchronous native bindings", + "version": "0.0.4", "homepage": "https://github.com/tbranyen/nodegit", "author": "Tim Branyen (http://twitter.com/tbranyen)", "main": "./lib/index.js", diff --git a/src/blob.cc b/src/blob.cc index 906bcac3e..7b32c44a0 100755 --- a/src/blob.cc +++ b/src/blob.cc @@ -5,7 +5,6 @@ #include #include -#include #include #include @@ -60,21 +59,29 @@ void GitBlob::Close() { git_blob_close(this->blob); } +int CreateFromFile(git_oid* oid, git_repository* repo, const char* path) { + return git_blob_create_fromfile(oid, repo, path); +} + +int CreateFromBuffer(git_oid* oid, git_repository* repo, const void* buffer, size_t len) { + return git_blob_create_frombuffer(oid, repo, buffer, len); +} + Handle GitBlob::New(const Arguments& args) { HandleScope scope; GitBlob* blob = new GitBlob(); blob->Wrap(args.This()); - return scope.Close(args.This()); + return scope.Close( args.This() ); } Handle GitBlob::Lookup(const Arguments& args) { + HandleScope scope; + GitBlob* blob = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); } @@ -100,7 +107,7 @@ Handle GitBlob::Lookup(const Arguments& args) { eio_custom(EIO_Lookup, EIO_PRI_DEFAULT, EIO_AfterLookup, ar); ev_ref(EV_DEFAULT_UC); - return scope.Close(Undefined()); + return scope.Close( Undefined() ); } int GitBlob::EIO_Lookup(eio_req* req) { @@ -113,8 +120,6 @@ int GitBlob::EIO_Lookup(eio_req* req) { } int GitBlob::EIO_AfterLookup(eio_req* req) { - HandleScope scope; - lookup_request* ar = static_cast(req->data); ev_unref(EV_DEFAULT_UC); ar->blob->Unref(); @@ -137,45 +142,92 @@ int GitBlob::EIO_AfterLookup(eio_req* req) { } Handle GitBlob::RawContent(const Arguments& args) { - GitBlob* blob = ObjectWrap::Unwrap(args.This()); + HandleScope scope; - //if(args.Length() == 0 || !args[0]->IsObject()) { - // return ThrowException(Exception::Error(String::New("Buffer is required and must be an Object."))); - //} + GitBlob* blob = ObjectWrap::Unwrap(args.This()); int rawSize = blob->RawSize(); const char* contents = (const char *)const_cast(blob->RawContent()); - Buffer* buffer = Buffer::New(const_cast(contents), rawSize); - return buffer->handle_; + Buffer* buffer = Buffer::New(const_cast(contents), strlen(contents)); + + return scope.Close( buffer->handle_ ); } Handle GitBlob::RawSize(const Arguments& args) { + HandleScope scope; + GitBlob* blob = ObjectWrap::Unwrap(args.This()); - return Integer::New(blob->RawSize()); + return scope.Close( Integer::New(blob->RawSize()) ); } Handle GitBlob::Close(const Arguments& args) { + HandleScope scope; + GitBlob* blob = ObjectWrap::Unwrap(args.This()); blob->Close(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitBlob::CreateFromFile(const Arguments& args) { + HandleScope scope; + GitBlob* blob = ObjectWrap::Unwrap(args.This()); - blob->Close(); + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); + } - return Undefined(); + if(args.Length() == 1 || !args[1]->IsObject()) { + return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); + } + + if(args.Length() == 2 || !args[2]->IsString()) { + return ThrowException(Exception::Error(String::New("Path is required and must be an String."))); + } + + GitOid* oid = ObjectWrap::Unwrap(args[0]->ToObject()); + GitRepo* repo = ObjectWrap::Unwrap(args[1]->ToObject()); + + String::Utf8Value path(args[2]); + + git_oid tmp_oid = oid->GetValue(); + int err = blob->CreateFromFile(&tmp_oid, repo->GetValue(), *path); + + return scope.Close( Integer::New(err) ); } Handle GitBlob::CreateFromBuffer(const Arguments& args) { + HandleScope scope; + GitBlob* blob = ObjectWrap::Unwrap(args.This()); - return Undefined(); + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); + } + + if(args.Length() == 1 || !args[1]->IsObject()) { + return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); + } + + if(args.Length() == 2 || !Buffer::HasInstance(args[2])) { + return ThrowException(Exception::Error(String::New("Buffer is required and must be a Buffer."))); + } + + GitOid* oid = ObjectWrap::Unwrap(args[0]->ToObject()); + GitRepo* repo = ObjectWrap::Unwrap(args[1]->ToObject()); + Local buffer = args[2]->ToObject(); + + const void* data = Buffer::Data(buffer); + size_t length = Buffer::Length(buffer); + + git_oid tmp_oid = oid->GetValue(); + int err = blob->CreateFromBuffer(&tmp_oid, repo->GetValue(), data, length); + + return scope.Close( Integer::New(err) ); } Persistent GitBlob::constructor_template; diff --git a/src/commit.cc b/src/commit.cc index 8985cd71e..39009a214 100755 --- a/src/commit.cc +++ b/src/commit.cc @@ -143,7 +143,7 @@ Handle GitCommit::Lookup(const Arguments& args) { eio_custom(EIO_Lookup, EIO_PRI_DEFAULT, EIO_AfterLookup, ar); ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitCommit::EIO_Lookup(eio_req *req) { @@ -185,7 +185,7 @@ Handle GitCommit::Close(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); commit->Close(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitCommit::Id(const Arguments& args) { @@ -201,7 +201,7 @@ Handle GitCommit::Id(const Arguments& args) { oid->SetValue(*const_cast(commit->Id())); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitCommit::MessageShort(const Arguments& args) { @@ -209,7 +209,7 @@ Handle GitCommit::MessageShort(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); - return String::New(commit->MessageShort()); + return scope.Close( String::New(commit->MessageShort()) ); } Handle GitCommit::Message(const Arguments& args) { @@ -217,7 +217,7 @@ Handle GitCommit::Message(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); - return String::New(commit->Message()); + return scope.Close( String::New(commit->Message()) ); } Handle GitCommit::Time(const Arguments& args) { @@ -225,7 +225,7 @@ Handle GitCommit::Time(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); - return Integer::New(commit->Time()); + return scope.Close( Integer::New(commit->Time()) ); } Handle GitCommit::TimeOffset(const Arguments& args) { @@ -233,7 +233,7 @@ Handle GitCommit::TimeOffset(const Arguments& args) { GitCommit *commit = ObjectWrap::Unwrap(args.This()); - return Integer::New(commit->TimeOffset()); + return scope.Close( Integer::New(commit->TimeOffset()) ); } Handle GitCommit::Committer(const Arguments& args) { @@ -249,7 +249,7 @@ Handle GitCommit::Committer(const Arguments& args) { sig->SetValue(const_cast(commit->Committer())); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitCommit::Author(const Arguments& args) { @@ -265,7 +265,7 @@ Handle GitCommit::Author(const Arguments& args) { sig->SetValue(const_cast(commit->Author())); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitCommit::Tree(const Arguments& args) { @@ -283,7 +283,7 @@ Handle GitCommit::Tree(const Arguments& args) { int err = commit->Tree(&tree); g_tree->SetValue(tree); - return scope.Close(Integer::New(err)); + return scope.Close( Integer::New(err) ); } Handle GitCommit::ParentCount(const Arguments& args) { @@ -293,7 +293,7 @@ Handle GitCommit::ParentCount(const Arguments& args) { unsigned int count = commit->ParentCount(); - return Integer::New(count); + return scope.Close( Integer::New(count) ); } Handle GitCommit::Parent(const Arguments& args) { @@ -316,7 +316,7 @@ Handle GitCommit::Parent(const Arguments& args) { int err = commit->Parent(&in, index); out->SetValue(in); - return Integer::New(err); + return scope.Close( Integer::New(err) ); } Persistent GitCommit::constructor_template; diff --git a/src/error.cc b/src/error.cc index f4d86eba1..011beb22d 100755 --- a/src/error.cc +++ b/src/error.cc @@ -38,21 +38,21 @@ Handle GitError::New(const Arguments& args) { GitError *error = new GitError(); error->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitError::StrError(const Arguments& args) { - GitError* error = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + GitError* error = ObjectWrap::Unwrap(args.This()); + if(args.Length() == 0 || !args[0]->IsNumber()) { return ThrowException(Exception::Error(String::New("Error is required and must be a Number."))); } Local err = Local::Cast(args[0]); - return String::New(error->StrError(err->Value())); + return scope.Close( String::New(error->StrError(err->Value())) ); } Persistent GitError::constructor_template; diff --git a/src/object.cc b/src/object.cc index 9be703aa5..a0b43d54f 100755 --- a/src/object.cc +++ b/src/object.cc @@ -93,7 +93,7 @@ Handle GitObject::New(const Arguments& args) { obj->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitObject::Id(const Arguments& args) { @@ -109,7 +109,7 @@ Handle GitObject::Id(const Arguments& args) { oid->SetValue(*const_cast(obj->Id())); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitObject::Type(const Arguments& args) { @@ -117,7 +117,7 @@ Handle GitObject::Type(const Arguments& args) { GitObject *obj = ObjectWrap::Unwrap(args.This()); - return Integer::New(obj->Type()); + return scope.Close( Integer::New(obj->Type()) ); } Handle GitObject::Owner(const Arguments& args) { @@ -133,7 +133,7 @@ Handle GitObject::Owner(const Arguments& args) { repo->SetValue(obj->Owner()); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitObject::Type2String(const Arguments& args) { @@ -147,7 +147,7 @@ Handle GitObject::Type2String(const Arguments& args) { git_otype type = (git_otype)args[0]->ToInteger()->Value(); - return String::New(obj->Type2String(type)); + return scope.Close( String::New(obj->Type2String(type)) ); } Handle GitObject::String2Type(const Arguments& args) { @@ -161,7 +161,7 @@ Handle GitObject::String2Type(const Arguments& args) { String::Utf8Value type(args[0]); - return Integer::New(obj->String2Type(*type)); + return scope.Close( Integer::New(obj->String2Type(*type)) ); } Handle GitObject::TypeIsLoose(const Arguments& args) { @@ -175,7 +175,7 @@ Handle GitObject::TypeIsLoose(const Arguments& args) { git_otype type = (git_otype)args[0]->ToInteger()->Value(); - return Integer::New(obj->TypeIsLoose(type)); + return scope.Close( Integer::New(obj->TypeIsLoose(type)) ); } Handle GitObject::Size(const Arguments& args) { @@ -189,7 +189,7 @@ Handle GitObject::Size(const Arguments& args) { git_otype type = (git_otype)args[0]->ToInteger()->Value(); - return Integer::New(obj->Size(type)); + return scope.Close( Integer::New(obj->Size(type)) ); } Persistent GitObject::constructor_template; diff --git a/src/oid.cc b/src/oid.cc index c0296bbe7..572cd5f44 100755 --- a/src/oid.cc +++ b/src/oid.cc @@ -50,7 +50,7 @@ void GitOid::Mkraw(const unsigned char* raw) { git_oid_mkraw(&this->oid, raw); } -char* GitOid::Fmt(char* buffer) { +void GitOid::Fmt(char* buffer) { git_oid_fmt(buffer, &this->oid); } @@ -98,52 +98,54 @@ Handle GitOid::Mkstr(const Arguments& args) { } Handle GitOid::Mkraw(const Arguments& args) { - GitOid* oid = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + GitOid* oid = ObjectWrap::Unwrap(args.This()); + if(args.Length() == 0 || !args[0]->IsString()) { return ThrowException(Exception::Error(String::New("Raw object id is required."))); } - String::Utf8Value raw(Local::New(args[0])); + String::Utf8Value raw(args[0]); oid->Mkraw((const unsigned char*)*raw); - return Local::New(args.This()); + return scope.Close( args.This() ); } Handle GitOid::Fmt(const Arguments& args) { - GitOid *oid = ObjectWrap::Unwrap(args.This()); - HandleScope scope; - char buffer[32]; + GitOid *oid = ObjectWrap::Unwrap(args.This()); + + char buffer[40]; oid->Fmt(buffer); - return String::New(buffer); + + return scope.Close( String::New(buffer) ); } Handle GitOid::PathFmt(const Arguments& args) { - GitOid *oid = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + GitOid *oid = ObjectWrap::Unwrap(args.This()); + char buffer[41]; oid->PathFmt(buffer); - return String::New(buffer); + + return scope.Close( String::New(buffer) ); } Handle GitOid::AllocFmt(const Arguments& args) { - GitOid *oid = ObjectWrap::Unwrap(args.This()); - HandleScope scope; - return String::New(oid->AllocFmt()); + GitOid *oid = ObjectWrap::Unwrap(args.This()); + + return scope.Close( String::New(oid->AllocFmt()) ); } Handle GitOid::ToString(const Arguments& args) { - GitOid *oid = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + + GitOid *oid = ObjectWrap::Unwrap(args.This()); if(args.Length() == 0 || !args[0]->IsNumber()) { return ThrowException(Exception::Error(String::New("Length argument is required and must be a Number."))); @@ -151,7 +153,8 @@ Handle GitOid::ToString(const Arguments& args) { char buffer[Int32::Cast(*args[0])->Value()+1]; oid->ToString(buffer, sizeof(buffer)); - return String::New(buffer); + + return scope.Close( String::New(buffer) ); } Handle GitOid::Cpy(const Arguments& args) { @@ -169,7 +172,7 @@ Handle GitOid::Cpy(const Arguments& args) { oid->Cpy(out); clone->SetValue(*out); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitOid::Cmp(const Arguments& args) { @@ -191,6 +194,6 @@ Handle GitOid::Cmp(const Arguments& args) { //int cmp = oid->Cmp(&a->GetValue(), &b->GetValue()); int cmp = 0; - return Integer::New(cmp); + return scope.Close( Integer::New(cmp) ); } Persistent GitOid::constructor_template; diff --git a/src/reference.cc b/src/reference.cc index 38a10ca2a..ab37f871f 100755 --- a/src/reference.cc +++ b/src/reference.cc @@ -44,7 +44,7 @@ int GitReference::Lookup(git_repository* repo, const char* name) { } const git_oid* GitReference::Oid() { - return git_reference_oid(*&this->ref); + return git_reference_oid(this->ref); } Handle GitReference::New(const Arguments& args) { @@ -58,11 +58,11 @@ Handle GitReference::New(const Arguments& args) { } Handle GitReference::Lookup(const Arguments& args) { + HandleScope scope; + GitReference *ref = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Repo is required and must be a Object."))); } @@ -91,7 +91,7 @@ Handle GitReference::Lookup(const Arguments& args) { eio_custom(EIO_Lookup, EIO_PRI_DEFAULT, EIO_AfterLookup, ar); ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitReference::EIO_Lookup(eio_req *req) { @@ -129,16 +129,18 @@ int GitReference::EIO_AfterLookup(eio_req *req) { } Handle GitReference::Oid(const Arguments& args) { - GitReference *ref = ObjectWrap::Unwrap(args.This()); HandleScope scope; + GitReference *ref = ObjectWrap::Unwrap(args.This()); + if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); } GitOid *oid = ObjectWrap::Unwrap(args[0]->ToObject()); - oid->SetValue(*const_cast(ref->Oid())); + git_oid* in = const_cast(ref->Oid()); + oid->SetValue(*in); - return Undefined(); + return scope.Close( Undefined() ); } Persistent GitReference::constructor_template; diff --git a/src/repo.cc b/src/repo.cc index 98fcab173..d288ef612 100755 --- a/src/repo.cc +++ b/src/repo.cc @@ -66,15 +66,15 @@ Handle GitRepo::New(const Arguments& args) { GitRepo *repo = new GitRepo(); repo->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitRepo::Open(const Arguments& args) { + HandleScope scope; + GitRepo *repo = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsString()) { return ThrowException(Exception::Error(String::New("Path is required and must be a String."))); } @@ -98,7 +98,7 @@ Handle GitRepo::Open(const Arguments& args) { eio_custom(EIO_Open, EIO_PRI_DEFAULT, EIO_AfterOpen, ar); ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitRepo::EIO_Open(eio_req *req) { @@ -134,11 +134,11 @@ int GitRepo::EIO_AfterOpen(eio_req *req) { } Handle GitRepo::Lookup(const Arguments& args) { + HandleScope scope; + GitRepo *repo = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Object is required and must be a Object."))); } @@ -166,7 +166,7 @@ Handle GitRepo::Lookup(const Arguments& args) { //eio_custom(EIO_LookupRef, EIO_PRI_DEFAULT, EIO_AfterLookupRef, ar); //ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitRepo::EIO_Lookup(eio_req *req) { @@ -212,21 +212,21 @@ int GitRepo::EIO_AfterLookup(eio_req *req) { } Handle GitRepo::Free(const Arguments& args) { - GitRepo *repo = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + GitRepo *repo = ObjectWrap::Unwrap(args.This()); + repo->Free(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitRepo::Init(const Arguments& args) { + HandleScope scope; + GitRepo *repo = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsString()) { return ThrowException(Exception::Error(String::New("path is required and must be a String."))); } @@ -255,7 +255,7 @@ Handle GitRepo::Init(const Arguments& args) { eio_custom(EIO_Init, EIO_PRI_DEFAULT, EIO_AfterInit, ar); ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitRepo::EIO_Init(eio_req *req) { diff --git a/src/revwalk.cc b/src/revwalk.cc index a7b0d5f38..a010f2e19 100755 --- a/src/revwalk.cc +++ b/src/revwalk.cc @@ -95,7 +95,7 @@ Handle GitRevWalk::New(const Arguments& args) { revwalk->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitRevWalk::Reset(const Arguments& args) { @@ -105,7 +105,7 @@ Handle GitRevWalk::Reset(const Arguments& args) { revwalk->Reset(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitRevWalk::Push(const Arguments& args) { @@ -121,15 +121,15 @@ Handle GitRevWalk::Push(const Arguments& args) { git_oid tmp = oid->GetValue(); int err = revwalk->Push(&tmp); - return Integer::New(err); + return scope.Close( Integer::New(err) ); } Handle GitRevWalk::Next(const Arguments& args) { + HandleScope scope; + GitRevWalk* revwalk = ObjectWrap::Unwrap(args.This()); Local callback; - HandleScope scope; - if(args.Length() == 0 || !args[0]->IsObject()) { return ThrowException(Exception::Error(String::New("Oid is required and must be an Object."))); } @@ -150,7 +150,7 @@ Handle GitRevWalk::Next(const Arguments& args) { eio_custom(EIO_Next, EIO_PRI_DEFAULT, EIO_AfterNext, ar); ev_ref(EV_DEFAULT_UC); - return Undefined(); + return scope.Close( Undefined() ); } int GitRevWalk::EIO_Next(eio_req *req) { @@ -188,13 +188,13 @@ int GitRevWalk::EIO_AfterNext(eio_req *req) { } Handle GitRevWalk::Free(const Arguments& args) { - GitRevWalk *revwalk = ObjectWrap::Unwrap(args.This()); - HandleScope scope; + GitRevWalk *revwalk = ObjectWrap::Unwrap(args.This()); + revwalk->Free(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitRevWalk::Repository(const Arguments& args) { @@ -209,6 +209,6 @@ Handle GitRevWalk::Repository(const Arguments& args) { GitRepo *repo = ObjectWrap::Unwrap(args[0]->ToObject()); repo->SetValue(revwalk->Repository()); - return Undefined(); + return scope.Close( Undefined() ); } Persistent GitRevWalk::constructor_template; diff --git a/src/sig.cc b/src/sig.cc index bbced516a..251b879a9 100755 --- a/src/sig.cc +++ b/src/sig.cc @@ -69,7 +69,7 @@ Handle GitSig::New(const Arguments& args) { GitSig *sig = new GitSig(); sig->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitSig::Dup(const Arguments& args) { @@ -82,7 +82,7 @@ Handle GitSig::Dup(const Arguments& args) { GitSig* sig = ObjectWrap::Unwrap(args[0]->ToObject()); sig->SetValue(sig->Dup()); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitSig::Free(const Arguments& args) { @@ -91,7 +91,7 @@ Handle GitSig::Free(const Arguments& args) { GitSig *sig = ObjectWrap::Unwrap(args.This()); sig->Free(); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitSig::Name(const Arguments& args) { @@ -99,7 +99,7 @@ Handle GitSig::Name(const Arguments& args) { GitSig *sig = ObjectWrap::Unwrap(args.This()); - return String::New(sig->Name()); + return scope.Close( String::New(sig->Name()) ); } Handle GitSig::Email(const Arguments& args) { @@ -107,6 +107,6 @@ Handle GitSig::Email(const Arguments& args) { GitSig *sig = ObjectWrap::Unwrap(args.This()); - return String::New(sig->Email()); + return scope.Close( String::New(sig->Email()) ); } Persistent GitSig::constructor_template; diff --git a/src/tree.cc b/src/tree.cc index c54f9c16c..be2306391 100755 --- a/src/tree.cc +++ b/src/tree.cc @@ -45,11 +45,11 @@ size_t GitTree::EntryCount() { } git_tree_entry* GitTree::EntryByIndex(int idx) { - return git_tree_entry_byindex(this->tree, idx); + return const_cast(git_tree_entry_byindex(this->tree, idx)); } git_tree_entry* GitTree::EntryByName(const char* name) { - return git_tree_entry_byname(this->tree, name); + return const_cast(git_tree_entry_byname(this->tree, name)); } int GitTree::SortEntries() { @@ -64,7 +64,7 @@ Handle GitTree::New(const Arguments& args) { tree->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitTree::EntryCount(const Arguments& args) { @@ -74,7 +74,7 @@ Handle GitTree::EntryCount(const Arguments& args) { int count = tree->EntryCount(); - return Local::New(Integer::New(count)); + return scope.Close( Integer::New(count) ); } Handle GitTree::EntryByIndex(const Arguments& args) { @@ -96,7 +96,7 @@ Handle GitTree::EntryByIndex(const Arguments& args) { entry->SetValue(tree->EntryByIndex(index)); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitTree::EntryByName(const Arguments& args) { @@ -120,7 +120,7 @@ Handle GitTree::EntryByName(const Arguments& args) { entry->SetValue(tree->EntryByName(*name)); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitTree::SortEntries(const Arguments& args) { @@ -130,16 +130,16 @@ Handle GitTree::SortEntries(const Arguments& args) { int err = tree->SortEntries(); - return Integer::New(err); + return scope.Close( Integer::New(err) ); } Handle GitTree::ClearEntries(const Arguments& args) { - //HandleScope scope; + HandleScope scope; //GitTree *tree = ObjectWrap::Unwrap(args.This()); //tree->ClearEntries(); - // - return Undefined(); + + return scope.Close( Undefined() ); } Persistent GitTree::constructor_template; diff --git a/src/tree_entry.cc b/src/tree_entry.cc index 49d958354..2226c9910 100755 --- a/src/tree_entry.cc +++ b/src/tree_entry.cc @@ -26,6 +26,7 @@ void GitTreeEntry::Initialize(Handle target) { constructor_template->SetClassName(String::NewSymbol("TreeEntry")); NODE_SET_PROTOTYPE_METHOD(constructor_template, "name", Name); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "attributes", Attributes); NODE_SET_PROTOTYPE_METHOD(constructor_template, "toObject", ToObject); target->Set(String::NewSymbol("TreeEntry"), constructor_template->GetFunction()); @@ -39,6 +40,10 @@ const char* GitTreeEntry::Name() { return git_tree_entry_name(this->entry); } +int GitTreeEntry::Attributes() { + return git_tree_entry_attributes(this->entry); +} + const git_oid* GitTreeEntry::Id() { return git_tree_entry_id(this->entry); } @@ -54,7 +59,7 @@ Handle GitTreeEntry::New(const Arguments& args) { entry->Wrap(args.This()); - return args.This(); + return scope.Close( args.This() ); } Handle GitTreeEntry::Name(const Arguments& args) { @@ -62,7 +67,15 @@ Handle GitTreeEntry::Name(const Arguments& args) { GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); - return String::New(entry->Name()); + return scope.Close( String::New(entry->Name()) ); +} + +Handle GitTreeEntry::Attributes(const Arguments& args) { + HandleScope scope; + + GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); + + return scope.Close( Number::New(entry->Attributes()) ); } Handle GitTreeEntry::Id(const Arguments& args) { @@ -78,29 +91,31 @@ Handle GitTreeEntry::Id(const Arguments& args) { oid->SetValue(*const_cast(entry->Id())); - return Undefined(); + return scope.Close( Undefined() ); } Handle GitTreeEntry::ToObject(const Arguments& args) { HandleScope scope; - GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); + //GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); - } + //if(args.Length() == 0 || !args[0]->IsObject()) { + // return ThrowException(Exception::Error(String::New("Repo is required and must be an Object."))); + //} - if(args.Length() == 1 || !args[1]->IsObject()) { - return ThrowException(Exception::Error(String::New("Blob is required and must be an Object."))); - } + //if(args.Length() == 1 || !args[1]->IsObject()) { + // return ThrowException(Exception::Error(String::New("Object is required and must be an Object."))); + //} - GitRepo* repo = ObjectWrap::Unwrap(args[0]->ToObject()); - GitBlob* blob = ObjectWrap::Unwrap(args[1]->ToObject()); + //GitRepo* repo = ObjectWrap::Unwrap(args[0]->ToObject()); + //GitObject* object = ObjectWrap::UnwrapToObject()); - git_object* out; - entry->ToObject(repo->GetValue(), &out); - blob->SetValue((git_blob *)out); - - return Undefined(); + //git_object* out; + //entry->ToObject(repo->GetValue(), &out); + + //GitObject->SetValue(out); + // + return scope.Close( Undefined() ); } Persistent GitTreeEntry::constructor_template; + diff --git a/test/index.js b/test/index.js index b300c8058..84b37099e 100644 --- a/test/index.js +++ b/test/index.js @@ -31,25 +31,21 @@ process.chdir( './test' ); reporter.run( [ // Raw API - 'raw-blob.js', - 'raw-commit.js', - 'raw-error.js', - 'raw-obj.js', - 'raw-oid.js', - 'raw-ref.js', - 'raw-repo.js', - 'raw-revwalk.js', - // Revwalk + 'raw-blob.js' + , 'raw-commit.js' + , 'raw-error.js' + , 'raw-object.js' + , 'raw-oid.js' + , 'raw-reference.js' + , 'raw-repo.js' + , 'raw-revwalk.js' // Sig // Tree // Tree Entry // Util - // TODO: - //'raw-revwalk.js', - // Convenience API - 'convenience-repo.js' + , 'convenience-repo.js' // Blob // Commit // Error diff --git a/test/raw-blob.js b/test/raw-blob.js index 900f743c2..d63eb70af 100644 --- a/test/raw-blob.js +++ b/test/raw-blob.js @@ -40,8 +40,9 @@ exports.constructor = function( test ){ // Blob::Lookup exports.lookup = function( test ) { - var testOid = new git.Oid(), - testBlob = new git.Blob(); + var testOid = new git.Oid() + , testRef = new git.Ref( testRepo ) + , testBlob = new git.Blob(); test.expect( 5 ); @@ -63,14 +64,27 @@ exports.lookup = function( test ) { testBlob.lookup( testRepo, testOid ); }, 'Throw an exception if no callback Object' ); - // Test invalid oid lookup - //testBlob.lookup( testRepo, testOid, function( err ) { - // - // console.log( err ); + testRepo.open( path.resolve( '../.git' ), function() { + + //testOid.mkstr( '59b20b8d5c6ff8d09518454d4dd8b7b30f095ab5' ); - //}); + //testCommit.lookup( testRepo, testOid, function( err ) { + // var tree = new git.Tree( testRepo ) + // , entry = new git.TreeEntry() + // , blob = new git.Blob( testRepo ); + + // if( !testCommit.tree( tree ) && tree.entryCount() > 1 ) { + // tree.entryByIndex( entry, 1 ); + // entry.toObject( testRepo, blob ); + + // //console.log( entry.name() + ':' ); + // //console.log( blob.rawSize() ); + // //console.dir( blob.rawContent() ); + // } + //}); + test.done(); - test.done(); + }); }; // Blob::RawContent diff --git a/test/raw-obj.js b/test/raw-object.js similarity index 100% rename from test/raw-obj.js rename to test/raw-object.js diff --git a/test/raw-ref.js b/test/raw-reference.js similarity index 100% rename from test/raw-ref.js rename to test/raw-reference.js diff --git a/util/hint-check.js b/util/hint-check.js index 7f31f331b..bacd1666b 100644 --- a/util/hint-check.js +++ b/util/hint-check.js @@ -6,7 +6,7 @@ files = [ 'lib/commit.js', 'lib/error.js', 'lib/index.js', - 'lib/obj.js', + 'lib/object.js', 'lib/oid.js', 'lib/ref.js', 'lib/repo.js', diff --git a/vendor/libgit2/README.md b/vendor/libgit2/README.md index 1254adcd9..dae6a76bf 100644 --- a/vendor/libgit2/README.md +++ b/vendor/libgit2/README.md @@ -85,8 +85,8 @@ The waf build system for libgit2 accepts the following flags: --arch=[ia64|x64|x86|x86_amd64|x86_ia64] Force a specific architecture for compilers that support it. - --without-sqlite - Disable sqlite support. + --with-sqlite + Enable sqlite support. You can run `./waf --help` to see a full list of install options and targets. diff --git a/vendor/libgit2/include/git2.h b/vendor/libgit2/include/git2.h index 29fa98e18..d44c3f8df 100644 --- a/vendor/libgit2/include/git2.h +++ b/vendor/libgit2/include/git2.h @@ -26,9 +26,9 @@ #ifndef INCLUDE_git_git_h__ #define INCLUDE_git_git_h__ -#define LIBGIT2_VERSION "0.11.0" +#define LIBGIT2_VERSION "0.12.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 10 +#define LIBGIT2_VER_MINOR 12 #define LIBGIT2_VER_REVISION 0 #include "git2/common.h" diff --git a/vendor/libgit2/include/git2/commit.h b/vendor/libgit2/include/git2/commit.h index c09b34843..3687d9460 100644 --- a/vendor/libgit2/include/git2/commit.h +++ b/vendor/libgit2/include/git2/commit.h @@ -135,6 +135,16 @@ GIT_EXTERN(const git_signature *) git_commit_author(git_commit *commit); */ GIT_EXTERN(int) git_commit_tree(git_tree **tree_out, git_commit *commit); +/** + * Get the id of the tree pointed to by a commit. This differs from + * `git_commit_tree` in that no attempts are made to fetch an object + * from the ODB. + * + * @param commit a previously loaded commit. + * @return the id of tree pointed to by commit. + */ +GIT_EXTERN(const git_oid *) git_commit_tree_oid(git_commit *commit); + /** * Get the number of parents of this commit * @@ -153,6 +163,16 @@ GIT_EXTERN(unsigned int) git_commit_parentcount(git_commit *commit); */ GIT_EXTERN(int) git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n); +/** + * Get the oid of a specified parent for a commit. This is different from + * `git_commit_parent`, which will attempt to load the parent commit from + * the ODB. + * + * @param commit a previously loaded commit. + * @param n the position of the parent (from 0 to `parentcount`) + * @return the id of the parent, NULL on error. + */ +GIT_EXTERN(const git_oid *) git_commit_parent_oid(git_commit *commit, unsigned int n); /** * Create a new commit in the repository diff --git a/vendor/libgit2/include/git2/common.h b/vendor/libgit2/include/git2/common.h index 57ab9c1ff..9a27ac2e5 100644 --- a/vendor/libgit2/include/git2/common.h +++ b/vendor/libgit2/include/git2/common.h @@ -84,83 +84,6 @@ * @{ */ -/** Operation completed successfully. */ -#define GIT_SUCCESS 0 - -/** - * Operation failed, with unspecified reason. - * This value also serves as the base error code; all other - * error codes are subtracted from it such that all errors - * are < 0, in typical POSIX C tradition. - */ -#define GIT_ERROR -1 - -/** Input was not a properly formatted Git object id. */ -#define GIT_ENOTOID (GIT_ERROR - 1) - -/** Input does not exist in the scope searched. */ -#define GIT_ENOTFOUND (GIT_ERROR - 2) - -/** Not enough space available. */ -#define GIT_ENOMEM (GIT_ERROR - 3) - -/** Consult the OS error information. */ -#define GIT_EOSERR (GIT_ERROR - 4) - -/** The specified object is of invalid type */ -#define GIT_EOBJTYPE (GIT_ERROR - 5) - -/** The specified object has its data corrupted */ -#define GIT_EOBJCORRUPTED (GIT_ERROR - 6) - -/** The specified repository is invalid */ -#define GIT_ENOTAREPO (GIT_ERROR - 7) - -/** The object type is invalid or doesn't match */ -#define GIT_EINVALIDTYPE (GIT_ERROR - 8) - -/** The object cannot be written because it's missing internal data */ -#define GIT_EMISSINGOBJDATA (GIT_ERROR - 9) - -/** The packfile for the ODB is corrupted */ -#define GIT_EPACKCORRUPTED (GIT_ERROR - 10) - -/** Failed to acquire or release a file lock */ -#define GIT_EFLOCKFAIL (GIT_ERROR - 11) - -/** The Z library failed to inflate/deflate an object's data */ -#define GIT_EZLIB (GIT_ERROR - 12) - -/** The queried object is currently busy */ -#define GIT_EBUSY (GIT_ERROR - 13) - -/** The index file is not backed up by an existing repository */ -#define GIT_EBAREINDEX (GIT_ERROR - 14) - -/** The name of the reference is not valid */ -#define GIT_EINVALIDREFNAME (GIT_ERROR - 15) - -/** The specified reference has its data corrupted */ -#define GIT_EREFCORRUPTED (GIT_ERROR - 16) - -/** The specified symbolic reference is too deeply nested */ -#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17) - -/** The pack-refs file is either corrupted or its format is not currently supported */ -#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18) - -/** The path is invalid */ -#define GIT_EINVALIDPATH (GIT_ERROR - 19) - -/** The revision walker is empty; there are no more commits left to iterate */ -#define GIT_EREVWALKOVER (GIT_ERROR - 20) - -/** The state of the reference is not valid */ -#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21) - -/** This feature has not been implemented yet */ -#define GIT_ENOTIMPLEMENTED (GIT_ERROR - 22) - GIT_BEGIN_DECL typedef struct { diff --git a/vendor/libgit2/include/git2/errors.h b/vendor/libgit2/include/git2/errors.h index 627e67c70..dbe565aab 100644 --- a/vendor/libgit2/include/git2/errors.h +++ b/vendor/libgit2/include/git2/errors.h @@ -33,8 +33,112 @@ */ GIT_BEGIN_DECL +/** Operation completed successfully. */ +#define GIT_SUCCESS 0 + +/** + * Operation failed, with unspecified reason. + * This value also serves as the base error code; all other + * error codes are subtracted from it such that all errors + * are < 0, in typical POSIX C tradition. + */ +#define GIT_ERROR -1 + +/** Input was not a properly formatted Git object id. */ +#define GIT_ENOTOID (GIT_ERROR - 1) + +/** Input does not exist in the scope searched. */ +#define GIT_ENOTFOUND (GIT_ERROR - 2) + +/** Not enough space available. */ +#define GIT_ENOMEM (GIT_ERROR - 3) + +/** Consult the OS error information. */ +#define GIT_EOSERR (GIT_ERROR - 4) + +/** The specified object is of invalid type */ +#define GIT_EOBJTYPE (GIT_ERROR - 5) + +/** The specified object has its data corrupted */ +#define GIT_EOBJCORRUPTED (GIT_ERROR - 6) + +/** The specified repository is invalid */ +#define GIT_ENOTAREPO (GIT_ERROR - 7) + +/** The object type is invalid or doesn't match */ +#define GIT_EINVALIDTYPE (GIT_ERROR - 8) + +/** The object cannot be written because it's missing internal data */ +#define GIT_EMISSINGOBJDATA (GIT_ERROR - 9) + +/** The packfile for the ODB is corrupted */ +#define GIT_EPACKCORRUPTED (GIT_ERROR - 10) + +/** Failed to acquire or release a file lock */ +#define GIT_EFLOCKFAIL (GIT_ERROR - 11) + +/** The Z library failed to inflate/deflate an object's data */ +#define GIT_EZLIB (GIT_ERROR - 12) + +/** The queried object is currently busy */ +#define GIT_EBUSY (GIT_ERROR - 13) + +/** The index file is not backed up by an existing repository */ +#define GIT_EBAREINDEX (GIT_ERROR - 14) + +/** The name of the reference is not valid */ +#define GIT_EINVALIDREFNAME (GIT_ERROR - 15) + +/** The specified reference has its data corrupted */ +#define GIT_EREFCORRUPTED (GIT_ERROR - 16) + +/** The specified symbolic reference is too deeply nested */ +#define GIT_ETOONESTEDSYMREF (GIT_ERROR - 17) + +/** The pack-refs file is either corrupted or its format is not currently supported */ +#define GIT_EPACKEDREFSCORRUPTED (GIT_ERROR - 18) + +/** The path is invalid */ +#define GIT_EINVALIDPATH (GIT_ERROR - 19) + +/** The revision walker is empty; there are no more commits left to iterate */ +#define GIT_EREVWALKOVER (GIT_ERROR - 20) + +/** The state of the reference is not valid */ +#define GIT_EINVALIDREFSTATE (GIT_ERROR - 21) + +/** This feature has not been implemented yet */ +#define GIT_ENOTIMPLEMENTED (GIT_ERROR - 22) + +/** A reference with this name already exists */ +#define GIT_EEXISTS (GIT_ERROR - 23) + +/** The given integer literal is too large to be parsed */ +#define GIT_EOVERFLOW (GIT_ERROR - 24) + +/** The given literal is not a valid number */ +#define GIT_ENOTNUM (GIT_ERROR - 25) + +/** Streaming error */ +#define GIT_ESTREAM (GIT_ERROR - 26) + +/** invalid arguments to function */ +#define GIT_EINVALIDARGS (GIT_ERROR - 27) + +/** + * Return a detailed error string with the latest error + * that occurred in the library. + * @return a string explaining the error + */ +GIT_EXTERN(const char *) git_lasterror(void); + /** * strerror() for the Git library + * + * Get a string description for a given error code. + * NOTE: This method will be eventually deprecated in favor + * of the new `git_lasterror`. + * * @param num The error code to explain * @return a string explaining the error code */ diff --git a/vendor/libgit2/include/git2/index.h b/vendor/libgit2/include/git2/index.h index 599512f8a..2d8975ca1 100644 --- a/vendor/libgit2/include/git2/index.h +++ b/vendor/libgit2/include/git2/index.h @@ -44,6 +44,36 @@ GIT_BEGIN_DECL #define GIT_IDXENTRY_VALID (0x8000) #define GIT_IDXENTRY_STAGESHIFT 12 +/* + * Flags are divided into two parts: in-memory flags and + * on-disk ones. Flags in GIT_IDXENTRY_EXTENDED_FLAGS + * will get saved on-disk. + * + * In-memory only flags: + */ +#define GIT_IDXENTRY_UPDATE (1 << 0) +#define GIT_IDXENTRY_REMOVE (1 << 1) +#define GIT_IDXENTRY_UPTODATE (1 << 2) +#define GIT_IDXENTRY_ADDED (1 << 3) + +#define GIT_IDXENTRY_HASHED (1 << 4) +#define GIT_IDXENTRY_UNHASHED (1 << 5) +#define GIT_IDXENTRY_WT_REMOVE (1 << 6) /* remove in work directory */ +#define GIT_IDXENTRY_CONFLICTED (1 << 7) + +#define GIT_IDXENTRY_UNPACKED (1 << 8) +#define GIT_IDXENTRY_NEW_SKIP_WORKTREE (1 << 9) + +/* + * Extended on-disk flags: + */ +#define GIT_IDXENTRY_INTENT_TO_ADD (1 << 13) +#define GIT_IDXENTRY_SKIP_WORKTREE (1 << 14) +/* GIT_IDXENTRY_EXTENDED2 is for future extension */ +#define GIT_IDXENTRY_EXTENDED2 (1 << 15) + +#define GIT_IDXENTRY_EXTENDED_FLAGS (GIT_IDXENTRY_INTENT_TO_ADD | GIT_IDXENTRY_SKIP_WORKTREE) + /** Time used in a git index entry */ typedef struct { git_time_t seconds; @@ -142,7 +172,12 @@ GIT_EXTERN(int) git_index_write(git_index *index); GIT_EXTERN(int) git_index_find(git_index *index, const char *path); /** - * Add or update an index entry from a file in disk. + * Add or update an index entry from a file in disk + * + * The file `path` must be relative to the repository's + * working folder and must be readable. + * + * This method will fail in bare index instances. * * @param index an existing index object * @param path filename to add @@ -152,26 +187,62 @@ GIT_EXTERN(int) git_index_find(git_index *index, const char *path); GIT_EXTERN(int) git_index_add(git_index *index, const char *path, int stage); /** - * Remove an entry from the index + * Add or update an index entry from an in-memory struct + * + * A full copy (including the 'path' string) of the given + * 'source_entry' will be inserted on the index. * * @param index an existing index object - * @param position position of the entry to remove + * @param source_entry new entry object * @return 0 on success, otherwise an error code */ -GIT_EXTERN(int) git_index_remove(git_index *index, int position); +GIT_EXTERN(int) git_index_add2(git_index *index, const git_index_entry *source_entry); /** - * Insert an entry into the index. + * Add (append) an index entry from a file in disk + * + * A new entry will always be inserted into the index; + * if the index already contains an entry for such + * path, the old entry will **not** be replaced. + * + * The file `path` must be relative to the repository's + * working folder and must be readable. + * + * This method will fail in bare index instances. + * + * @param index an existing index object + * @param path filename to add + * @param stage stage for the entry + * @return 0 on success, otherwise an error code + */ +GIT_EXTERN(int) git_index_append(git_index *index, const char *path, int stage); + +/** + * Add (append) an index entry from an in-memory struct + * + * A new entry will always be inserted into the index; + * if the index already contains an entry for the path + * in the `entry` struct, the old entry will **not** be + * replaced. + * * A full copy (including the 'path' string) of the given - * 'source_entry' will be inserted on the index; if the index - * already contains an entry for the same path, the entry - * will be updated. + * 'source_entry' will be inserted on the index. * * @param index an existing index object * @param source_entry new entry object * @return 0 on success, otherwise an error code */ -GIT_EXTERN(int) git_index_insert(git_index *index, const git_index_entry *source_entry); +GIT_EXTERN(int) git_index_append2(git_index *index, const git_index_entry *source_entry); + +/** + * Remove an entry from the index + * + * @param index an existing index object + * @param position position of the entry to remove + * @return 0 on success, otherwise an error code + */ +GIT_EXTERN(int) git_index_remove(git_index *index, int position); + /** * Get a pointer to one of the entries in the index diff --git a/vendor/libgit2/include/git2/refs.h b/vendor/libgit2/include/git2/refs.h index da55eaa3b..298c66d51 100644 --- a/vendor/libgit2/include/git2/refs.h +++ b/vendor/libgit2/include/git2/refs.h @@ -68,6 +68,27 @@ GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_reposito */ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target); +/** + * Create a new symbolic reference, overwriting an existing one with + * the same name, if it exists. + * + * If the new reference isn't a symbolic one, any pointers to the old + * reference become invalid. + * + * The reference will be created in the repository and written + * to the disk. + * + * This reference is owned by the repository and shall not + * be free'd by the user. + * + * @param ref_out Pointer to the newly created reference + * @param repo Repository where that reference will live + * @param name The name of the reference + * @param target The target of the reference + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target); + /** * Create a new object id reference. * @@ -85,6 +106,27 @@ GIT_EXTERN(int) git_reference_create_symbolic(git_reference **ref_out, git_repos */ GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id); +/** + * Create a new object id reference, overwriting an existing one with + * the same name, if it exists. + * + * If the new reference isn't an object id one, any pointers to the + * old reference become invalid. + * + * The reference will be created in the repository and written + * to the disk. + * + * This reference is owned by the repository and shall not + * be free'd by the user. + * + * @param ref_out Pointer to the newly created reference + * @param repo Repository where that reference will live + * @param name The name of the reference + * @param id The object id pointed to by the reference. + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id); + /** * Get the OID pointed to by a reference. * @@ -189,6 +231,20 @@ GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); */ GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name); +/** + * Rename an existing reference, overwriting an existing one with the + * same name, if it exists. + * + * This method works for both direct and symbolic references. + * The new name will be checked for validity and may be + * modified into a normalized form. + * + * The refernece will be immediately renamed in-memory + * and on disk. + * + */ +GIT_EXTERN(int) git_reference_rename_f(git_reference *ref, const char *new_name); + /** * Delete an existing reference * diff --git a/vendor/libgit2/include/git2/repository.h b/vendor/libgit2/include/git2/repository.h index 00c1f20d0..c47fcfc9a 100644 --- a/vendor/libgit2/include/git2/repository.h +++ b/vendor/libgit2/include/git2/repository.h @@ -182,6 +182,36 @@ GIT_EXTERN(void) git_repository_free(git_repository *repo); */ GIT_EXTERN(int) git_repository_init(git_repository **repo_out, const char *path, unsigned is_bare); +/** + * Check if a repository is empty + * + * An empty repository has just been initialized and contains + * no commits. + * + * @param repo Repo to test + * @return 1 if the repository is empty, 0 if it isn't, error code + * if the repository is corrupted + */ +GIT_EXTERN(int) git_repository_is_empty(git_repository *repo); + +/** + * Get the normalized path to the git repository. + * + * @param repo a repository object + * @return absolute path to the git directory + */ +GIT_EXTERN(const char *) git_repository_path(git_repository *repo); + +/** + * Get the normalized path to the working directory of the repository. + * + * If the repository is bare, there is no working directory and NULL we be returned. + * + * @param repo a repository object + * @return NULL if the repository is bare; absolute path to the working directory otherwise. + */ +GIT_EXTERN(const char *) git_repository_workdir(git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/signature.h b/vendor/libgit2/include/git2/signature.h index 40412a45f..44d1f285e 100644 --- a/vendor/libgit2/include/git2/signature.h +++ b/vendor/libgit2/include/git2/signature.h @@ -41,19 +41,30 @@ GIT_BEGIN_DECL * Create a new action signature. The signature must be freed * manually or using git_signature_free * - * @name name of the person - * @email email of the person - * @time time when the action happened - * @offset timezone offset in minutes for the time + * @param name name of the person + * @param mail email of the person + * @param time time when the action happened + * @param offset timezone offset in minutes for the time * @return the new sig, NULL on out of memory */ GIT_EXTERN(git_signature *) git_signature_new(const char *name, const char *email, git_time_t time, int offset); +/** + * Create a new action signature with a timestamp of 'now'. The + * signature must be freed manually or using git_signature_free + * + * @param name name of the person + * @param email email of the person + * @return the new sig, NULL on out of memory + */ +GIT_EXTERN(git_signature *) git_signature_now(const char *name, const char *email); + + /** * Create a copy of an existing signature. * * All internal strings are also duplicated. - * @sig signature to duplicated + * @param sig signature to duplicated * @return a copy of sig, NULL on out of memory */ GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig); @@ -61,7 +72,7 @@ GIT_EXTERN(git_signature *) git_signature_dup(const git_signature *sig); /** * Free an existing signature * - * @sig signature to free + * @param sig signature to free */ GIT_EXTERN(void) git_signature_free(git_signature *sig); diff --git a/vendor/libgit2/include/git2/tag.h b/vendor/libgit2/include/git2/tag.h index ee92cd5c2..3fc6b4499 100644 --- a/vendor/libgit2/include/git2/tag.h +++ b/vendor/libgit2/include/git2/tag.h @@ -140,7 +140,8 @@ GIT_EXTERN(const char *) git_tag_message(git_tag *t); * @param repo Repository where to store the tag * * @param tag_name Name for the tag; this name is validated - * for consistency + * for consistency. It should also not conflict with an + * already existing tag name * * @param target OID to which this tag points; note that no * validation is done on this OID. Use the _o version of this @@ -188,6 +189,109 @@ GIT_EXTERN(int) git_tag_create_o( const git_signature *tagger, const char *message); +/** + * Create a new tag in the repository from a buffer + * + * @param oid Pointer where to store the OID of the newly created tag + * + * @param repo Repository where to store the tag + * + * @param buffer Raw tag data + */ +GIT_EXTERN(int) git_tag_create_frombuffer( + git_oid *oid, + git_repository *repo, + const char *buffer); + +/** + * Create a new tag in the repository from an OID + * and overwrite an already existing tag reference, if any. + * + * @param oid Pointer where to store the OID of the + * newly created tag + * + * @param repo Repository where to store the tag + * + * @param tag_name Name for the tag; this name is validated + * for consistency. + * + * @param target OID to which this tag points; note that no + * validation is done on this OID. Use the _fo version of this + * method to assure a proper object is being tagged + * + * @param target_type Type of the tagged OID; note that no + * validation is performed here either + * + * @param tagger Signature of the tagger for this tag, and + * of the tagging time + * + * @param message Full message for this tag + * + * @return 0 on success; error code otherwise. + * A tag object is written to the ODB, and a proper reference + * is written in the /refs/tags folder, pointing to it + */ +GIT_EXTERN(int) git_tag_create_f( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_oid *target, + git_otype target_type, + const git_signature *tagger, + const char *message); + +/** + * Create a new tag in the repository from an existing + * `git_object` instance and overwrite an already existing + * tag reference, if any. + * + * This method replaces the `target` and `target_type` + * paremeters of `git_tag_create_f` by a single instance + * of a `const git_object *`, which is assured to be + * a proper object in the ODB and hence will create + * a valid tag + * + * @see git_tag_create_f + */ +GIT_EXTERN(int) git_tag_create_fo( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + const git_signature *tagger, + const char *message); + +/** + * Delete an existing tag reference. + * + * @param repo Repository where lives the tag + * + * @param tag_name Name of the tag to be deleted; + * this name is validated for consistency. + * + * @return 0 on success; error code otherwise. + */ +GIT_EXTERN(int) git_tag_delete( + git_repository *repo, + const char *tag_name); + +/** + * Fill a list with all the tags in the Repository + * + * The string array will be filled with the names of the + * matching tags; these values are owned by the user and + * should be free'd manually when no longer needed, using + * `git_strarray_free`. + * + * @param array Pointer to a git_strarray structure where + * the tag names will be stored + * @param repo Repository where to find the tags + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_tag_list( + git_strarray *tag_names, + git_repository *repo); + /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/include/git2/thread-utils.h b/vendor/libgit2/include/git2/thread-utils.h index fb8644b93..e26876bea 100644 --- a/vendor/libgit2/include/git2/thread-utils.h +++ b/vendor/libgit2/include/git2/thread-utils.h @@ -35,6 +35,7 @@ #if defined(__APPLE__) && defined(__MACH__) # undef GIT_TLS +# define GIT_TLS #elif defined(__GNUC__) || \ defined(__SUNPRO_C) || \ diff --git a/vendor/libgit2/include/git2/tree.h b/vendor/libgit2/include/git2/tree.h index 164aec9e2..0caf60a48 100644 --- a/vendor/libgit2/include/git2/tree.h +++ b/vendor/libgit2/include/git2/tree.h @@ -93,7 +93,7 @@ GIT_EXTERN(size_t) git_tree_entrycount(git_tree *tree); * @param filename the filename of the desired entry * @return the tree entry; NULL if not found */ -GIT_EXTERN(git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *filename); +GIT_EXTERN(const git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *filename); /** * Lookup a tree entry by its position in the tree @@ -102,7 +102,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byname(git_tree *tree, const char *f * @param idx the position in the entry list * @return the tree entry; NULL if not found */ -GIT_EXTERN(git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx); +GIT_EXTERN(const git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx); /** * Get the UNIX file attributes of a tree entry @@ -110,7 +110,7 @@ GIT_EXTERN(git_tree_entry *) git_tree_entry_byindex(git_tree *tree, int idx); * @param entry a tree entry * @return attributes as an integer */ -GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry); +GIT_EXTERN(unsigned int) git_tree_entry_attributes(const git_tree_entry *entry); /** * Get the filename of a tree entry @@ -118,7 +118,7 @@ GIT_EXTERN(unsigned int) git_tree_entry_attributes(git_tree_entry *entry); * @param entry a tree entry * @return the name of the file */ -GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry); +GIT_EXTERN(const char *) git_tree_entry_name(const git_tree_entry *entry); /** * Get the id of the object pointed by the entry @@ -126,7 +126,7 @@ GIT_EXTERN(const char *) git_tree_entry_name(git_tree_entry *entry); * @param entry a tree entry * @return the oid of the object */ -GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry); +GIT_EXTERN(const git_oid *) git_tree_entry_id(const git_tree_entry *entry); /** * Convert a tree entry to the git_object it points too. @@ -134,9 +134,132 @@ GIT_EXTERN(const git_oid *) git_tree_entry_id(git_tree_entry *entry); * @param object pointer to the converted object * @param repo repository where to lookup the pointed object * @param entry a tree entry - * @return a reference to the pointed object in the repository + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, const git_tree_entry *entry); + +/** + * Write a tree to the ODB from the index file + * + * This method will scan the index and write a representation + * of its current state back to disk; it recursively creates + * tree objects for each of the subtrees stored in the index, + * but only returns the OID of the root tree. This is the OID + * that can be used e.g. to create a commit. + * + * The index instance cannot be bare, and needs to be associated + * to an existing repository. + * + * @param oid Pointer where to store the written tree + * @param index Index to write + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_tree_create_fromindex(git_oid *oid, git_index *index); + +/** + * Create a new tree builder. + * + * The tree builder can be used to create or modify + * trees in memory and write them as tree objects to the + * database. + * + * If the `source` parameter is not NULL, the tree builder + * will be initialized with the entries of the given tree. + * + * If the `source` parameter is NULL, the tree builder will + * have no entries and will have to be filled manually. + * + * @param builder_p Pointer where to store the tree builder + * @param source Source tree to initialize the builder (optional) + * @return 0 on sucess; error code otherwise + */ +GIT_EXTERN(int) git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source); + +/** + * Clear all the entires in the builder + * + * @param bld Builder to clear + */ +GIT_EXTERN(void) git_treebuilder_clear(git_treebuilder *bld); + +/** + * Free a tree builder + * + * This will clear all the entries and free to builder. + * Failing to free the builder after you're done using it + * will result in a memory leak + * + * @param bld Builder to free + */ +GIT_EXTERN(void) git_treebuilder_free(git_treebuilder *bld); + +/** + * Get an entry from the builder from its filename + * + * The returned entry is owned by the builder and should + * not be freed manually. + * + * @param bld Tree builder + * @param filename Name of the entry + * @return pointer to the entry; NULL if not found + */ +GIT_EXTERN(const git_tree_entry *) git_treebuilder_get(git_treebuilder *bld, const char *filename); + +/** + * Add or update an entry to the builder + * + * Insert a new entry for `filename` in the builder with the + * given attributes. + * + * if an entry named `filename` already exists, its attributes + * will be updated with the given ones. + * + * The optional pointer `entry_out` can be used to retrieve a + * pointer to the newly created/updated entry. + * + * @param entry_out Pointer to store the entry (optional) + * @param bld Tree builder + * @param filename Filename of the entry + * @param id SHA1 oid of the entry + * @param attributes Folder attributes of the entry + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes); + +/** + * Remove an entry from the builder by its filename + * + * @param bld Tree builder + * @param filename Filename of the entry to remove + */ +GIT_EXTERN(int) git_treebuilder_remove(git_treebuilder *bld, const char *filename); + +/** + * Filter the entries in the tree + * + * The `filter` callback will be called for each entry + * in the tree with a pointer to the entry and the + * provided `payload`: if the callback returns 1, the + * entry will be filtered (removed from the builder). + * + * @param bld Tree builder + * @param filter Callback to filter entries + */ +GIT_EXTERN(void) git_treebuilder_filter(git_treebuilder *bld, int (*filter)(const git_tree_entry *, void *), void *payload); + +/** + * Write the contents of the tree builder as a tree object + * + * The tree builder will be written to the given `repo`, and + * it's identifying SHA1 hash will be stored in the `oid` + * pointer. + * + * @param oid Pointer where to store the written OID + * @param repo Repository where to store the object + * @param bld Tree builder to write + * @return 0 on success; error code otherwise */ -GIT_EXTERN(int) git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry); +GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld); /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/include/git2/types.h b/vendor/libgit2/include/git2/types.h index 88f6b7d55..6123abc82 100644 --- a/vendor/libgit2/include/git2/types.h +++ b/vendor/libgit2/include/git2/types.h @@ -124,6 +124,9 @@ typedef struct git_tree_entry git_tree_entry; /** Representation of a tree object. */ typedef struct git_tree git_tree; +/** Constructor for in-memory trees */ +typedef struct git_treebuilder git_treebuilder; + /** Memory representation of an index file. */ typedef struct git_index git_index; diff --git a/vendor/libgit2/src/backends/hiredis.c b/vendor/libgit2/src/backends/hiredis.c new file mode 100644 index 000000000..707412bf6 --- /dev/null +++ b/vendor/libgit2/src/backends/hiredis.c @@ -0,0 +1,200 @@ +/* + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * In addition to the permissions in the GNU General Public License, + * the authors give you unlimited permission to link the compiled + * version of this file into combinations with other programs, + * and to distribute those combinations without any restriction + * coming from the use of this file. (The General Public License + * restrictions do apply in other respects; for example, they cover + * modification of the file, and distribution when not linked into + * a combined executable.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#include "common.h" +#include "git2/object.h" +#include "hash.h" +#include "odb.h" + +#include "git2/odb_backend.h" + +#ifdef GIT2_HIREDIS_BACKEND + +#include + +typedef struct { + git_odb_backend parent; + + redisContext *db; +} hiredis_backend; + +int hiredis_backend__read_header(size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(len_p && type_p && _backend && oid); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + reply = redisCommand(backend->db, "HMGET %b %s %s", oid->id, GIT_OID_RAWSZ, + "type", "size"); + + if (reply->type == REDIS_REPLY_ARRAY) { + if (reply->element[0]->type != REDIS_REPLY_NIL && + reply->element[0]->type != REDIS_REPLY_NIL) { + *type_p = (git_otype) atoi(reply->element[0]->str); + *len_p = (size_t) atoi(reply->element[1]->str); + error = GIT_SUCCESS; + } else { + error = GIT_ENOTFOUND; + } + } else { + error = GIT_ERROR; + } + + freeReplyObject(reply); + return error; +} + +int hiredis_backend__read(void **data_p, size_t *len_p, git_otype *type_p, git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(data_p && len_p && type_p && _backend && oid); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + reply = redisCommand(backend->db, "HMGET %b %s %s %s", oid->id, GIT_OID_RAWSZ, + "type", "size", "data"); + + if (reply->type == REDIS_REPLY_ARRAY) { + if (reply->element[0]->type != REDIS_REPLY_NIL && + reply->element[1]->type != REDIS_REPLY_NIL && + reply->element[2]->type != REDIS_REPLY_NIL) { + *type_p = (git_otype) atoi(reply->element[0]->str); + *len_p = (size_t) atoi(reply->element[1]->str); + *data_p = git__malloc(*len_p); + if (*data_p == NULL) { + error = GIT_ENOMEM; + } else { + memcpy(*data_p, reply->element[2]->str, *len_p); + error = GIT_SUCCESS; + } + } else { + error = GIT_ENOTFOUND; + } + } else { + error = GIT_ERROR; + } + + freeReplyObject(reply); + return error; +} + +int hiredis_backend__exists(git_odb_backend *_backend, const git_oid *oid) { + hiredis_backend *backend; + int found; + redisReply *reply; + + assert(_backend && oid); + + backend = (hiredis_backend *) _backend; + found = 0; + + reply = redisCommand(backend->db, "exists %b", oid->id, GIT_OID_RAWSZ); + if (reply->type != REDIS_REPLY_NIL && reply->type != REDIS_REPLY_ERROR) + found = 1; + + + freeReplyObject(reply); + return found; +} + +int hiredis_backend__write(git_oid *id, git_odb_backend *_backend, const void *data, size_t len, git_otype type) { + hiredis_backend *backend; + int error; + redisReply *reply; + + assert(id && _backend && data); + + backend = (hiredis_backend *) _backend; + error = GIT_ERROR; + + if ((error = git_odb_hash(id, data, len, type)) < 0) + return error; + + reply = redisCommand(backend->db, "HMSET %b " + "type %d " + "size %d " + "data %b ", id->id, GIT_OID_RAWSZ, + (int) type, len, data, len); + error = reply->type == REDIS_REPLY_ERROR ? GIT_ERROR : GIT_SUCCESS; + + freeReplyObject(reply); + return error; +} + +void hiredis_backend__free(git_odb_backend *_backend) { + hiredis_backend *backend; + assert(_backend); + backend = (hiredis_backend *) _backend; + + redisFree(backend->db); + + free(backend); +} + +int git_odb_backend_hiredis(git_odb_backend **backend_out, const char *host, int port) { + hiredis_backend *backend; + + backend = git__calloc(1, sizeof (hiredis_backend)); + if (backend == NULL) + return GIT_ENOMEM; + + + backend->db = redisConnect(host, port); + if (backend->db->err) + goto cleanup; + + backend->parent.read = &hiredis_backend__read; + backend->parent.read_header = &hiredis_backend__read_header; + backend->parent.write = &hiredis_backend__write; + backend->parent.exists = &hiredis_backend__exists; + backend->parent.free = &hiredis_backend__free; + + *backend_out = (git_odb_backend *) backend; + + return GIT_SUCCESS; +cleanup: + free(backend); + return GIT_ERROR; +} + +#else + +int git_odb_backend_hiredis(git_odb_backend ** GIT_UNUSED(backend_out), + const char *GIT_UNUSED(host), int GIT_UNUSED(port)) { + GIT_UNUSED_ARG(backend_out); + GIT_UNUSED_ARG(host); + GIT_UNUSED_ARG(port); + return GIT_ENOTIMPLEMENTED; +} + + +#endif /* HAVE_HIREDIS */ diff --git a/vendor/libgit2/src/blob.c b/vendor/libgit2/src/blob.c index bc0a08a8a..5e3c22fbf 100644 --- a/vendor/libgit2/src/blob.c +++ b/vendor/libgit2/src/blob.c @@ -115,6 +115,7 @@ int git_blob_create_fromfile(git_oid *oid, git_repository *repo, const char *pat error = stream->finalize_write(oid, stream); stream->free(stream); + gitfo_close(fd); return error; } diff --git a/vendor/libgit2/src/commit.c b/vendor/libgit2/src/commit.c index 03b111da5..54d7a47fe 100644 --- a/vendor/libgit2/src/commit.c +++ b/vendor/libgit2/src/commit.c @@ -224,9 +224,18 @@ int git_commit_create( if (error < GIT_SUCCESS) return error; - if (git_reference_type(head) == GIT_REF_SYMBOLIC) { - if ((error = git_reference_resolve(&head, head)) < GIT_SUCCESS) + error = git_reference_resolve(&head, head); + if (error < GIT_SUCCESS) { + if (error != GIT_ENOTFOUND) return error; + /* + * The target of the reference was not found. This can happen + * just after a repository has been initialized (the master + * branch doesn't exist yet, as it doesn't have anything to + * point to) or after an orphan checkout, so if the target + * branch doesn't exist yet, create it and return. + */ + return git_reference_create_oid_f(&head, repo, git_reference_target(head), oid); } error = git_reference_set_oid(head, oid); @@ -235,9 +244,9 @@ int git_commit_create( return error; } -int commit_parse_buffer(git_commit *commit, void *data, size_t len) +int commit_parse_buffer(git_commit *commit, const void *data, size_t len) { - char *buffer = (char *)data; + const char *buffer = (char *)data; const char *buffer_end = (char *)data + len; git_oid parent_oid; @@ -277,7 +286,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len) if (buffer < buffer_end) { const char *line_end; - size_t message_len = buffer_end - buffer; + size_t message_len; /* Long message */ message_len = buffer_end - buffer; @@ -318,6 +327,7 @@ GIT_COMMIT_GETTER(const char *, message_short, commit->message_short) GIT_COMMIT_GETTER(git_time_t, time, commit->committer->when.time) GIT_COMMIT_GETTER(int, time_offset, commit->committer->when.offset) GIT_COMMIT_GETTER(unsigned int, parentcount, commit->parent_oids.length) +GIT_COMMIT_GETTER(const git_oid *, tree_oid, &commit->tree_oid); int git_commit_tree(git_tree **tree_out, git_commit *commit) @@ -338,4 +348,9 @@ int git_commit_parent(git_commit **parent, git_commit *commit, unsigned int n) return git_commit_lookup(parent, commit->object.repo, parent_oid); } +const git_oid *git_commit_parent_oid(git_commit *commit, unsigned int n) +{ + assert(commit); + return git_vector_get(&commit->parent_oids, n); +} diff --git a/vendor/libgit2/src/common.h b/vendor/libgit2/src/common.h index 5ad878e26..f4f11fd2f 100644 --- a/vendor/libgit2/src/common.h +++ b/vendor/libgit2/src/common.h @@ -50,10 +50,14 @@ typedef SSIZE_T ssize_t; #include "git2/common.h" #include "git2/types.h" -#include "util.h" +#include "git2/errors.h" #include "thread-utils.h" #include "bswap.h" #define GIT_PATH_MAX 4096 +extern int git__throw(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3); +extern int git__rethrow(int error, const char *, ...) GIT_FORMAT_PRINTF(2, 3); + +#include "util.h" #endif /* INCLUDE_common_h__ */ diff --git a/vendor/libgit2/src/errors.c b/vendor/libgit2/src/errors.c index f6b964837..bf3810174 100644 --- a/vendor/libgit2/src/errors.c +++ b/vendor/libgit2/src/errors.c @@ -1,6 +1,35 @@ +/* + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * In addition to the permissions in the GNU General Public License, + * the authors give you unlimited permission to link the compiled + * version of this file into combinations with other programs, + * and to distribute those combinations without any restriction + * coming from the use of this file. (The General Public License + * restrictions do apply in other respects; for example, they cover + * modification of the file, and distribution when not linked into + * a combined executable.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ #include "common.h" +#include "git2/thread-utils.h" /* for GIT_TLS */ #include "thread-utils.h" /* for GIT_TLS */ +#include + +static GIT_TLS char g_last_error[1024]; + static struct { int num; const char *str; @@ -28,7 +57,10 @@ static struct { {GIT_EINVALIDPATH, "The path is invalid" }, {GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"}, {GIT_EINVALIDREFSTATE, "The state of the reference is not valid"}, - {GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"} + {GIT_ENOTIMPLEMENTED, "This feature has not been implemented yet"}, + {GIT_EEXISTS, "A reference with this name already exists"}, + {GIT_EOVERFLOW, "The given integer literal is too large to be parsed"}, + {GIT_ENOTNUM, "The given literal is not a valid number"}, }; const char *git_strerror(int num) @@ -43,3 +75,38 @@ const char *git_strerror(int num) return "Unknown error"; } + +int git__rethrow(int error, const char *msg, ...) +{ + char new_error[1024]; + char *old_error = NULL; + + va_list va; + + va_start(va, msg); + vsnprintf(new_error, sizeof(new_error), msg, va); + va_end(va); + + old_error = strdup(g_last_error); + snprintf(g_last_error, sizeof(g_last_error), "%s \n - %s", new_error, old_error); + free(old_error); + + return error; +} + +int git__throw(int error, const char *msg, ...) +{ + va_list va; + + va_start(va, msg); + vsnprintf(g_last_error, sizeof(g_last_error), msg, va); + va_end(va); + + return error; +} + +const char *git_lasterror(void) +{ + return g_last_error; +} + diff --git a/vendor/libgit2/src/filebuf.c b/vendor/libgit2/src/filebuf.c index dff9373f6..eb93424ef 100644 --- a/vendor/libgit2/src/filebuf.c +++ b/vendor/libgit2/src/filebuf.c @@ -178,7 +178,7 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags) if (flags & GIT_FILEBUF_DEFLATE_CONTENTS) { /* Initialize the ZLib stream */ - if (deflateInit(&file->zs, Z_DEFAULT_COMPRESSION) != Z_OK) { + if (deflateInit(&file->zs, Z_BEST_SPEED) != Z_OK) { error = GIT_EZLIB; goto cleanup; } diff --git a/vendor/libgit2/src/index.c b/vendor/libgit2/src/index.c index 6a31dd5cb..f643e73fb 100644 --- a/vendor/libgit2/src/index.c +++ b/vendor/libgit2/src/index.c @@ -101,6 +101,7 @@ static int read_tree(git_index *index, const char *buffer, size_t buffer_size); static git_index_tree *read_tree_internal(const char **, const char *, git_index_tree *); static int parse_index(git_index *index, const char *buffer, size_t buffer_size); +static int is_index_extended(git_index *index); static void sort_index(git_index *index); static int write_index(git_index *index, git_filebuf *file); @@ -289,56 +290,12 @@ git_index_entry *git_index_get(git_index *index, int n) return git_vector_get(&index->entries, (unsigned int)n); } -int git_index_add(git_index *index, const char *rel_path, int stage) -{ - git_index_entry entry; - char full_path[GIT_PATH_MAX]; - struct stat st; - int error; - - if (index->repository == NULL) - return GIT_EBAREINDEX; - - git__joinpath(full_path, index->repository->path_workdir, rel_path); - - if (gitfo_exists(full_path) < 0) - return GIT_ENOTFOUND; - - if (gitfo_stat(full_path, &st) < 0) - return GIT_EOSERR; - - if (stage < 0 || stage > 3) - return GIT_ERROR; - - memset(&entry, 0x0, sizeof(git_index_entry)); - - entry.ctime.seconds = (git_time_t)st.st_ctime; - entry.mtime.seconds = (git_time_t)st.st_mtime; - /* entry.mtime.nanoseconds = st.st_mtimensec; */ - /* entry.ctime.nanoseconds = st.st_ctimensec; */ - entry.dev= st.st_rdev; - entry.ino = st.st_ino; - entry.mode = st.st_mode; - entry.uid = st.st_uid; - entry.gid = st.st_gid; - entry.file_size = st.st_size; - - /* write the blob to disk and get the oid */ - if ((error = git_blob_create_fromfile(&entry.oid, index->repository, rel_path)) < GIT_SUCCESS) - return error; - - entry.flags |= (stage << GIT_IDXENTRY_STAGESHIFT); - entry.path = (char *)rel_path; /* do not duplicate; index_insert already does this */ - - return git_index_insert(index, &entry); -} - -void sort_index(git_index *index) +static void sort_index(git_index *index) { git_vector_sort(&index->entries); } -int git_index_insert(git_index *index, const git_index_entry *source_entry) +static int index_insert(git_index *index, const git_index_entry *source_entry, int replace) { git_index_entry *entry; size_t path_length; @@ -374,13 +331,15 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry) /* look if an entry with this path already exists */ position = git_index_find(index, source_entry->path); - /* if no entry exists, add the entry at the end; + /* if no entry exists and replace is not set, + * add the entry at the end; * the index is no longer sorted */ - if (position == GIT_ENOTFOUND) { + if (!replace || position == GIT_ENOTFOUND) { if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; - /* if a previous entry exists, replace it */ + /* if a previous entry exists and replace is set, + * replace it */ } else { git_index_entry **entry_array = (git_index_entry **)index->entries.contents; @@ -393,6 +352,81 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry) return GIT_SUCCESS; } +static int index_init_entry(git_index_entry *entry, git_index *index, const char *rel_path, int stage) +{ + char full_path[GIT_PATH_MAX]; + struct stat st; + int error; + + if (index->repository == NULL) + return GIT_EBAREINDEX; + + git__joinpath(full_path, index->repository->path_workdir, rel_path); + + if (gitfo_exists(full_path) < 0) + return GIT_ENOTFOUND; + + if (gitfo_stat(full_path, &st) < 0) + return GIT_EOSERR; + + if (stage < 0 || stage > 3) + return GIT_ERROR; + + memset(entry, 0x0, sizeof(git_index_entry)); + + entry->ctime.seconds = (git_time_t)st.st_ctime; + entry->mtime.seconds = (git_time_t)st.st_mtime; + /* entry.mtime.nanoseconds = st.st_mtimensec; */ + /* entry.ctime.nanoseconds = st.st_ctimensec; */ + entry->dev= st.st_rdev; + entry->ino = st.st_ino; + entry->mode = st.st_mode; + entry->uid = st.st_uid; + entry->gid = st.st_gid; + entry->file_size = st.st_size; + + /* write the blob to disk and get the oid */ + if ((error = git_blob_create_fromfile(&entry->oid, index->repository, rel_path)) < GIT_SUCCESS) + return error; + + entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT); + entry->path = (char *)rel_path; /* do not duplicate; index_insert already does this */ + return GIT_SUCCESS; +} + +int git_index_add(git_index *index, const char *path, int stage) +{ + int error; + git_index_entry entry; + + if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS) + return error; + + return index_insert(index, &entry, 1); +} + +int git_index_append(git_index *index, const char *path, int stage) +{ + int error; + git_index_entry entry; + + if ((error = index_init_entry(&entry, index, path, stage)) < GIT_SUCCESS) + return error; + + return index_insert(index, &entry, 0); +} + +int git_index_add2(git_index *index, const git_index_entry *source_entry) +{ + return index_insert(index, source_entry, 1); +} + +int git_index_append2(git_index *index, const git_index_entry *source_entry) +{ + return index_insert(index, source_entry, 0); +} + + int git_index_remove(git_index *index, int position) { assert(index); @@ -411,6 +445,7 @@ static git_index_tree *read_tree_internal( { git_index_tree *tree; const char *name_start, *buffer; + long count; if ((tree = git__malloc(sizeof(git_index_tree))) == NULL) return NULL; @@ -429,12 +464,22 @@ static git_index_tree *read_tree_internal( goto error_cleanup; /* Blank-terminated ASCII decimal number of entries in this tree */ - tree->entries = strtol(buffer, (char **)&buffer, 10); + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || + count < 0) + goto error_cleanup; + + tree->entries = (size_t)count; + if (*buffer != ' ' || ++buffer >= buffer_end) goto error_cleanup; /* Number of children of the tree, newline-terminated */ - tree->children_count = strtol(buffer, (char **)&buffer, 10); + if (git__strtol32(&count, buffer, &buffer, 10) < GIT_SUCCESS || + count < 0) + goto error_cleanup; + + tree->children_count = (size_t)count; + if (*buffer != '\n' || ++buffer >= buffer_end) goto error_cleanup; @@ -674,6 +719,24 @@ static int parse_index(git_index *index, const char *buffer, size_t buffer_size) return GIT_SUCCESS; } +static int is_index_extended(git_index *index) +{ + unsigned int i, extended; + + extended = 0; + + for (i = 0; i < index->entries.length; ++i) { + git_index_entry *entry; + entry = git_vector_get(&index->entries, i); + entry->flags &= ~GIT_IDXENTRY_EXTENDED; + if (entry->flags_extended & GIT_IDXENTRY_EXTENDED_FLAGS) { + extended++; + entry->flags |= GIT_IDXENTRY_EXTENDED; + } + } + return extended; +} + static int write_disk_entry(git_filebuf *file, git_index_entry *entry) { struct entry_short *ondisk; @@ -742,12 +805,14 @@ static int write_index(git_index *index, git_filebuf *file) struct index_header header; - int is_extended = 1; + int is_extended; assert(index && file); + is_extended = is_index_extended(index); + header.signature = htonl(INDEX_HEADER_SIG); - header.version = htonl(is_extended ? INDEX_VERSION_NUMBER : INDEX_VERSION_NUMBER_EXT); + header.version = htonl(is_extended ? INDEX_VERSION_NUMBER_EXT : INDEX_VERSION_NUMBER); header.entry_count = htonl(index->entries.length); git_filebuf_write(file, &header, sizeof(struct index_header)); diff --git a/vendor/libgit2/src/odb.c b/vendor/libgit2/src/odb.c index 33d5468d9..e9e495eb1 100644 --- a/vendor/libgit2/src/odb.c +++ b/vendor/libgit2/src/odb.c @@ -149,6 +149,69 @@ int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type) return git_odb__hash_obj(id, hdr, sizeof(hdr), &hdrlen, &raw); } +/** + * FAKE WSTREAM + */ + +typedef struct { + git_odb_stream stream; + char *buffer; + size_t size, written; + git_otype type; +} fake_wstream; + +static int fake_wstream__fwrite(git_oid *oid, git_odb_stream *_stream) +{ + fake_wstream *stream = (fake_wstream *)_stream; + return _stream->backend->write(oid, _stream->backend, stream->buffer, stream->size, stream->type); +} + +static int fake_wstream__write(git_odb_stream *_stream, const char *data, size_t len) +{ + fake_wstream *stream = (fake_wstream *)_stream; + + if (stream->written + len >= stream->size) + return GIT_ENOMEM; + + memcpy(stream->buffer + stream->written, data, len); + stream->written += len; + return GIT_SUCCESS; +} + +static void fake_wstream__free(git_odb_stream *_stream) +{ + fake_wstream *stream = (fake_wstream *)_stream; + + free(stream->buffer); + free(stream); +} + +static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, size_t size, git_otype type) +{ + fake_wstream *stream; + + stream = git__calloc(1, sizeof(fake_wstream)); + if (stream == NULL) + return GIT_ENOMEM; + + stream->size = size; + stream->type = type; + stream->buffer = git__malloc(size); + if (stream->buffer == NULL) { + free(stream); + return GIT_ENOMEM; + } + + stream->stream.backend = backend; + stream->stream.read = NULL; /* read only */ + stream->stream.write = &fake_wstream__write; + stream->stream.finalize_write = &fake_wstream__fwrite; + stream->stream.free = &fake_wstream__free; + stream->stream.mode = GIT_STREAM_WRONLY; + + *stream_p = (git_odb_stream *)stream; + return GIT_SUCCESS; +} /*********************************************************** * @@ -158,7 +221,7 @@ int git_odb_hash(git_oid *id, const void *data, size_t len, git_otype type) * ***********************************************************/ -int backend_sort_cmp(const void *a, const void *b) +static int backend_sort_cmp(const void *a, const void *b) { const backend_internal *backend_a = *(const backend_internal **)(a); const backend_internal *backend_b = *(const backend_internal **)(b); @@ -467,6 +530,8 @@ int git_odb_open_wstream(git_odb_stream **stream, git_odb *db, size_t size, git_ if (b->writestream != NULL) error = b->writestream(stream, b, size, type); + else if (b->write != NULL) + error = init_fake_wstream(stream, b, size, type); } return error; diff --git a/vendor/libgit2/src/odb_loose.c b/vendor/libgit2/src/odb_loose.c index 8ee01cd2c..873dbfa0a 100644 --- a/vendor/libgit2/src/odb_loose.c +++ b/vendor/libgit2/src/odb_loose.c @@ -336,7 +336,6 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj) { unsigned char head[64], *buf; z_stream zs; - int z_status; obj_hdr hdr; size_t used; @@ -350,7 +349,7 @@ static int inflate_disk_obj(git_rawobj *out, gitfo_buf *obj) * inflate the initial part of the io buffer in order * to parse the object header (type and size). */ - if ((z_status = start_inflate(&zs, obj, head, sizeof(head))) < Z_OK) + if (start_inflate(&zs, obj, head, sizeof(head)) < Z_OK) return GIT_ERROR; if ((used = get_object_header(&hdr, head)) == 0) @@ -434,6 +433,9 @@ static int read_header_loose(git_rawobj *out, const char *loc) if ((read_bytes = read(fd, raw_buffer, sizeof(raw_buffer))) > 0) { set_stream_input(&zs, raw_buffer, read_bytes); z_return = inflate(&zs, 0); + } else { + z_return = Z_STREAM_END; + break; } } while (z_return == Z_OK); diff --git a/vendor/libgit2/src/odb_pack.c b/vendor/libgit2/src/odb_pack.c index 8c527bcf3..57ad5e34b 100644 --- a/vendor/libgit2/src/odb_pack.c +++ b/vendor/libgit2/src/odb_pack.c @@ -108,15 +108,12 @@ struct pack_entry { struct pack_file *p; }; -struct pack__dirent { - struct pack_backend *backend; - int is_pack_local; -}; - struct pack_backend { git_odb_backend parent; git_vector packs; struct pack_file *last_found; + char *pack_folder; + time_t pack_folder_mtime; size_t window_size; /* needs default value */ @@ -259,9 +256,9 @@ static int pack_index_open(struct pack_file *p); static struct pack_file *packfile_alloc(int extra); static int packfile_open(struct pack_file *p); -static int packfile_check(struct pack_file **pack_out, const char *path, int local); +static int packfile_check(struct pack_file **pack_out, const char *path); static int packfile_load__cb(void *_data, char *path); -static int packfile_load_all(struct pack_backend *backend, const char *odb_path, int local); +static int packfile_refresh_all(struct pack_backend *backend); static off_t nth_packed_object_offset(const struct pack_file *p, uint32_t n); @@ -790,7 +787,7 @@ static int packfile_open(struct pack_file *p) return GIT_EPACKCORRUPTED; } -static int packfile_check(struct pack_file **pack_out, const char *path, int local) +static int packfile_check(struct pack_file **pack_out, const char *path) { struct stat st; struct pack_file *p; @@ -826,7 +823,7 @@ static int packfile_check(struct pack_file **pack_out, const char *path, int loc * actually mapping the pack file. */ p->pack_size = (off_t)st.st_size; - p->pack_local = local; + p->pack_local = 1; p->mtime = (git_time_t)st.st_mtime; /* see if we can parse the sha1 oid in the packfile name */ @@ -840,22 +837,25 @@ static int packfile_check(struct pack_file **pack_out, const char *path, int loc static int packfile_load__cb(void *_data, char *path) { - struct pack__dirent *data = (struct pack__dirent *)_data; + struct pack_backend *backend = (struct pack_backend *)_data; struct pack_file *pack; int error; + size_t i; if (git__suffixcmp(path, ".idx") != 0) return GIT_SUCCESS; /* not an index */ - /* FIXME: git.git checks for duplicate packs. - * But that makes no fucking sense. Our dirent is not - * going to generate dupicate entries */ + for (i = 0; i < backend->packs.length; ++i) { + struct pack_file *p = git_vector_get(&backend->packs, i); + if (memcmp(p->pack_name, path, strlen(path) - STRLEN(".idx")) == 0) + return GIT_SUCCESS; + } - error = packfile_check(&pack, path, data->is_pack_local); + error = packfile_check(&pack, path); if (error < GIT_SUCCESS) return error; - if (git_vector_insert(&data->backend->packs, pack) < GIT_SUCCESS) { + if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) { free(pack); return GIT_ENOMEM; } @@ -863,25 +863,29 @@ static int packfile_load__cb(void *_data, char *path) return GIT_SUCCESS; } -static int packfile_load_all(struct pack_backend *backend, const char *odb_path, int local) +static int packfile_refresh_all(struct pack_backend *backend) { int error; - char path[GIT_PATH_MAX]; - struct pack__dirent data; - - data.backend = backend; - data.is_pack_local = local; + struct stat st; - git__joinpath(path, odb_path, "pack"); - if (gitfo_isdir(path) < GIT_SUCCESS) + if (backend->pack_folder == NULL) return GIT_SUCCESS; - error = gitfo_dirent(path, GIT_PATH_MAX, packfile_load__cb, (void *)&data); - if (error < GIT_SUCCESS) - return error; + if (gitfo_stat(backend->pack_folder, &st) < 0 || !S_ISDIR(st.st_mode)) + return GIT_ENOTFOUND; - git_vector_sort(&backend->packs); - backend->last_found = git_vector_get(&backend->packs, 0); + if (st.st_mtime != backend->pack_folder_mtime) { + char path[GIT_PATH_MAX]; + strcpy(path, backend->pack_folder); + + /* reload all packs */ + error = gitfo_dirent(path, GIT_PATH_MAX, packfile_load__cb, (void *)backend); + if (error < GIT_SUCCESS) + return error; + + git_vector_sort(&backend->packs); + backend->pack_folder_mtime = st.st_mtime; + } return GIT_SUCCESS; } @@ -1026,8 +1030,12 @@ static int pack_entry_find1( static int pack_entry_find(struct pack_entry *e, struct pack_backend *backend, const git_oid *oid) { + int error; size_t i; + if ((error = packfile_refresh_all(backend)) < GIT_SUCCESS) + return error; + if (backend->last_found && pack_entry_find1(e, backend->last_found, oid) == GIT_SUCCESS) return GIT_SUCCESS; @@ -1377,13 +1385,14 @@ void pack_backend__free(git_odb_backend *_backend) } git_vector_free(&backend->packs); + free(backend->pack_folder); free(backend); } int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) { - int error; struct pack_backend *backend; + char path[GIT_PATH_MAX]; backend = git__calloc(1, sizeof(struct pack_backend)); if (backend == NULL) @@ -1397,10 +1406,15 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->window_size = DEFAULT_WINDOW_SIZE; backend->mapped_limit = DEFAULT_MAPPED_LIMIT; - error = packfile_load_all(backend, objects_dir, 1); - if (error < GIT_SUCCESS) { - pack_backend__free((git_odb_backend *)backend); - return error; + git__joinpath(path, objects_dir, "pack"); + if (gitfo_isdir(path) == GIT_SUCCESS) { + backend->pack_folder = git__strdup(path); + backend->pack_folder_mtime = 0; + + if (backend->pack_folder == NULL) { + free(backend); + return GIT_ENOMEM; + } } backend->parent.read = &pack_backend__read; diff --git a/vendor/libgit2/src/oid.c b/vendor/libgit2/src/oid.c index eb167a685..86c1e0039 100644 --- a/vendor/libgit2/src/oid.c +++ b/vendor/libgit2/src/oid.c @@ -118,13 +118,13 @@ char *git_oid_to_string(char *out, size_t n, const git_oid *oid) return out; } -int git__parse_oid(git_oid *oid, char **buffer_out, +int git__parse_oid(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header) { const size_t sha_len = GIT_OID_HEXSZ; const size_t header_len = strlen(header); - char *buffer = *buffer_out; + const char *buffer = *buffer_out; if (buffer + (header_len + sha_len + 1) > buffer_end) return GIT_EOBJCORRUPTED; diff --git a/vendor/libgit2/src/refs.c b/vendor/libgit2/src/refs.c index 16bd74149..c4d3d6ae6 100644 --- a/vendor/libgit2/src/refs.c +++ b/vendor/libgit2/src/refs.c @@ -79,6 +79,11 @@ static int packed_remove_loose(git_repository *repo, git_vector *packing_list); static int packed_sort(const void *a, const void *b); static int packed_write(git_repository *repo); +/* internal helpers */ +static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force); +static int reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force); +static int reference_rename(git_reference *ref, const char *new_name, int force); + /* name normalization */ static int check_valid_ref_char(char ch); static int normalize_name(char *buffer_out, const char *name, int is_oid_ref); @@ -117,7 +122,8 @@ static int reference_create( else if (type == GIT_REF_OID) size = sizeof(reference_oid); else - return GIT_EINVALIDREFSTATE; + return git__throw(GIT_EINVALIDARGS, + "Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier"); reference = git__malloc(size); if (reference == NULL) @@ -154,11 +160,9 @@ static int reference_read(gitfo_buf *file_content, time_t *mtime, const char *re /* Determine the full path of the file */ git__joinpath(path, repo_path, ref_name); - if (gitfo_stat(path, &st) < 0) - return GIT_ENOTFOUND; - - if (S_ISDIR(st.st_mode)) - return GIT_EOBJCORRUPTED; + if (gitfo_stat(path, &st) < 0 || S_ISDIR(st.st_mode)) + return git__throw(GIT_ENOTFOUND, + "Cannot read reference file '%s'", ref_name); if (mtime) *mtime = st.st_mtime; @@ -200,7 +204,8 @@ static int loose_update(git_reference *ref) else if (ref->type == GIT_REF_OID) error = loose_parse_oid(ref, &ref_file); else - error = GIT_EINVALIDREFSTATE; + error = git__throw(GIT_EOBJCORRUPTED, + "Invalid reference type (%d) for loose reference", ref->type); gitfo_free_buf(&ref_file); @@ -224,7 +229,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) ref_sym = (reference_symbolic *)ref; if (file_content->len < (header_len + 1)) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Object too short"); /* * Assume we have already checked for the header @@ -241,7 +247,8 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) /* remove newline at the end of file */ eol = strchr(ref_sym->target, '\n'); if (eol == NULL) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Missing EOL"); *eol = '\0'; if (eol[-1] == '\r') @@ -252,6 +259,7 @@ static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content) { + int error; reference_oid *ref_oid; char *buffer; @@ -260,17 +268,19 @@ static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content) /* File format: 40 chars (OID) + newline */ if (file_content->len < GIT_OID_HEXSZ + 1) - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Reference too short"); - if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS) - return GIT_EREFCORRUPTED; + if ((error = git_oid_mkstr(&ref_oid->oid, buffer)) < GIT_SUCCESS) + return git__rethrow(GIT_EOBJCORRUPTED, "Failed to parse loose reference."); buffer = buffer + GIT_OID_HEXSZ; if (*buffer == '\r') buffer++; if (*buffer != '\n') - return GIT_EREFCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, + "Failed to parse loose reference. Missing EOL"); return GIT_SUCCESS; } @@ -382,7 +392,7 @@ static int loose_write(git_reference *ref) strcpy(ref_contents, GIT_SYMREF); strcat(ref_contents, ref_sym->target); } else { - error = GIT_EINVALIDREFSTATE; + error = git__throw(GIT_EOBJCORRUPTED, "Failed to write reference. Invalid reference type"); goto unlock; } @@ -679,7 +689,7 @@ static int packed_loadloose(git_repository *repository) /* Remove any loose references from the cache */ { - const void *_unused; + const void *GIT_UNUSED(_unused); git_reference *reference; GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference, @@ -741,7 +751,7 @@ static int packed_write_ref(reference_oid *ref, git_filebuf *file) */ static int packed_find_peel(reference_oid *ref) { - git_tag *tag; + git_object *object; int error; if (ref->ref.type & GIT_REF_HAS_PEEL) @@ -755,25 +765,34 @@ static int packed_find_peel(reference_oid *ref) return GIT_SUCCESS; /* - * Find the tag in the repository. The tag must exist, - * otherwise this reference is broken and we shouldn't - * pack it. + * Find the tagged object in the repository */ - error = git_tag_lookup(&tag, ref->ref.owner, &ref->oid); + error = git_object_lookup(&object, ref->ref.owner, &ref->oid, GIT_OBJ_ANY); if (error < GIT_SUCCESS) return GIT_EOBJCORRUPTED; /* - * Find the object pointed at by this tag + * If the tagged object is a Tag object, we need to resolve it; + * if the ref is actually a 'weak' ref, we don't need to resolve + * anything. */ - git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); - ref->ref.type |= GIT_REF_HAS_PEEL; + if (git_object_type(object) == GIT_OBJ_TAG) { + git_tag *tag = (git_tag *)object; - /* - * The reference has now cached the resolved OID, and is - * marked at such. When written to the packfile, it'll be - * accompanied by this resolved oid - */ + /* + * Find the object pointed at by this tag + */ + git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag)); + ref->ref.type |= GIT_REF_HAS_PEEL; + + /* + * The reference has now cached the resolved OID, and is + * marked at such. When written to the packfile, it'll be + * accompanied by this resolved oid + */ + } + + git_object_close(object); return GIT_SUCCESS; } @@ -856,7 +875,7 @@ static int packed_write(git_repository *repo) /* Load all the packfile into a vector */ { git_reference *reference; - const void *_unused; + const void *GIT_UNUSED(_unused); GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference, git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */ @@ -915,8 +934,240 @@ static int packed_write(git_repository *repo) return error; } +/***************************************** + * Internal methods - reference creation + *****************************************/ + +static int reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force) +{ + char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + int error = GIT_SUCCESS, updated = 0; + git_reference *ref = NULL, *old_ref = NULL; + + if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) + return GIT_EEXISTS; + + /* + * If they old ref was of the same type, then we can just update + * it (once we've checked that the target is valid). Otherwise we + * need a new reference because we can't make a symbolic ref out + * of an oid one. + * If if didn't exist, then we need to create a new one anyway. + */ + if (ref && ref->type & GIT_REF_SYMBOLIC){ + updated = 1; + } else { + ref = NULL; + error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC); + if (error < GIT_SUCCESS) + goto cleanup; + } + + /* The target can aither be the name of an object id reference or the name of another symbolic reference */ + error = normalize_name(normalized, target, 0); + if (error < GIT_SUCCESS) + goto cleanup; + + /* set the target; this will write the reference on disk */ + error = git_reference_set_target(ref, normalized); + if (error < GIT_SUCCESS) + goto cleanup; + + /* + * If we didn't update the ref, then we need to insert or replace + * it in the loose cache. If we replaced a ref, free it. + */ + if (!updated){ + error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref); + if (error < GIT_SUCCESS) + goto cleanup; + + if(old_ref) + reference_free(old_ref); + } + + *ref_out = ref; + + return error; + +cleanup: + reference_free(ref); + return error; +} + +static int reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force) +{ + int error = GIT_SUCCESS, updated = 0; + git_reference *ref = NULL, *old_ref = NULL; + + if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force) + return GIT_EEXISTS; + + /* + * If they old ref was of the same type, then we can just update + * it (once we've checked that the target is valid). Otherwise we + * need a new reference because we can't make a symbolic ref out + * of an oid one. + * If if didn't exist, then we need to create a new one anyway. + */ + if (ref && ref-> type & GIT_REF_OID){ + updated = 1; + } else { + ref = NULL; + error = reference_create(&ref, repo, name, GIT_REF_OID); + if (error < GIT_SUCCESS) + goto cleanup; + } + + /* set the oid; this will write the reference on disk */ + error = git_reference_set_oid(ref, id); + if (error < GIT_SUCCESS) + goto cleanup; + + if(!updated){ + error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, (void **) &old_ref); + if (error < GIT_SUCCESS) + goto cleanup; + + if(old_ref) + reference_free(old_ref); + } + + *ref_out = ref; + + return error; + +cleanup: + reference_free(ref); + return error; +} + +/* + * Rename a reference + * + * If the reference is packed, we need to rewrite the + * packfile to remove the reference from it and create + * the reference back as a loose one. + * + * If the reference is loose, we just rename it on + * the filesystem. + * + * We also need to re-insert the reference on its corresponding + * in-memory cache, since the caches are indexed by refname. + */ +static int reference_rename(git_reference *ref, const char *new_name, int force) +{ + int error; + char *old_name; + char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + git_reference *looked_up_ref, *old_ref = NULL; + + assert(ref); + + /* Ensure the name is valid */ + error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID); + if (error < GIT_SUCCESS) + return error; + + /* Ensure we're not going to overwrite an existing reference + unless the user has allowed us */ + error = git_reference_lookup(&looked_up_ref, ref->owner, new_name); + if (error == GIT_SUCCESS && !force) + return GIT_EEXISTS; + + if (error < GIT_SUCCESS && + error != GIT_ENOTFOUND) + return error; + old_name = ref->name; + ref->name = git__strdup(new_name); + + if (ref->name == NULL) { + ref->name = old_name; + return GIT_ENOMEM; + } + + if (ref->type & GIT_REF_PACKED) { + /* write the packfile to disk; note + * that the state of the in-memory cache is not + * consistent, because the reference is indexed + * by its old name but it already has the new one. + * This doesn't affect writing, though, and allows + * us to rollback if writing fails + */ + + ref->type &= ~GIT_REF_PACKED; + + /* Create the loose ref under its new name */ + error = loose_write(ref); + if (error < GIT_SUCCESS) { + ref->type |= GIT_REF_PACKED; + goto cleanup; + } + + /* Remove from the packfile cache in order to avoid packing it back + * Note : we do not rely on git_reference_delete() because this would + * invalidate the reference. + */ + git_hashtable_remove(ref->owner->references.packfile, old_name); + + /* Recreate the packed-refs file without the reference */ + error = packed_write(ref->owner); + if (error < GIT_SUCCESS) + goto rename_loose_to_old_name; + + } else { + git__joinpath(old_path, ref->owner->path_repository, old_name); + git__joinpath(new_path, ref->owner->path_repository, ref->name); + + error = gitfo_mv_force(old_path, new_path); + if (error < GIT_SUCCESS) + goto cleanup; + + /* Once succesfully renamed, remove from the cache the reference known by its old name*/ + git_hashtable_remove(ref->owner->references.loose_cache, old_name); + } + + /* Store the renamed reference into the loose ref cache */ + error = git_hashtable_insert2(ref->owner->references.loose_cache, ref->name, ref, (void **) &old_ref); + + /* If we force-replaced, we need to free the old reference */ + if(old_ref) + reference_free(old_ref); + + free(old_name); + return error; + +cleanup: + /* restore the old name if this failed */ + free(ref->name); + ref->name = old_name; + return error; + +rename_loose_to_old_name: + /* If we hit this point. Something *bad* happened! Think "Ghostbusters + * crossing the streams" definition of bad. + * Either the packed-refs has been correctly generated and something else + * has gone wrong, or the writing of the new packed-refs has failed, and + * we're stuck with the old one. As a loose ref always takes priority over + * a packed ref, we'll eventually try and rename the generated loose ref to + * its former name. It even that fails, well... we might have lost the reference + * for good. :-/ + */ + + git__joinpath(old_path, ref->owner->path_repository, ref->name); + git__joinpath(new_path, ref->owner->path_repository, old_name); + + /* No error checking. We'll return the initial error */ + gitfo_mv_force(old_path, new_path); + + /* restore the old name */ + free(ref->name); + ref->name = old_name; + + return error; +} /***************************************** * External Library API @@ -975,64 +1226,23 @@ int git_reference_lookup(git_reference **ref_out, git_repository *repo, const ch int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target) { - char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; - int error = GIT_SUCCESS; - git_reference *ref = NULL; - - error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC); - if (error < GIT_SUCCESS) - goto cleanup; - - /* The target can aither be the name of an object id reference or the name of another symbolic reference */ - error = normalize_name(normalized, target, 0); - if (error < GIT_SUCCESS) - goto cleanup; - - /* set the target; this will write the reference on disk */ - error = git_reference_set_target(ref, normalized); - if (error < GIT_SUCCESS) - goto cleanup; - - error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref); - if (error < GIT_SUCCESS) - goto cleanup; - - *ref_out = ref; - - return error; + return reference_create_symbolic(ref_out, repo, name, target, 0); +} -cleanup: - reference_free(ref); - return error; +int git_reference_create_symbolic_f(git_reference **ref_out, git_repository *repo, const char *name, const char *target) +{ + return reference_create_symbolic(ref_out, repo, name, target, 1); } int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id) { - int error = GIT_SUCCESS; - git_reference *ref = NULL; - - error = reference_create(&ref, repo, name, GIT_REF_OID); - if (error < GIT_SUCCESS) - goto cleanup; - - /* set the oid; this will write the reference on disk */ - error = git_reference_set_oid(ref, id); - if (error < GIT_SUCCESS) - goto cleanup; - - error = git_hashtable_insert(repo->references.loose_cache, ref->name, ref); - if (error < GIT_SUCCESS) - goto cleanup; - - *ref_out = ref; - - return error; - -cleanup: - reference_free(ref); - return error; + return reference_create_oid(ref_out, repo, name, id, 0); } +int git_reference_create_oid_f(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id) +{ + return reference_create_oid(ref_out, repo, name, id, 1); +} /** * Getters @@ -1123,6 +1333,13 @@ int git_reference_set_oid(git_reference *ref, const git_oid *id) ref_oid = (reference_oid *)ref; + assert(ref->owner); + + /* Don't let the user create references to OIDs that + * don't exist in the ODB */ + if (!git_odb_exists(git_repository_database(ref->owner), id)) + return GIT_ENOTFOUND; + /* duplicate the reference; * this copy will stay on the packfile cache */ if (ref->type & GIT_REF_PACKED) { @@ -1216,6 +1433,10 @@ int git_reference_delete(git_reference *ref) assert(ref); if (ref->type & GIT_REF_PACKED) { + /* load the existing packfile */ + if ((error = packed_load(ref->owner)) < GIT_SUCCESS) + return error; + git_hashtable_remove(ref->owner->references.packfile, ref->name); error = packed_write(ref->owner); } else { @@ -1240,125 +1461,14 @@ int git_reference_delete(git_reference *ref) return error; } -/* - * Rename a reference - * - * If the reference is packed, we need to rewrite the - * packfile to remove the reference from it and create - * the reference back as a loose one. - * - * If the reference is loose, we just rename it on - * the filesystem. - * - * We also need to re-insert the reference on its corresponding - * in-memory cache, since the caches are indexed by refname. - */ int git_reference_rename(git_reference *ref, const char *new_name) { - int error; - char *old_name; - char old_path[GIT_PATH_MAX], new_path[GIT_PATH_MAX], normalized_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; - git_reference *looked_up_ref; - - assert(ref); - - /* Ensure the name is valid */ - error = normalize_name(normalized_name, new_name, ref->type & GIT_REF_OID); - if (error < GIT_SUCCESS) - return error; - - /* Ensure we're not going to overwrite an existing reference */ - error = git_reference_lookup(&looked_up_ref, ref->owner, new_name); - if (error == GIT_SUCCESS) - return GIT_EINVALIDREFNAME; - - if (error != GIT_ENOTFOUND) - return error; - - - old_name = ref->name; - ref->name = git__strdup(new_name); - - if (ref->name == NULL) { - ref->name = old_name; - return GIT_ENOMEM; - } - - if (ref->type & GIT_REF_PACKED) { - /* write the packfile to disk; note - * that the state of the in-memory cache is not - * consistent, because the reference is indexed - * by its old name but it already has the new one. - * This doesn't affect writing, though, and allows - * us to rollback if writing fails - */ - - ref->type &= ~GIT_REF_PACKED; - - /* Create the loose ref under its new name */ - error = loose_write(ref); - if (error < GIT_SUCCESS) { - ref->type |= GIT_REF_PACKED; - goto cleanup; - } - - /* Remove from the packfile cache in order to avoid packing it back - * Note : we do not rely on git_reference_delete() because this would - * invalidate the reference. - */ - git_hashtable_remove(ref->owner->references.packfile, old_name); - - /* Recreate the packed-refs file without the reference */ - error = packed_write(ref->owner); - if (error < GIT_SUCCESS) - goto rename_loose_to_old_name; - - } else { - git__joinpath(old_path, ref->owner->path_repository, old_name); - git__joinpath(new_path, ref->owner->path_repository, ref->name); - - error = gitfo_mv_force(old_path, new_path); - if (error < GIT_SUCCESS) - goto cleanup; - - /* Once succesfully renamed, remove from the cache the reference known by its old name*/ - git_hashtable_remove(ref->owner->references.loose_cache, old_name); - } - - /* Store the renamed reference into the loose ref cache */ - error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref); - - free(old_name); - return error; - -cleanup: - /* restore the old name if this failed */ - free(ref->name); - ref->name = old_name; - return error; - -rename_loose_to_old_name: - /* If we hit this point. Something *bad* happened! Think "Ghostbusters - * crossing the streams" definition of bad. - * Either the packed-refs has been correctly generated and something else - * has gone wrong, or the writing of the new packed-refs has failed, and - * we're stuck with the old one. As a loose ref always takes priority over - * a packed ref, we'll eventually try and rename the generated loose ref to - * its former name. It even that fails, well... we might have lost the reference - * for good. :-/ - */ - - git__joinpath(old_path, ref->owner->path_repository, ref->name); - git__joinpath(new_path, ref->owner->path_repository, old_name); - - /* No error checking. We'll return the initial error */ - gitfo_mv_force(old_path, new_path); - - /* restore the old name */ - free(ref->name); - ref->name = old_name; + return reference_rename(ref, new_name, 0); +} - return error; +int git_reference_rename_f(git_reference *ref, const char *new_name) +{ + return reference_rename(ref, new_name, 1); } int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) @@ -1377,8 +1487,9 @@ int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) for (i = 0; i < MAX_NESTING_LEVEL; ++i) { reference_symbolic *ref_sym; + *resolved_ref = ref; + if (ref->type & GIT_REF_OID) { - *resolved_ref = ref; return GIT_SUCCESS; } @@ -1415,7 +1526,7 @@ int git_reference_listcb(git_repository *repo, unsigned int list_flags, int (*ca /* list all the packed references first */ if (list_flags & GIT_REF_PACKED) { const char *ref_name; - void *_unused; + void *GIT_UNUSED(_unused); if ((error = packed_load(repo)) < GIT_SUCCESS) return error; @@ -1494,7 +1605,7 @@ int git_repository__refcache_init(git_refcache *refs) void git_repository__refcache_free(git_refcache *refs) { git_reference *reference; - const void *_unused; + const void *GIT_UNUSED(_unused); assert(refs); @@ -1588,8 +1699,10 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) *buffer_out++ = *current++; } - /* Object id refname have to contain at least one slash */ - if (is_oid_ref && !contains_a_slash) + /* Object id refname have to contain at least one slash, except + * for HEAD in a detached state or MERGE_HEAD if we're in the + * middle of a merge */ + if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE))) return GIT_EINVALIDREFNAME; /* A refname can not end with ".lock" */ @@ -1598,9 +1711,13 @@ static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) *buffer_out = '\0'; - /* For object id references, name has to start with refs/(heads|tags|remotes) */ - if (is_oid_ref && !(!git__prefixcmp(buffer_out_start, GIT_REFS_HEADS_DIR) || - !git__prefixcmp(buffer_out_start, GIT_REFS_TAGS_DIR) || !git__prefixcmp(buffer_out_start, GIT_REFS_REMOTES_DIR))) + /* + * For object id references, name has to start with refs/. Again, + * we need to allow HEAD to be in a detached state. + */ + if (is_oid_ref && + !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) || + strcmp(buffer_out_start, GIT_HEAD_FILE))) return GIT_EINVALIDREFNAME; return error; diff --git a/vendor/libgit2/src/refs.h b/vendor/libgit2/src/refs.h index bebb1b97d..b8f3e2f6d 100644 --- a/vendor/libgit2/src/refs.h +++ b/vendor/libgit2/src/refs.h @@ -17,6 +17,7 @@ #define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100 #define GIT_HEAD_FILE "HEAD" +#define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" struct git_reference { diff --git a/vendor/libgit2/src/repository.c b/vendor/libgit2/src/repository.c index 91b95a881..8cc2644ca 100644 --- a/vendor/libgit2/src/repository.c +++ b/vendor/libgit2/src/repository.c @@ -58,7 +58,6 @@ static int assign_repository_dirs( const char *git_work_tree) { char path_aux[GIT_PATH_MAX]; - size_t git_dir_path_len; int error = GIT_SUCCESS; assert(repo); @@ -70,8 +69,6 @@ static int assign_repository_dirs( if (error < GIT_SUCCESS) return error; - git_dir_path_len = strlen(path_aux); - /* store GIT_DIR */ repo->path_repository = git__strdup(path_aux); if (repo->path_repository == NULL) @@ -346,7 +343,7 @@ static int repo_init_reinit(repo_init *results) { /* TODO: reinit the repository */ results->has_been_reinit = 1; - return GIT_SUCCESS; + return GIT_ENOTIMPLEMENTED; } static int repo_init_createhead(git_repository *repo) @@ -473,3 +470,29 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is return error; } +int git_repository_is_empty(git_repository *repo) +{ + git_reference *head, *branch; + int error; + + error = git_reference_lookup(&head, repo, "HEAD"); + if (error < GIT_SUCCESS) + return error; + + if (git_reference_type(head) != GIT_REF_SYMBOLIC) + return GIT_EOBJCORRUPTED; + + return git_reference_resolve(&branch, head) == GIT_SUCCESS ? 0 : 1; +} + +const char *git_repository_path(git_repository *repo) +{ + assert(repo); + return repo->path_repository; +} + +const char *git_repository_workdir(git_repository *repo) +{ + assert(repo); + return repo->path_workdir; +} diff --git a/vendor/libgit2/src/repository.h b/vendor/libgit2/src/repository.h index fef1c7da0..813cac942 100644 --- a/vendor/libgit2/src/repository.h +++ b/vendor/libgit2/src/repository.h @@ -43,7 +43,7 @@ struct git_repository { * export */ void git_object__free(void *object); -int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); +int git__parse_oid(git_oid *oid, const char **buffer_out, const char *buffer_end, const char *header); int git__write_oid(git_odb_stream *src, const char *header, const git_oid *oid); #endif diff --git a/vendor/libgit2/src/revwalk.c b/vendor/libgit2/src/revwalk.c index 73bb060f5..78798480f 100644 --- a/vendor/libgit2/src/revwalk.c +++ b/vendor/libgit2/src/revwalk.c @@ -191,6 +191,7 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo unsigned char *parents_start; int i, parents = 0; + long commit_time; buffer += STRLEN("tree ") + GIT_OID_HEXSZ + 1; @@ -227,10 +228,10 @@ static int commit_quick_parse(git_revwalk *walk, commit_object *commit, git_rawo if (buffer == NULL) return GIT_EOBJCORRUPTED; - commit->time = strtol((char *)buffer + 2, NULL, 10); - if (commit->time == 0) + if (git__strtol32(&commit_time, (char *)buffer + 2, NULL, 10) < GIT_SUCCESS) return GIT_EOBJCORRUPTED; + commit->time = (time_t)commit_time; commit->parsed = 1; return GIT_SUCCESS; } @@ -482,7 +483,7 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) void git_revwalk_free(git_revwalk *walk) { unsigned int i; - const void *_unused; + const void *GIT_UNUSED(_unused); commit_object *commit; if (walk == NULL) @@ -557,7 +558,7 @@ int git_revwalk_next(git_oid *oid, git_revwalk *walk) void git_revwalk_reset(git_revwalk *walk) { - const void *_unused; + const void *GIT_UNUSED(_unused); commit_object *commit; assert(walk); diff --git a/vendor/libgit2/src/signature.c b/vendor/libgit2/src/signature.c index 412637600..62bd28b9a 100644 --- a/vendor/libgit2/src/signature.c +++ b/vendor/libgit2/src/signature.c @@ -65,14 +65,47 @@ git_signature *git_signature_dup(const git_signature *sig) return git_signature_new(sig->name, sig->email, sig->when.time, sig->when.offset); } +git_signature *git_signature_now(const char *name, const char *email) +{ + time_t now; + time_t offset; + struct tm *utc_tm, *local_tm; + +#ifndef GIT_WIN32 + struct tm _utc, _local; +#endif + + time(&now); + + /** + * On Win32, `gmtime_r` doesn't exist but + * `gmtime` is threadsafe, so we can use that + */ +#ifdef GIT_WIN32 + utc_tm = gmtime(&now); + local_tm = localtime(&now); +#else + utc_tm = gmtime_r(&now, &_utc); + local_tm = localtime_r(&now, &_local); +#endif + + offset = mktime(local_tm) - mktime(utc_tm); + offset /= 60; + + /* mktime takes care of setting tm_isdst correctly */ + if (local_tm->tm_isdst) + offset += 60; + + return git_signature_new(name, email, now, (int)offset); +} -static int parse_timezone_offset(const char *buffer, int *offset_out) +static int parse_timezone_offset(const char *buffer, long *offset_out) { - int offset, dec_offset; + long offset, dec_offset; int mins, hours; - const char* offset_start; - char* offset_end; + const char *offset_start; + const char *offset_end; offset_start = buffer + 1; @@ -82,21 +115,22 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) } if (offset_start[0] != '-' && offset_start[0] != '+') - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It doesn't start with '+' or '-'"); - dec_offset = strtol(offset_start + 1, &offset_end, 10); + if (git__strtol32(&dec_offset, offset_start + 1, &offset_end, 10) < GIT_SUCCESS) + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. It isn't a number"); if (offset_end - offset_start != 5) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Invalid length"); hours = dec_offset / 100; mins = dec_offset % 100; if (hours > 14) // see http://www.worldtimezone.com/faq.html - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Hour value too large");; if (mins > 59) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse TZ offset. Minute value too large"); offset = (hours * 60) + mins; @@ -109,60 +143,66 @@ static int parse_timezone_offset(const char *buffer, int *offset_out) } -int git_signature__parse(git_signature *sig, char **buffer_out, +int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header) { const size_t header_len = strlen(header); int name_length, email_length; - char *buffer = *buffer_out; - char *line_end, *name_end, *email_end; - int offset = 0; + const char *buffer = *buffer_out; + const char *line_end, *name_end, *email_end; + long offset = 0, time; memset(sig, 0x0, sizeof(git_signature)); line_end = memchr(buffer, '\n', buffer_end - buffer); if (!line_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. No newline found");; if (buffer + (header_len + 1) > line_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Signature too short"); if (memcmp(buffer, header, header_len) != 0) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Expected prefix '%s' doesn't match actual", header); buffer += header_len; /* Parse name */ if ((name_end = memchr(buffer, '<', buffer_end - buffer)) == NULL) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail start"); name_length = name_end - buffer - 1; sig->name = git__malloc(name_length + 1); + if (sig->name == NULL) + return GIT_ENOMEM; + memcpy(sig->name, buffer, name_length); sig->name[name_length] = 0; buffer = name_end + 1; if (buffer >= line_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly"); /* Parse email */ if ((email_end = memchr(buffer, '>', buffer_end - buffer)) == NULL) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Can't find e-mail end"); email_length = email_end - buffer; sig->email = git__malloc(email_length + 1); + if (sig->name == NULL) + return GIT_ENOMEM; + memcpy(sig->email, buffer, email_length); sig->email[email_length] = 0; buffer = email_end + 1; if (buffer >= line_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Ended unexpectedly"); - sig->when.time = strtol(buffer, &buffer, 10); + if (git__strtol32(&time, buffer, &buffer, 10) < GIT_SUCCESS) + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse signature. Timestamp isn't a number"); - if (sig->when.time == 0) - return GIT_EOBJCORRUPTED; + sig->when.time = (time_t)time; if (parse_timezone_offset(buffer, &offset) < GIT_SUCCESS) return GIT_EOBJCORRUPTED; diff --git a/vendor/libgit2/src/signature.h b/vendor/libgit2/src/signature.h index 3534cb21f..feba6578d 100644 --- a/vendor/libgit2/src/signature.h +++ b/vendor/libgit2/src/signature.h @@ -6,7 +6,7 @@ #include "repository.h" #include -int git_signature__parse(git_signature *sig, char **buffer_out, const char *buffer_end, const char *header); +int git_signature__parse(git_signature *sig, const char **buffer_out, const char *buffer_end, const char *header); int git_signature__write(char **signature, const char *header, const git_signature *sig); #endif diff --git a/vendor/libgit2/src/tag.c b/vendor/libgit2/src/tag.c index 7baababbf..849429b7e 100644 --- a/vendor/libgit2/src/tag.c +++ b/vendor/libgit2/src/tag.c @@ -79,7 +79,7 @@ const char *git_tag_message(git_tag *t) return t->message; } -static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) +static int parse_tag_buffer(git_tag *tag, const char *buffer, const char *buffer_end) { static const char *tag_types[] = { NULL, "commit\n", "tree\n", "blob\n", "tag\n" @@ -90,13 +90,13 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) int error; if ((error = git__parse_oid(&tag->target, &buffer, buffer_end, "object ")) < 0) - return error; + return git__rethrow(error, "Failed to parse tag. Object field invalid"); if (buffer + 5 >= buffer_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); if (memcmp(buffer, "type ", 5) != 0) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Type field not found"); buffer += 5; tag->type = GIT_OBJ_BAD; @@ -105,7 +105,7 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) size_t type_length = strlen(tag_types[i]); if (buffer + type_length >= buffer_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); if (memcmp(buffer, tag_types[i], type_length) == 0) { tag->type = i; @@ -115,77 +115,119 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) } if (tag->type == GIT_OBJ_BAD) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Invalid object type"); if (buffer + 4 >= buffer_end) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); if (memcmp(buffer, "tag ", 4) != 0) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Tag field not found"); + buffer += 4; search = memchr(buffer, '\n', buffer_end - buffer); if (search == NULL) - return GIT_EOBJCORRUPTED; + return git__throw(GIT_EOBJCORRUPTED, "Failed to parse tag. Object too short"); text_len = search - buffer; - if (tag->tag_name != NULL) - free(tag->tag_name); - tag->tag_name = git__malloc(text_len + 1); + if (tag->tag_name == NULL) + return GIT_ENOMEM; + memcpy(tag->tag_name, buffer, text_len); tag->tag_name[text_len] = '\0'; buffer = search + 1; tag->tagger = git__malloc(sizeof(git_signature)); + if (tag->tagger == NULL) + return GIT_ENOMEM; - if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) + if ((error = git_signature__parse(tag->tagger, &buffer, buffer_end, "tagger ")) != 0) { + free(tag->tag_name); + git_signature_free(tag->tagger); return error; + } text_len = buffer_end - ++buffer; tag->message = git__malloc(text_len + 1); + if (tag->message == NULL) + return GIT_ENOMEM; + memcpy(tag->message, buffer, text_len); tag->message[text_len] = '\0'; return GIT_SUCCESS; } -int git_tag_create_o( - git_oid *oid, - git_repository *repo, - const char *tag_name, - const git_object *target, - const git_signature *tagger, - const char *message) +static int retreive_tag_reference(git_reference **tag_reference_out, char *ref_name_out, git_repository *repo, const char *tag_name) { - return git_tag_create( - oid, repo, tag_name, - git_object_id(target), - git_object_type(target), - tagger, message); + git_reference *tag_ref; + int error; + + git__joinpath(ref_name_out, GIT_REFS_TAGS_DIR, tag_name); + error = git_reference_lookup(&tag_ref, repo, ref_name_out); + if (error < GIT_SUCCESS) + return error; + + *tag_reference_out = tag_ref; + + return GIT_SUCCESS; } -int git_tag_create( +static int tag_create( git_oid *oid, git_repository *repo, const char *tag_name, const git_oid *target, git_otype target_type, const git_signature *tagger, - const char *message) + const char *message, + int allow_ref_overwrite) { size_t final_size = 0; git_odb_stream *stream; const char *type_str; char *tagger_str; + git_reference *new_ref; + + char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; int type_str_len, tag_name_len, tagger_str_len, message_len; - int error; + int error, should_update_ref = 0; + + /** Ensure the tag name doesn't conflict with an already existing + reference unless overwriting has explictly been requested **/ + error = retreive_tag_reference(&new_ref, ref_name, repo, tag_name); + + switch (error) { + case GIT_SUCCESS: + if (!allow_ref_overwrite) + return GIT_EEXISTS; + should_update_ref = 1; + + /* Fall trough */ + case GIT_ENOTFOUND: + break; + + default: + return error; + } + + if (!git_odb_exists(repo->db, target)) + return git__throw(GIT_ENOTFOUND, "Failed to create tag. Object to tag doesn't exist"); + + /* Try to find out what the type is */ + if (target_type == GIT_OBJ_ANY) { + size_t _unused; + error = git_odb_read_header(&_unused, &target_type, repo->db, target); + if (error < GIT_SUCCESS) + return error; + } type_str = git_object_type2string(target_type); @@ -223,16 +265,112 @@ int git_tag_create( error = stream->finalize_write(oid, stream); stream->free(stream); - if (error == GIT_SUCCESS) { - char ref_name[512]; - git_reference *new_ref; - git__joinpath(ref_name, GIT_REFS_TAGS_DIR, tag_name); + if (error < GIT_SUCCESS) + return error; + + if (!should_update_ref) error = git_reference_create_oid(&new_ref, repo, ref_name, oid); - } + else + error = git_reference_set_oid(new_ref, oid); + + return error; +} + +int git_tag_create_frombuffer(git_oid *oid, git_repository *repo, const char *buffer) +{ + git_tag tag; + int error; + + assert(oid && buffer); + + memset(&tag, 0, sizeof(tag)); + + if ((error = parse_tag_buffer(&tag, buffer, buffer + strlen(buffer))) < GIT_SUCCESS) + return error; + + error = git_tag_create(oid, repo, tag.tag_name, &tag.target, tag.type, tag.tagger, tag.message); + + git_signature_free(tag.tagger); + free(tag.tag_name); + free(tag.message); return error; } +int git_tag_create_o( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + const git_signature *tagger, + const char *message) +{ + return tag_create( + oid, repo, tag_name, + git_object_id(target), + git_object_type(target), + tagger, message, 0); +} + +int git_tag_create( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_oid *target, + git_otype target_type, + const git_signature *tagger, + const char *message) +{ + return tag_create( + oid, repo, tag_name, + target, + target_type, + tagger, message, 0); +} + +int git_tag_create_fo( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_object *target, + const git_signature *tagger, + const char *message) +{ + return tag_create( + oid, repo, tag_name, + git_object_id(target), + git_object_type(target), + tagger, message, 1); +} + +int git_tag_create_f( + git_oid *oid, + git_repository *repo, + const char *tag_name, + const git_oid *target, + git_otype target_type, + const git_signature *tagger, + const char *message) +{ + return tag_create( + oid, repo, tag_name, + target, + target_type, + tagger, message, 1); +} + +int git_tag_delete(git_repository *repo, const char *tag_name) +{ + int error; + git_reference *tag_ref; + char ref_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + + error = retreive_tag_reference(&tag_ref, ref_name, repo, tag_name); + if (error < GIT_SUCCESS) + return error; + + return git_reference_delete(tag_ref); +} int git_tag__parse(git_tag *tag, git_odb_object *obj) { @@ -240,3 +378,29 @@ int git_tag__parse(git_tag *tag, git_odb_object *obj) return parse_tag_buffer(tag, obj->raw.data, (char *)obj->raw.data + obj->raw.len); } +static int tag_list_cb(const char *tag_name, void *payload) +{ + if (git__prefixcmp(tag_name, GIT_REFS_TAGS_DIR) == 0) + return git_vector_insert((git_vector *)payload, git__strdup(tag_name)); + + return GIT_SUCCESS; +} + +int git_tag_list(git_strarray *tag_names, git_repository *repo) +{ + int error; + git_vector taglist; + + if (git_vector_init(&taglist, 8, NULL) < GIT_SUCCESS) + return GIT_ENOMEM; + + error = git_reference_listcb(repo, GIT_REF_OID|GIT_REF_PACKED, &tag_list_cb, (void *)&taglist); + if (error < GIT_SUCCESS) { + git_vector_free(&taglist); + return error; + } + + tag_names->strings = (char **)taglist.contents; + tag_names->count = taglist.length; + return GIT_SUCCESS; +} diff --git a/vendor/libgit2/src/tree.c b/vendor/libgit2/src/tree.c index 31b286e69..b7daf39c4 100644 --- a/vendor/libgit2/src/tree.c +++ b/vendor/libgit2/src/tree.c @@ -33,6 +33,10 @@ #define MAX_FILEMODE 0777777 #define MAX_FILEMODE_BYTES 6 +static int valid_attributes(const int attributes) { + return attributes >= 0 && attributes <= MAX_FILEMODE; +} + int entry_search_cmp(const void *key, const void *array_member) { const char *filename = (const char *)key; @@ -79,30 +83,30 @@ const git_oid *git_tree_id(git_tree *c) return git_object_id((git_object *)c); } -unsigned int git_tree_entry_attributes(git_tree_entry *entry) +unsigned int git_tree_entry_attributes(const git_tree_entry *entry) { return entry->attr; } -const char *git_tree_entry_name(git_tree_entry *entry) +const char *git_tree_entry_name(const git_tree_entry *entry) { assert(entry); return entry->filename; } -const git_oid *git_tree_entry_id(git_tree_entry *entry) +const git_oid *git_tree_entry_id(const git_tree_entry *entry) { assert(entry); return &entry->oid; } -int git_tree_entry_2object(git_object **object_out, git_repository *repo, git_tree_entry *entry) +int git_tree_entry_2object(git_object **object_out, git_repository *repo, const git_tree_entry *entry) { assert(entry && object_out); return git_object_lookup(object_out, repo, &entry->oid, GIT_OBJ_ANY); } -git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) +const git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) { int idx; @@ -115,7 +119,7 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) return git_vector_get(&tree->entries, idx); } -git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) +const git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) { assert(tree); return git_vector_get(&tree->entries, (unsigned int)idx); @@ -127,7 +131,7 @@ size_t git_tree_entrycount(git_tree *tree) return tree->entries.length; } -static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end) +static int tree_parse_buffer(git_tree *tree, const char *buffer, const char *buffer_end) { int error = GIT_SUCCESS; @@ -137,7 +141,7 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end) while (buffer < buffer_end) { git_tree_entry *entry; - entry = git__malloc(sizeof(git_tree_entry)); + entry = git__calloc(1, sizeof(git_tree_entry)); if (entry == NULL) { error = GIT_ENOMEM; break; @@ -146,7 +150,8 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end) if (git_vector_insert(&tree->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; - entry->attr = strtol(buffer, &buffer, 8); + if (git__strtol32((long *)&entry->attr, buffer, &buffer, 8) < GIT_SUCCESS) + return GIT_EOBJCORRUPTED; if (*buffer++ != ' ') { error = GIT_EOBJCORRUPTED; @@ -159,6 +164,7 @@ static int tree_parse_buffer(git_tree *tree, char *buffer, char *buffer_end) } entry->filename = git__strdup(buffer); + entry->filename_len = strlen(buffer); while (buffer < buffer_end && *buffer != 0) buffer++; @@ -178,3 +184,305 @@ int git_tree__parse(git_tree *tree, git_odb_object *obj) return tree_parse_buffer(tree, (char *)obj->raw.data, (char *)obj->raw.data + obj->raw.len); } +static int write_index_entry(char *buffer, int mode, const char *path, size_t path_len, const git_oid *oid) +{ + int written; + written = sprintf(buffer, "%o %.*s%c", mode, (int)path_len, path, 0); + memcpy(buffer + written, &oid->id, GIT_OID_RAWSZ); + return written + GIT_OID_RAWSZ; +} + +static int write_index(git_oid *oid, git_index *index, const char *base, int baselen, int entry_no, int maxentries) +{ + size_t size, offset; + char *buffer; + int nr, error; + + /* Guess at some random initial size */ + size = maxentries * 40; + buffer = git__malloc(size); + if (buffer == NULL) + return GIT_ENOMEM; + + offset = 0; + + for (nr = entry_no; nr < maxentries; ++nr) { + git_index_entry *entry = git_index_get(index, nr); + + const char *pathname = entry->path, *filename, *dirname; + int pathlen = strlen(pathname), entrylen; + + unsigned int write_mode; + git_oid subtree_oid; + git_oid *write_oid; + + /* Did we hit the end of the directory? Return how many we wrote */ + if (baselen >= pathlen || memcmp(base, pathname, baselen) != 0) + break; + + /* Do we have _further_ subdirectories? */ + filename = pathname + baselen; + dirname = strchr(filename, '/'); + + write_oid = &entry->oid; + write_mode = entry->mode; + + if (dirname) { + int subdir_written; + +#if 0 + if (entry->mode != S_IFDIR) { + free(buffer); + return GIT_EOBJCORRUPTED; + } +#endif + subdir_written = write_index(&subtree_oid, index, pathname, dirname - pathname + 1, nr, maxentries); + + if (subdir_written < GIT_SUCCESS) { + free(buffer); + return subdir_written; + } + + nr = subdir_written - 1; + + /* Now we need to write out the directory entry into this tree.. */ + pathlen = dirname - pathname; + write_oid = &subtree_oid; + write_mode = S_IFDIR; + } + + entrylen = pathlen - baselen; + if (offset + entrylen + 32 > size) { + size = alloc_nr(offset + entrylen + 32); + buffer = git__realloc(buffer, size); + + if (buffer == NULL) + return GIT_ENOMEM; + } + + offset += write_index_entry(buffer + offset, write_mode, filename, entrylen, write_oid); + } + + error = git_odb_write(oid, index->repository->db, buffer, offset, GIT_OBJ_TREE); + free(buffer); + + return (error == GIT_SUCCESS) ? nr : error; +} + +int git_tree_create_fromindex(git_oid *oid, git_index *index) +{ + int error; + + if (index->repository == NULL) + return GIT_EBAREINDEX; + + error = write_index(oid, index, "", 0, 0, git_index_entrycount(index)); + return (error < GIT_SUCCESS) ? error : GIT_SUCCESS; +} + +static void sort_entries(git_treebuilder *bld) +{ + git_vector_sort(&bld->entries); +} + +int git_treebuilder_create(git_treebuilder **builder_p, const git_tree *source) +{ + git_treebuilder *bld; + size_t i, source_entries = DEFAULT_TREE_SIZE; + + assert(builder_p); + + bld = git__calloc(1, sizeof(git_treebuilder)); + if (bld == NULL) + return GIT_ENOMEM; + + if (source != NULL) + source_entries = source->entries.length; + + if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < GIT_SUCCESS) { + free(bld); + return GIT_ENOMEM; + } + + if (source != NULL) { + bld->entry_count = source_entries; + for (i = 0; i < source->entries.length; ++i) { + git_tree_entry *entry_src = source->entries.contents[i]; + git_tree_entry *entry = git__calloc(1, sizeof(git_tree_entry)); + + if (entry == NULL) { + git_treebuilder_free(bld); + return GIT_ENOMEM; + } + + entry->filename = git__strdup(entry_src->filename); + + if (entry->filename == NULL) { + free(entry); + git_treebuilder_free(bld); + return GIT_ENOMEM; + } + + entry->filename_len = entry_src->filename_len; + git_oid_cpy(&entry->oid, &entry_src->oid); + entry->attr = entry_src->attr; + + git_vector_insert(&bld->entries, entry); + } + } + + *builder_p = bld; + return GIT_SUCCESS; +} + +int git_treebuilder_insert(git_tree_entry **entry_out, git_treebuilder *bld, const char *filename, const git_oid *id, unsigned int attributes) +{ + git_tree_entry *entry; + int pos; + + assert(bld && id && filename); + + if (!valid_attributes(attributes)) + return GIT_ERROR; + + if ((pos = git_vector_bsearch2(&bld->entries, entry_search_cmp, filename)) != GIT_ENOTFOUND) { + entry = git_vector_get(&bld->entries, pos); + if (entry->removed) { + entry->removed = 0; + bld->entry_count++; + } + } else { + if ((entry = git__malloc(sizeof(git_tree_entry))) == NULL) + return GIT_ENOMEM; + + memset(entry, 0x0, sizeof(git_tree_entry)); + entry->filename = git__strdup(filename); + entry->filename_len = strlen(entry->filename); + + bld->entry_count++; + } + + git_oid_cpy(&entry->oid, id); + entry->attr = attributes; + + if (pos == GIT_ENOTFOUND) { + if (git_vector_insert(&bld->entries, entry) < 0) + return GIT_ENOMEM; + } + + if (entry_out != NULL) + *entry_out = entry; + + return GIT_SUCCESS; +} + +const git_tree_entry *git_treebuilder_get(git_treebuilder *bld, const char *filename) +{ + int idx; + git_tree_entry *entry; + + assert(bld && filename); + + sort_entries(bld); + idx = git_vector_bsearch2(&bld->entries, entry_search_cmp, filename); + if (idx == GIT_ENOTFOUND) + return NULL; + + entry = git_vector_get(&bld->entries, idx); + if (entry->removed) + return NULL; + + return entry; +} + +int git_treebuilder_remove(git_treebuilder *bld, const char *filename) +{ + git_tree_entry *remove_ptr = (git_tree_entry *)git_treebuilder_get(bld, filename); + + if (remove_ptr == NULL || remove_ptr->removed) + return GIT_ENOTFOUND; + + remove_ptr->removed = 1; + bld->entry_count--; + return GIT_SUCCESS; +} + +int git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld) +{ + size_t i, size = 0; + char filemode[MAX_FILEMODE_BYTES + 1 + 1]; + git_odb_stream *stream; + int error; + + assert(bld); + + sort_entries(bld); + + for (i = 0; i < bld->entries.length; ++i) { + git_tree_entry *entry = bld->entries.contents[i]; + + if (entry->removed) + continue; + + snprintf(filemode, sizeof(filemode), "%o ", entry->attr); + size += strlen(filemode); + size += entry->filename_len + 1; + size += GIT_OID_RAWSZ; + } + + if ((error = git_odb_open_wstream(&stream, git_repository_database(repo), size, GIT_OBJ_TREE)) < GIT_SUCCESS) + return error; + + for (i = 0; i < bld->entries.length; ++i) { + git_tree_entry *entry = bld->entries.contents[i]; + + if (entry->removed) + continue; + + snprintf(filemode, sizeof(filemode), "%o ", entry->attr); + stream->write(stream, filemode, strlen(filemode)); + stream->write(stream, entry->filename, entry->filename_len + 1); + stream->write(stream, (char *)entry->oid.id, GIT_OID_RAWSZ); + } + + error = stream->finalize_write(oid, stream); + stream->free(stream); + + return error; +} + +void git_treebuilder_filter(git_treebuilder *bld, int (*filter)(const git_tree_entry *, void *), void *payload) +{ + size_t i; + + assert(bld && filter); + + for (i = 0; i < bld->entries.length; ++i) { + git_tree_entry *entry = bld->entries.contents[i]; + if (!entry->removed && filter(entry, payload)) + entry->removed = 1; + } +} + +void git_treebuilder_clear(git_treebuilder *bld) +{ + size_t i; + assert(bld); + + for (i = 0; i < bld->entries.length; ++i) { + git_tree_entry *e = bld->entries.contents[i]; + free(e->filename); + free(e); + } + + git_vector_clear(&bld->entries); +} + +void git_treebuilder_free(git_treebuilder *bld) +{ + git_treebuilder_clear(bld); + git_vector_free(&bld->entries); + free(bld); +} + + diff --git a/vendor/libgit2/src/tree.h b/vendor/libgit2/src/tree.h index b4e910a9f..bff3f8edb 100644 --- a/vendor/libgit2/src/tree.h +++ b/vendor/libgit2/src/tree.h @@ -10,6 +10,8 @@ struct git_tree_entry { unsigned int attr; char *filename; git_oid oid; + size_t filename_len; + int removed; }; struct git_tree { @@ -17,6 +19,12 @@ struct git_tree { git_vector entries; }; +struct git_treebuilder { + git_vector entries; + size_t entry_count; +}; + + void git_tree__free(git_tree *tree); int git_tree__parse(git_tree *tree, git_odb_object *obj); diff --git a/vendor/libgit2/src/util.c b/vendor/libgit2/src/util.c index 995daf314..55a7ab2a9 100644 --- a/vendor/libgit2/src/util.c +++ b/vendor/libgit2/src/util.c @@ -2,6 +2,7 @@ #include "common.h" #include #include +#include void git_strarray_free(git_strarray *array) { @@ -12,6 +13,84 @@ void git_strarray_free(git_strarray *array) free(array->strings); } +int git__strtol32(long *result, const char *nptr, const char **endptr, int base) +{ + const char *p; + long n, nn; + int c, ovfl, v, neg, ndig; + + p = nptr; + neg = 0; + n = 0; + ndig = 0; + ovfl = 0; + + /* + * White space + */ + while (isspace(*p)) + p++; + + /* + * Sign + */ + if (*p == '-' || *p == '+') + if (*p++ == '-') + neg = 1; + + /* + * Base + */ + if (base == 0) { + if (*p != '0') + base = 10; + else { + base = 8; + if (p[1] == 'x' || p[1] == 'X') { + p += 2; + base = 16; + } + } + } else if (base == 16 && *p == '0') { + if (p[1] == 'x' || p[1] == 'X') + p += 2; + } else if (base < 0 || 36 < base) + goto Return; + + /* + * Non-empty sequence of digits + */ + for (;; p++,ndig++) { + c = *p; + v = base; + if ('0'<=c && c<='9') + v = c - '0'; + else if ('a'<=c && c<='z') + v = c - 'a' + 10; + else if ('A'<=c && c<='Z') + v = c - 'A' + 10; + if (v >= base) + break; + nn = n*base + v; + if (nn < n) + ovfl = 1; + n = nn; + } + +Return: + if (ndig == 0) + return GIT_ENOTNUM; + + if (endptr) + *endptr = p; + + if (ovfl) + return GIT_EOVERFLOW; + + *result = neg ? -n : n; + return GIT_SUCCESS; +} + int git__fmt(char *buf, size_t buf_sz, const char *fmt, ...) { va_list va; diff --git a/vendor/libgit2/src/util.h b/vendor/libgit2/src/util.h index 653b34d02..6724e8d41 100644 --- a/vendor/libgit2/src/util.h +++ b/vendor/libgit2/src/util.h @@ -6,21 +6,49 @@ #define MSB(x, bits) ((x) & (~0ULL << (bitsizeof(x) - (bits)))) /* - * Don't wrap malloc/calloc. - * Use the default versions in glibc, and make - * sure that any methods that allocate memory - * return a GIT_ENOMEM error when allocation - * fails. + * Custom memory allocation wrappers + * that set error code and error message + * on allocation failure */ -#define git__malloc malloc -#define git__calloc calloc -#define git__strdup strdup +GIT_INLINE(void *) git__malloc(size_t len) +{ + void *ptr = malloc(len); + if (!ptr) + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)len); + return ptr; +} + +GIT_INLINE(void *) git__calloc(size_t nelem, size_t elsize) +{ + void *ptr = calloc(nelem, elsize); + if (!ptr) + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)elsize); + return ptr; +} + +GIT_INLINE(char *) git__strdup(const char *str) +{ + char *ptr = strdup(str); + if (!ptr) + git__throw(GIT_ENOMEM, "Out of memory. Failed to duplicate string"); + return ptr; +} + +GIT_INLINE(void *) git__realloc(void *ptr, size_t size) +{ + void *new_ptr = realloc(ptr, size); + if (!new_ptr) + git__throw(GIT_ENOMEM, "Out of memory. Failed to allocate %d bytes.", (int)size); + return new_ptr; +} extern int git__fmt(char *, size_t, const char *, ...) GIT_FORMAT_PRINTF(3, 4); extern int git__prefixcmp(const char *str, const char *prefix); extern int git__suffixcmp(const char *str, const char *suffix); +extern int git__strtol32(long *n, const char *buff, const char **end_buf, int base); + /* * The dirname() function shall take a pointer to a character string * that contains a pathname, and return a pointer to a string that is a diff --git a/vendor/libgit2/src/win32/pthread.c b/vendor/libgit2/src/win32/pthread.c index f47364a76..7e17b6bdf 100644 --- a/vendor/libgit2/src/win32/pthread.c +++ b/vendor/libgit2/src/win32/pthread.c @@ -48,16 +48,15 @@ int pthread_join(pthread_t thread, void **value_ptr) int pthread_mutex_init(pthread_mutex_t *GIT_RESTRICT mutex, const pthread_mutexattr_t *GIT_RESTRICT GIT_UNUSED(mutexattr)) { - GIT_UNUSED_ARG(mutexattr); + GIT_UNUSED_ARG(mutexattr); InitializeCriticalSection(mutex); return 0; } int pthread_mutex_destroy(pthread_mutex_t *mutex) { - int ret; - ret = CloseHandle(mutex); - return -(!ret); + DeleteCriticalSection(mutex); + return 0; } int pthread_mutex_lock(pthread_mutex_t *mutex) diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 b/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 index 03770969a..697c94c92 100644 Binary files a/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 and b/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 differ diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/tags/very-simple b/vendor/libgit2/tests/resources/testrepo.git/refs/tags/e90810b similarity index 100% rename from vendor/libgit2/tests/resources/testrepo.git/refs/tags/very-simple rename to vendor/libgit2/tests/resources/testrepo.git/refs/tags/e90810b diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/tags/point_to_blob b/vendor/libgit2/tests/resources/testrepo.git/refs/tags/point_to_blob new file mode 100644 index 000000000..f874a3ffc --- /dev/null +++ b/vendor/libgit2/tests/resources/testrepo.git/refs/tags/point_to_blob @@ -0,0 +1 @@ +1385f264afb75a56a5bec74243be9b367ba4ca08 diff --git a/vendor/libgit2/tests/t00-core.c b/vendor/libgit2/tests/t00-core.c index 4cb111428..ab9a683a7 100644 --- a/vendor/libgit2/tests/t00-core.c +++ b/vendor/libgit2/tests/t00-core.c @@ -233,7 +233,7 @@ BEGIN_TEST(path3, "prettify and validate a path to a file") must_fail(ensure_file_path_normalized("d1/s1///s2/..//../s3/", NULL, 0)); must_pass(ensure_file_path_normalized("d1/s1//../s2/../../d2", "d2", CWD_AS_PREFIX | PATH_AS_SUFFIX)); must_fail(ensure_file_path_normalized("dir/sub/../", NULL, 0)); - must_pass(ensure_file_path_normalized("../../a/../../b/c/d/../../e", "b/e", PATH_AS_SUFFIX)); + must_pass(ensure_file_path_normalized("../a/../b/c/d/../../e", "b/e", PATH_AS_SUFFIX)); must_fail(ensure_file_path_normalized("....", NULL, 0)); must_fail(ensure_file_path_normalized("...", NULL, 0)); must_fail(ensure_file_path_normalized("./...", NULL, 0)); @@ -309,7 +309,7 @@ BEGIN_TEST(path4, "validate and prettify a path to a folder") must_pass(ensure_dir_path_normalized("d1/s1///s2/..//../s3/", "d1/s3/", CWD_AS_PREFIX | PATH_AS_SUFFIX)); must_pass(ensure_dir_path_normalized("d1/s1//../s2/../../d2", "d2/", CWD_AS_PREFIX | PATH_AS_SUFFIX)); must_pass(ensure_dir_path_normalized("dir/sub/../", "dir/", CWD_AS_PREFIX | PATH_AS_SUFFIX)); - must_pass(ensure_dir_path_normalized("../../a/../../b/c/d/../../e", "b/e/", PATH_AS_SUFFIX)); + must_pass(ensure_dir_path_normalized("../a/../b/c/d/../../e", "b/e/", PATH_AS_SUFFIX)); must_fail(ensure_dir_path_normalized("....", NULL, 0)); must_fail(ensure_dir_path_normalized("...", NULL, 0)); must_fail(ensure_dir_path_normalized("./...", NULL, 0)); diff --git a/vendor/libgit2/tests/t04-commit.c b/vendor/libgit2/tests/t04-commit.c index e92842435..36f3e66b5 100644 --- a/vendor/libgit2/tests/t04-commit.c +++ b/vendor/libgit2/tests/t04-commit.c @@ -114,15 +114,15 @@ BEGIN_TEST(parse0, "parse the OID line in a commit") git_oid oid; #define TEST_OID_PASS(string, header) { \ - char *ptr = string;\ - char *ptr_original = ptr;\ + const char *ptr = string;\ + const char *ptr_original = ptr;\ size_t len = strlen(ptr);\ must_pass(git__parse_oid(&oid, &ptr, ptr + len, header));\ must_be_true(ptr == ptr_original + len);\ } #define TEST_OID_FAIL(string, header) { \ - char *ptr = string;\ + const char *ptr = string;\ size_t len = strlen(ptr);\ must_fail(git__parse_oid(&oid, &ptr, ptr + len, header));\ } @@ -154,7 +154,7 @@ END_TEST BEGIN_TEST(parse1, "parse the signature line in a commit") #define TEST_SIGNATURE_PASS(_string, _header, _name, _email, _time, _offset) { \ - char *ptr = _string; \ + const char *ptr = _string; \ size_t len = strlen(_string);\ git_signature person = {NULL, NULL, {0, 0}}; \ must_pass(git_signature__parse(&person, &ptr, ptr + len, _header));\ @@ -166,7 +166,7 @@ BEGIN_TEST(parse1, "parse the signature line in a commit") } #define TEST_SIGNATURE_FAIL(_string, _header) { \ - char *ptr = _string; \ + const char *ptr = _string; \ size_t len = strlen(_string);\ git_signature person = {NULL, NULL, {0, 0}}; \ must_fail(git_signature__parse(&person, &ptr, ptr + len, _header));\ @@ -368,7 +368,7 @@ BEGIN_TEST(details0, "query the details on a parsed commit") const char *message, *message_short; git_time_t commit_time; unsigned int parents, p; - git_commit *parent; + git_commit *parent = NULL, *old_parent = NULL; git_oid_mkstr(&id, commit_ids[i]); @@ -390,11 +390,19 @@ BEGIN_TEST(details0, "query the details on a parsed commit") must_be_true(commit_time > 0); must_be_true(parents <= 2); for (p = 0;p < parents;p++) { + if (old_parent != NULL) + git_commit_close(old_parent); + + old_parent = parent; must_pass(git_commit_parent(&parent, commit, p)); must_be_true(parent != NULL); must_be_true(git_commit_author(parent) != NULL); // is it really a commit? } + git_commit_close(old_parent); + git_commit_close(parent); + must_fail(git_commit_parent(&parent, commit, parents)); + git_commit_close(commit); } git_repository_free(repo); @@ -462,9 +470,76 @@ BEGIN_TEST(write0, "write a new commit object from memory to disk") must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); + git_commit_close(commit); git_repository_free(repo); END_TEST +#define ROOT_COMMIT_MESSAGE "This is a root commit\n\ +This is a root commit and should be the only one in this branch\n" + +BEGIN_TEST(root0, "create a root commit") + git_repository *repo; + git_commit *commit; + git_oid tree_id, commit_id; + const git_oid *branch_oid; + const git_signature *author, *committer; + const char *branch_name = "refs/heads/root-commit-branch"; + git_reference *head, *branch; + char *head_old; + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + git_oid_mkstr(&tree_id, tree_oid); + + /* create signatures */ + committer = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 123456789, 60); + must_be_true(committer != NULL); + + author = git_signature_new(COMMITTER_NAME, COMMITTER_EMAIL, 987654321, 90); + must_be_true(author != NULL); + + /* First we need to update HEAD so it points to our non-existant branch */ + must_pass(git_reference_lookup(&head, repo, "HEAD")); + must_be_true(git_reference_type(head) == GIT_REF_SYMBOLIC); + head_old = git__strdup(git_reference_target(head)); + must_be_true(head_old != NULL); + + must_pass(git_reference_set_target(head, branch_name)); + + must_pass(git_commit_create_v( + &commit_id, /* out id */ + repo, + "HEAD", + author, + committer, + ROOT_COMMIT_MESSAGE, + &tree_id, + 0)); + + git_signature_free((git_signature *)committer); + git_signature_free((git_signature *)author); + + /* + * The fact that creating a commit works has already been + * tested. Here we just make sure it's our commit and that it was + * written as a root commit. + */ + must_pass(git_commit_lookup(&commit, repo, &commit_id)); + must_be_true(git_commit_parentcount(commit) == 0); + must_pass(git_reference_lookup(&branch, repo, branch_name)); + branch_oid = git_reference_oid(branch); + must_pass(git_oid_cmp(branch_oid, &commit_id)); + must_be_true(!strcmp(git_commit_message(commit), ROOT_COMMIT_MESSAGE)); + + /* Remove the data we just added to the repo */ + must_pass(git_reference_lookup(&head, repo, "HEAD")); + must_pass(git_reference_set_target(head, head_old)); + must_pass(git_reference_delete(branch)); + must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit)); + free(head_old); + git_commit_close(commit); + git_repository_free(repo); +END_TEST BEGIN_SUITE(commit) ADD_TEST(parse0); @@ -474,4 +549,6 @@ BEGIN_SUITE(commit) ADD_TEST(write0); //ADD_TEST(write1); + + ADD_TEST(root0); END_SUITE diff --git a/vendor/libgit2/tests/t07-hashtable.c b/vendor/libgit2/tests/t07-hashtable.c index 597136965..0b362cafd 100644 --- a/vendor/libgit2/tests/t07-hashtable.c +++ b/vendor/libgit2/tests/t07-hashtable.c @@ -155,7 +155,7 @@ BEGIN_TEST(tableit0, "iterate through all the contents of the table") const int objects_n = 32; int i; table_item *objects, *ob; - const void *_unused; + const void *GIT_UNUSED(_unused); git_hashtable *table = NULL; diff --git a/vendor/libgit2/tests/t08-tag.c b/vendor/libgit2/tests/t08-tag.c index 70eeb28a6..fae2e99db 100644 --- a/vendor/libgit2/tests/t08-tag.c +++ b/vendor/libgit2/tests/t08-tag.c @@ -58,6 +58,22 @@ BEGIN_TEST(read0, "read and parse a tag from the repository") must_be_true(git_oid_cmp(&id_commit, git_commit_id(commit)) == 0); + git_tag_close(tag1); + git_tag_close(tag2); + git_commit_close(commit); + git_repository_free(repo); +END_TEST + +BEGIN_TEST(read1, "list all tag names from the repository") + git_repository *repo; + git_strarray tag_list; + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(git_tag_list(&tag_list, repo)); + + must_be_true(tag_list.count == 3); + + git_strarray_free(&tag_list); git_repository_free(repo); END_TEST @@ -72,20 +88,19 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") git_oid target_id, tag_id; const git_signature *tagger; git_reference *ref_tag; - /* char hex_oid[41]; */ must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); git_oid_mkstr(&target_id, tagged_commit); - /* create signatures */ + /* create signature */ tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60); must_be_true(tagger != NULL); must_pass(git_tag_create( &tag_id, /* out id */ repo, - "the-tag", /* do not update the HEAD */ + "the-tag", &target_id, GIT_OBJ_COMMIT, tagger, @@ -94,6 +109,7 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") git_signature_free((git_signature *)tagger); must_pass(git_tag_lookup(&tag, repo, &tag_id)); + must_be_true(git_oid_cmp(git_tag_target_oid(tag), &target_id) == 0); /* Check attributes were set correctly */ tagger = git_tag_tagger(tag); @@ -111,12 +127,123 @@ BEGIN_TEST(write0, "write a tag to the repository and read it again") must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag)); + git_tag_close(tag); + git_repository_free(repo); + +END_TEST + +BEGIN_TEST(write1, "write a tag to the repository which points to an unknown oid should fail") + git_repository *repo; + git_oid target_id, tag_id; + const git_signature *tagger; + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + git_oid_mkstr(&target_id, "deadbeef1b46c854b31185ea97743be6a8774479"); + + /* create signature */ + tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60); + must_be_true(tagger != NULL); + + must_fail(git_tag_create( + &tag_id, /* out id */ + repo, + "the-zombie-tag", + &target_id, + GIT_OBJ_COMMIT, + tagger, + TAGGER_MESSAGE)); + + git_signature_free((git_signature *)tagger); + + git_repository_free(repo); + +END_TEST + +BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag") + git_repository *repo; + git_oid target_id, tag_id; + const git_signature *tagger; + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + git_oid_mkstr(&target_id, tagged_commit); + + /* create signature */ + tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60); + must_be_true(tagger != NULL); + + must_fail(git_tag_create( + &tag_id, /* out id */ + repo, + "e90810b", + &target_id, + GIT_OBJ_COMMIT, + tagger, + TAGGER_MESSAGE)); + + git_signature_free((git_signature *)tagger); + git_repository_free(repo); END_TEST +BEGIN_TEST(write3, "Replace an already existing tag") + git_repository *repo; + git_oid target_id, tag_id, old_tag_id; + const git_signature *tagger; + git_reference *ref_tag; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + git_oid_mkstr(&target_id, tagged_commit); + + must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b")); + git_oid_cpy(&old_tag_id, git_reference_oid(ref_tag)); + + /* create signature */ + tagger = git_signature_new(TAGGER_NAME, TAGGER_EMAIL, 123456789, 60); + must_be_true(tagger != NULL); + + must_pass(git_tag_create_f( + &tag_id, /* out id */ + repo, + "e90810b", + &target_id, + GIT_OBJ_COMMIT, + tagger, + TAGGER_MESSAGE)); + + git_signature_free((git_signature *)tagger); + + must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b")); + must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0); + must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &old_tag_id) != 0); + + close_temp_repo(repo); + +END_TEST + +BEGIN_TEST(write4, "Delete an already existing tag") + git_repository *repo; + git_reference *ref_tag; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + must_pass(git_tag_delete(repo,"e90810b")); + + must_fail(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b")); + + close_temp_repo(repo); + +END_TEST BEGIN_SUITE(tag) ADD_TEST(read0); - ADD_TEST(write0); + ADD_TEST(read1); + ADD_TEST(write0); + ADD_TEST(write1); + ADD_TEST(write2); + ADD_TEST(write3); + ADD_TEST(write4); END_SUITE diff --git a/vendor/libgit2/tests/t09-tree.c b/vendor/libgit2/tests/t09-tree.c index 6c1b2e643..af992fdb3 100644 --- a/vendor/libgit2/tests/t09-tree.c +++ b/vendor/libgit2/tests/t09-tree.c @@ -29,6 +29,41 @@ static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; +static const char *blob_oid = "fa49b077972391ad58037050f2a75f74e3671e92"; +static const char *first_tree = "181037049a54a1eb5fab404658a3a250b44335d7"; +static const char *second_tree = "f60079018b664e4e79329a7ef9559c8d9e0378d1"; +static const char *third_tree = "eb86d8b81d6adbd5290a935d6c9976882de98488"; + +#if 0 +static int print_tree(git_repository *repo, const git_oid *tree_oid, int depth) +{ + static const char *indent = " "; + git_tree *tree; + unsigned int i; + + if (git_tree_lookup(&tree, repo, tree_oid) < GIT_SUCCESS) + return GIT_ERROR; + + for (i = 0; i < git_tree_entrycount(tree); ++i) { + const git_tree_entry *entry = git_tree_entry_byindex(tree, i); + char entry_oid[40]; + + git_oid_fmt(entry_oid, &entry->oid); + printf("%.*s%o [%.*s] %s\n", depth*2, indent, entry->attr, 40, entry_oid, entry->filename); + + if (entry->attr == S_IFDIR) { + if (print_tree(repo, &entry->oid, depth + 1) < GIT_SUCCESS) { + git_tree_close(tree); + return GIT_ERROR; + } + } + } + + git_tree_close(tree); + return GIT_SUCCESS; +} +#endif + BEGIN_TEST(read0, "acces randomly the entries on a loaded tree") git_oid id; git_repository *repo; @@ -48,6 +83,7 @@ BEGIN_TEST(read0, "acces randomly the entries on a loaded tree") must_be_true(git_tree_entry_byindex(tree, 3) == NULL); must_be_true(git_tree_entry_byindex(tree, -1) == NULL); + git_tree_close(tree); git_repository_free(repo); END_TEST @@ -55,7 +91,7 @@ BEGIN_TEST(read1, "read a tree from the repository") git_oid id; git_repository *repo; git_tree *tree; - git_tree_entry *entry; + const git_tree_entry *entry; git_object *obj; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); @@ -68,7 +104,9 @@ BEGIN_TEST(read1, "read a tree from the repository") /* GH-86: git_object_lookup() should also check the type if the object comes from the cache */ must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_TREE) == 0); + git_object_close(obj); must_be_true(git_object_lookup(&obj, repo, &id, GIT_OBJ_BLOB) == GIT_EINVALIDTYPE); + git_object_close(obj); entry = git_tree_entry_byname(tree, "README"); must_be_true(entry != NULL); @@ -77,13 +115,96 @@ BEGIN_TEST(read1, "read a tree from the repository") must_pass(git_tree_entry_2object(&obj, repo, entry)); + git_object_close(obj); + git_tree_close(tree); + git_repository_free(repo); +END_TEST + +#if 0 +BEGIN_TEST(write0, "write a tree from an index") + git_repository *repo; + git_index *index; + git_oid tree_oid; + + must_pass(git_repository_open(&repo, "/tmp/redtmp/.git")); + must_pass(git_repository_index(&index, repo)); + + must_pass(git_tree_create_fromindex(&tree_oid, index)); + must_pass(print_tree(repo, &tree_oid, 0)); + git_repository_free(repo); END_TEST +#endif + +BEGIN_TEST(write2, "write a tree from a memory") + git_repository *repo; + git_treebuilder *builder; + git_tree *tree; + git_oid id, bid, rid, id2; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + git_oid_mkstr(&id, first_tree); + git_oid_mkstr(&id2, second_tree); + git_oid_mkstr(&bid, blob_oid); + + //create a second tree from first tree using `git_treebuilder_insert` on REPOSITORY_FOLDER. + must_pass(git_tree_lookup(&tree, repo, &id)); + must_pass(git_treebuilder_create(&builder, tree)); + must_pass(git_treebuilder_insert(NULL,builder,"new.txt",&bid,0100644)); + must_pass(git_treebuilder_write(&rid,repo,builder)); + + must_be_true(git_oid_cmp(&rid, &id2) == 0); + + git_treebuilder_free(builder); + git_tree_close(tree); + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(write3, "write a hierarchical tree from a memory") + git_repository *repo; + git_treebuilder *builder; + git_tree *tree; + git_oid id, bid, subtree_id, id2, id3; + git_oid id_hiearar; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + git_oid_mkstr(&id, first_tree); + git_oid_mkstr(&id2, second_tree); + git_oid_mkstr(&id3, third_tree); + git_oid_mkstr(&bid, blob_oid); + + //create subtree + must_pass(git_treebuilder_create(&builder, NULL)); + must_pass(git_treebuilder_insert(NULL,builder,"new.txt",&bid,0100644)); + must_pass(git_treebuilder_write(&subtree_id,repo,builder)); + git_treebuilder_free(builder); + + // create parent tree + must_pass(git_tree_lookup(&tree, repo, &id)); + must_pass(git_treebuilder_create(&builder, tree)); + must_pass(git_treebuilder_insert(NULL,builder,"new",&subtree_id,040000)); + must_pass(git_treebuilder_write(&id_hiearar,repo,builder)); + git_treebuilder_free(builder); + git_tree_close(tree); + + must_be_true(git_oid_cmp(&id_hiearar, &id3) == 0); + + // check data is correct + must_pass(git_tree_lookup(&tree, repo, &id_hiearar)); + must_be_true(2 == git_tree_entrycount(tree)); + git_tree_close(tree); + + close_temp_repo(repo); + +END_TEST BEGIN_SUITE(tree) + //ADD_TEST(print0); ADD_TEST(read0); ADD_TEST(read1); -// ADD_TEST(write0); /* TODO THREADSAFE */ -// ADD_TEST(write1); + //ADD_TEST(write0); + //ADD_TEST(write1); + ADD_TEST(write2); + ADD_TEST(write3); END_SUITE diff --git a/vendor/libgit2/tests/t10-refs.c b/vendor/libgit2/tests/t10-refs.c index 565d636ba..ee006a8ce 100644 --- a/vendor/libgit2/tests/t10-refs.c +++ b/vendor/libgit2/tests/t10-refs.c @@ -27,13 +27,14 @@ #include "repository.h" -static const char *loose_tag_ref_name = "refs/tags/test"; +static const char *loose_tag_ref_name = "refs/tags/e90810b"; static const char *non_existing_tag_ref_name = "refs/tags/i-do-not-exist"; BEGIN_TEST(readtag0, "lookup a loose tag reference") git_repository *repo; git_reference *reference; git_object *object; + char ref_name_from_tag_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); @@ -46,6 +47,11 @@ BEGIN_TEST(readtag0, "lookup a loose tag reference") must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_TAG); + /* Ensure the name of the tag matches the name of the reference */ + git__joinpath(ref_name_from_tag_name, GIT_REFS_TAGS_DIR, git_tag_name((git_tag *)object)); + must_be_true(strcmp(ref_name_from_tag_name, loose_tag_ref_name) == 0); + + git_object_close(object); git_repository_free(repo); END_TEST @@ -86,6 +92,7 @@ BEGIN_TEST(readsym0, "lookup a symbolic reference") git_oid_mkstr(&id, current_master_tip); must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0); + git_object_close(object); git_repository_free(repo); END_TEST @@ -112,6 +119,7 @@ BEGIN_TEST(readsym1, "lookup a nested symbolic reference") git_oid_mkstr(&id, current_master_tip); must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0); + git_object_close(object); git_repository_free(repo); END_TEST @@ -170,6 +178,7 @@ BEGIN_TEST(readpacked0, "lookup a packed reference") must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); + git_object_close(object); git_repository_free(repo); END_TEST @@ -189,7 +198,7 @@ END_TEST BEGIN_TEST(create0, "create a new symbolic reference") git_reference *new_reference, *looked_up_ref, *resolved_ref; - git_repository *repo; + git_repository *repo, *repo2; git_oid id; char ref_path[GIT_PATH_MAX]; @@ -197,7 +206,7 @@ BEGIN_TEST(create0, "create a new symbolic reference") git_oid_mkstr(&id, current_master_tip); - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); /* Retrieve the physical path to the symbolic ref for further cleaning */ git__joinpath(ref_path, repo->path_repository, new_head_tracker); @@ -221,15 +230,13 @@ BEGIN_TEST(create0, "create a new symbolic reference") git_repository_free(repo); /* Similar test with a fresh new repository */ - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(git_repository_open(&repo2, TEMP_REPO_FOLDER)); - must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker)); + must_pass(git_reference_lookup(&looked_up_ref, repo2, new_head_tracker)); must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); - git_repository_free(repo); - - must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ + close_temp_repo(repo2); END_TEST BEGIN_TEST(create1, "create a deep symbolic reference") @@ -242,7 +249,7 @@ BEGIN_TEST(create1, "create a deep symbolic reference") git_oid_mkstr(&id, current_master_tip); - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); git__joinpath(ref_path, repo->path_repository, new_head_tracker); must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target)); @@ -250,14 +257,12 @@ BEGIN_TEST(create1, "create a deep symbolic reference") must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); - git_repository_free(repo); - - must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ + close_temp_repo(repo); END_TEST BEGIN_TEST(create2, "create a new OID reference") git_reference *new_reference, *looked_up_ref; - git_repository *repo; + git_repository *repo, *repo2; git_oid id; char ref_path[GIT_PATH_MAX]; @@ -265,7 +270,7 @@ BEGIN_TEST(create2, "create a new OID reference") git_oid_mkstr(&id, current_master_tip); - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); /* Retrieve the physical path to the symbolic ref for further cleaning */ git__joinpath(ref_path, repo->path_repository, new_head); @@ -285,14 +290,139 @@ BEGIN_TEST(create2, "create a new OID reference") git_repository_free(repo); /* Similar test with a fresh new repository */ - must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + must_pass(git_repository_open(&repo2, TEMP_REPO_FOLDER)); - must_pass(git_reference_lookup(&looked_up_ref, repo, new_head)); + must_pass(git_reference_lookup(&looked_up_ref, repo2, new_head)); must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); + close_temp_repo(repo2); +END_TEST + +BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id") + git_reference *new_reference, *looked_up_ref; + git_repository *repo; + git_oid id; + + const char *new_head = "refs/heads/new-head"; + + git_oid_mkstr(&id, "deadbeef3f795b2b4353bcce3a527ad0a4f7f644"); + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + /* Create and write the new object id reference */ + must_fail(git_reference_create_oid(&new_reference, repo, new_head, &id)); + + /* Ensure the reference can't be looked-up... */ + must_fail(git_reference_lookup(&looked_up_ref, repo, new_head)); + git_repository_free(repo); +END_TEST + +static const char *ref_name = "refs/heads/other"; +static const char *ref_master_name = "refs/heads/master"; +static const char *ref_branch_name = "refs/heads/branch"; +static const char *ref_test_name = "refs/heads/test"; +BEGIN_TEST(overwrite0, "Overwrite an existing symbolic reference") + git_reference *ref, *branch_ref; + git_repository *repo; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* The target needds to exist and we need to check the name has changed */ + must_pass(git_reference_create_symbolic(&branch_ref, repo, ref_branch_name, ref_master_name)); + must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_branch_name)); + /* Ensure it points to the right place*/ + must_pass(git_reference_lookup(&ref, repo, ref_name)); + must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC); + must_be_true(!strcmp(git_reference_target(ref), ref_branch_name)); + + /* Ensure we can't create it unless we force it to */ + must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name)); + must_pass(git_reference_create_symbolic_f(&ref, repo, ref_name, ref_master_name)); - must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ + /* Ensure it points to the right place */ + must_pass(git_reference_lookup(&ref, repo, ref_name)); + must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC); + must_be_true(!strcmp(git_reference_target(ref), ref_master_name)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(overwrite1, "Overwrite an existing object id reference") + git_reference *ref; + git_repository *repo; + git_oid id; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + must_pass(git_reference_lookup(&ref, repo, ref_master_name)); + must_be_true(ref->type & GIT_REF_OID); + git_oid_cpy(&id, git_reference_oid(ref)); + + /* Create it */ + must_pass(git_reference_create_oid(&ref, repo, ref_name, &id)); + + must_pass(git_reference_lookup(&ref, repo, ref_test_name)); + must_be_true(ref->type & GIT_REF_OID); + git_oid_cpy(&id, git_reference_oid(ref)); + + /* Ensure we can't overwrite unless we force it */ + must_fail(git_reference_create_oid(&ref, repo, ref_name, &id)); + must_pass(git_reference_create_oid_f(&ref, repo, ref_name, &id)); + + /* Ensure it has been overwritten */ + must_pass(git_reference_lookup(&ref, repo, ref_name)); + must_be_true(!git_oid_cmp(&id, git_reference_oid(ref))); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symbolic one") + git_reference *ref; + git_repository *repo; + git_oid id; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + must_pass(git_reference_lookup(&ref, repo, ref_master_name)); + must_be_true(ref->type & GIT_REF_OID); + git_oid_cpy(&id, git_reference_oid(ref)); + + must_pass(git_reference_create_oid(&ref, repo, ref_name, &id)); + must_fail(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name)); + must_pass(git_reference_create_symbolic_f(&ref, repo, ref_name, ref_master_name)); + + /* Ensure it points to the right place */ + must_pass(git_reference_lookup(&ref, repo, ref_name)); + must_be_true(git_reference_type(ref) & GIT_REF_SYMBOLIC); + must_be_true(!strcmp(git_reference_target(ref), ref_master_name)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object id one") + git_reference *ref; + git_repository *repo; + git_oid id; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + must_pass(git_reference_lookup(&ref, repo, ref_master_name)); + must_be_true(ref->type & GIT_REF_OID); + git_oid_cpy(&id, git_reference_oid(ref)); + + /* Create the symbolic ref */ + must_pass(git_reference_create_symbolic(&ref, repo, ref_name, ref_master_name)); + /* It shouldn't overwrite unless we tell it to */ + must_fail(git_reference_create_oid(&ref, repo, ref_name, &id)); + must_pass(git_reference_create_oid_f(&ref, repo, ref_name, &id)); + + /* Ensure it points to the right place */ + must_pass(git_reference_lookup(&ref, repo, ref_name)); + must_be_true(git_reference_type(ref) & GIT_REF_OID); + must_be_true(!git_oid_cmp(git_reference_oid(ref), &id)); + + close_temp_repo(repo); END_TEST BEGIN_TEST(pack0, "create a packfile for an empty folder") @@ -322,6 +452,11 @@ BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") must_be_true((reference->type & GIT_REF_PACKED) == 0); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); + /* + * We are now trying to pack also a loose reference + * called `points_to_blob`, to make sure we can properly + * pack weak tags + */ must_pass(git_reference_packall(repo)); /* Ensure the packed-refs file exists */ @@ -500,6 +635,25 @@ BEGIN_TEST(rename4, "can not rename a reference with an invalid name") close_temp_repo(repo); END_TEST +BEGIN_TEST(rename5, "can force-rename a reference with the name of an existing reference") + git_reference *looked_up_ref; + git_repository *repo; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* An existing reference... */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); + + /* Can not be renamed to the name of another existing reference. */ + must_pass(git_reference_rename_f(looked_up_ref, packed_test_head_name)); + + /* Check we actually renamed it */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name)); + must_be_true(!strcmp(looked_up_ref->name, packed_test_head_name)); + + close_temp_repo(repo); +END_TEST + BEGIN_TEST(delete0, "deleting a ref which is both packed and loose should remove both tracks in the filesystem") git_reference *looked_up_ref, *another_looked_up_ref; git_repository *repo; @@ -560,7 +714,8 @@ BEGIN_TEST(normalize0, "normalize a direct (OID) reference name") must_fail(ensure_refname_normalized(OID_REF, "refs/heads/a/", NULL)); must_fail(ensure_refname_normalized(OID_REF, "refs/heads/a.", NULL)); must_fail(ensure_refname_normalized(OID_REF, "refs/heads/a.lock", NULL)); - must_fail(ensure_refname_normalized(OID_REF, "refs/dummy/a", NULL)); + must_pass(ensure_refname_normalized(OID_REF, "refs/dummy/a", NULL)); + must_pass(ensure_refname_normalized(OID_REF, "refs/stash", NULL)); must_pass(ensure_refname_normalized(OID_REF, "refs/tags/a", "refs/tags/a")); must_pass(ensure_refname_normalized(OID_REF, "refs/heads/a/b", "refs/heads/a/b")); must_pass(ensure_refname_normalized(OID_REF, "refs/heads/a./b", "refs/heads/a./b")); @@ -723,10 +878,10 @@ BEGIN_TEST(list0, "try to list all the references in our test repo") printf("# %s\n", ref_list.strings[i]); }*/ - /* We have exactly 7 refs in total if we include the packed ones: + /* We have exactly 8 refs in total if we include the packed ones: * there is a reference that exists both in the packfile and as * loose, but we only list it once */ - must_be_true(ref_list.count == 7); + must_be_true(ref_list.count == 8); git_strarray_free(&ref_list); git_repository_free(repo); @@ -760,6 +915,12 @@ BEGIN_SUITE(refs) ADD_TEST(create0); ADD_TEST(create1); ADD_TEST(create2); + ADD_TEST(create3); + + ADD_TEST(overwrite0); + ADD_TEST(overwrite1); + ADD_TEST(overwrite2); + ADD_TEST(overwrite3); ADD_TEST(normalize0); ADD_TEST(normalize1); @@ -773,6 +934,7 @@ BEGIN_SUITE(refs) ADD_TEST(rename2); ADD_TEST(rename3); ADD_TEST(rename4); + ADD_TEST(rename5); ADD_TEST(delete0); ADD_TEST(list0); diff --git a/vendor/libgit2/tests/t12-repo.c b/vendor/libgit2/tests/t12-repo.c index adf20cfd7..70dba4255 100644 --- a/vendor/libgit2/tests/t12-repo.c +++ b/vendor/libgit2/tests/t12-repo.c @@ -194,6 +194,8 @@ BEGIN_TEST(open0, "Open a bare repository that has just been initialized by git" must_pass(remove_placeholders(TEMP_REPO_FOLDER, "dummy-marker.txt")); must_pass(git_repository_open(&repo, TEMP_REPO_FOLDER)); + must_be_true(git_repository_path(repo) != NULL); + must_be_true(git_repository_workdir(repo) == NULL); git_repository_free(repo); must_pass(rmdir_recurs(TEMP_REPO_FOLDER)); @@ -211,6 +213,8 @@ BEGIN_TEST(open1, "Open a standard repository that has just been initialized by must_pass(remove_placeholders(DEST_REPOSITORY_FOLDER, "dummy-marker.txt")); must_pass(git_repository_open(&repo, DEST_REPOSITORY_FOLDER)); + must_be_true(git_repository_path(repo) != NULL); + must_be_true(git_repository_workdir(repo) != NULL); git_repository_free(repo); must_pass(rmdir_recurs(TEMP_REPO_FOLDER)); @@ -244,6 +248,19 @@ BEGIN_TEST(open2, "Open a bare repository with a relative path escaping out of t rmdir_recurs(TEMP_REPO_FOLDER); END_TEST +BEGIN_TEST(empty0, "test if a repository is empty or not") + + git_repository *repo_empty, *repo_normal; + + must_pass(git_repository_open(&repo_normal, REPOSITORY_FOLDER)); + must_be_true(git_repository_is_empty(repo_normal) == 0); + git_repository_free(repo_normal); + + must_pass(git_repository_open(&repo_empty, EMPTY_BARE_REPOSITORY_FOLDER)); + must_be_true(git_repository_is_empty(repo_empty) == 1); + git_repository_free(repo_empty); +END_TEST + BEGIN_SUITE(repository) ADD_TEST(odb0); ADD_TEST(odb1); @@ -253,5 +270,6 @@ BEGIN_SUITE(repository) ADD_TEST(open0); ADD_TEST(open1); ADD_TEST(open2); + ADD_TEST(empty0); END_SUITE diff --git a/vendor/libgit2/tests/t14-hiredis.c b/vendor/libgit2/tests/t14-hiredis.c new file mode 100644 index 000000000..c743f7d48 --- /dev/null +++ b/vendor/libgit2/tests/t14-hiredis.c @@ -0,0 +1,123 @@ +/* + * This file is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, + * as published by the Free Software Foundation. + * + * In addition to the permissions in the GNU General Public License, + * the authors give you unlimited permission to link the compiled + * version of this file into combinations with other programs, + * and to distribute those combinations without any restriction + * coming from the use of this file. (The General Public License + * restrictions do apply in other respects; for example, they cover + * modification of the file, and distribution when not linked into + * a combined executable.) + * + * This file is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ +#include "test_lib.h" +#include "odb.h" + +#ifdef GIT2_HIREDIS_BACKEND +#include "t03-data.h" +#include "fileops.h" +#include "git2/odb_backend.h" + + +static int cmp_objects(git_odb_object *odb_obj, git_rawobj *raw) +{ + if (raw->type != git_odb_object_type(odb_obj)) + return -1; + + if (raw->len != git_odb_object_size(odb_obj)) + return -1; + + if ((raw->len > 0) && (memcmp(raw->data, git_odb_object_data(odb_obj), raw->len) != 0)) + return -1; + + return 0; +} + +static git_odb *open_hiredis_odb(void) +{ + git_odb *odb; + git_odb_backend *hiredis; + + if (git_odb_new(&odb) < GIT_SUCCESS) + return NULL; + + if (git_odb_backend_hiredis(&hiredis, "127.0.0.1", 6379) < GIT_SUCCESS) + return NULL; + + if (git_odb_add_backend(odb, hiredis, 0) < GIT_SUCCESS) + return NULL; + + return odb; +} + +#define TEST_WRITE(PTR) {\ + git_odb *db; \ + git_oid id1, id2; \ + git_odb_object *obj; \ + db = open_hiredis_odb(); \ + must_be_true(db != NULL); \ + must_pass(git_oid_mkstr(&id1, PTR.id)); \ + must_pass(git_odb_write(&id2, db, PTR##_obj.data, PTR##_obj.len, PTR##_obj.type)); \ + must_be_true(git_oid_cmp(&id1, &id2) == 0); \ + must_pass(git_odb_read(&obj, db, &id1)); \ + must_pass(cmp_objects(obj, &PTR##_obj)); \ + git_odb_object_close(obj); \ + git_odb_close(db); \ +} + +BEGIN_TEST(hiredis0, "write a commit, read it back (hiredis backend)") + TEST_WRITE(commit); +END_TEST + +BEGIN_TEST(hiredis1, "write a tree, read it back (hiredis backend)") + TEST_WRITE(tree); +END_TEST + +BEGIN_TEST(hiredis2, "write a tag, read it back (hiredis backend)") + TEST_WRITE(tag); +END_TEST + +BEGIN_TEST(hiredis3, "write a zero-byte entry, read it back (hiredis backend)") + TEST_WRITE(zero); +END_TEST + +BEGIN_TEST(hiredis4, "write a one-byte entry, read it back (hiredis backend)") + TEST_WRITE(one); +END_TEST + +BEGIN_TEST(hiredis5, "write a two-byte entry, read it back (hiredis backend)") + TEST_WRITE(two); +END_TEST + +BEGIN_TEST(hiredis6, "write some bytes in an entry, read it back (hiredis backend)") + TEST_WRITE(some); +END_TEST + + +BEGIN_SUITE(hiredis) + ADD_TEST(hiredis0); + ADD_TEST(hiredis1); + ADD_TEST(hiredis2); + ADD_TEST(hiredis3); + ADD_TEST(hiredis4); + ADD_TEST(hiredis5); + ADD_TEST(hiredis6); +END_SUITE + +#else /* no hiredis builtin */ +BEGIN_SUITE(hiredis) + /* empty */ +END_SUITE +#endif diff --git a/vendor/libgit2/tests/test_lib.c b/vendor/libgit2/tests/test_lib.c index c9c6141c6..5778404c1 100755 --- a/vendor/libgit2/tests/test_lib.c +++ b/vendor/libgit2/tests/test_lib.c @@ -130,6 +130,7 @@ static void free_suite(git_testsuite *ts) if (ts->list[n]) test_free(ts->list[n]); + free(ts->name); free(ts); } diff --git a/vendor/libgit2/tests/test_main.c b/vendor/libgit2/tests/test_main.c index f2a623a48..102688ce1 100644 --- a/vendor/libgit2/tests/test_main.c +++ b/vendor/libgit2/tests/test_main.c @@ -41,6 +41,7 @@ DECLARE_SUITE(tag); DECLARE_SUITE(tree); DECLARE_SUITE(refs); DECLARE_SUITE(sqlite); +DECLARE_SUITE(hiredis); DECLARE_SUITE(repository); DECLARE_SUITE(threads); @@ -59,6 +60,7 @@ static libgit2_suite suite_methods[]= { SUITE_NAME(sqlite), SUITE_NAME(repository), SUITE_NAME(threads), + SUITE_NAME(hiredis) }; #define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods)) diff --git a/vendor/libgit2/wscript b/vendor/libgit2/wscript index b990e148a..f4f8da989 100644 --- a/vendor/libgit2/wscript +++ b/vendor/libgit2/wscript @@ -1,10 +1,11 @@ +from __future__ import with_statement from waflib.Context import Context from waflib.Build import BuildContext, CleanContext, \ InstallContext, UninstallContext # Unix flags -CFLAGS_UNIX = ["-O2", "-Wall", "-Wextra"] -CFLAGS_UNIX_DBG = ['-g'] +CFLAGS_UNIX = ["-O2", "-Wall", "-Wextra", "-fPIC"] +CFLAGS_UNIX_DBG = ['-g', '-O0'] # Windows MSVC flags CFLAGS_WIN32_COMMON = ['/TC', '/W4', '/WX', '/nologo', '/Zi'] @@ -16,7 +17,7 @@ CFLAGS_WIN32_L = ['/RELEASE'] # used for /both/ debug and release builds. # sets the module's checksum in the header. CFLAGS_WIN32_L_DBG = ['/DEBUG'] -ALL_LIBS = ['crypto', 'pthread', 'sqlite3'] +ALL_LIBS = ['crypto', 'pthread', 'sqlite3', 'hiredis'] def options(opt): opt.load('compiler_c') @@ -30,7 +31,9 @@ PPC optimized version (ppc) or the SHA1 functions from OpenSSL (openssl)") opt.add_option('--arch', action='store', default='x86', help='Select target architecture (ia64, x64, x86, x86_amd64, x86_ia64)') opt.add_option('--with-sqlite', action='store_true', default=False, - dest='use_sqlite', help='Disable sqlite support') + dest='use_sqlite', help='Enable sqlite support') + opt.add_option('--with-hiredis', action='store_true', default=False, + dest='use_hiredis', help='Enable redis support using hiredis') opt.add_option('--threadsafe', action='store_true', default=False, help='Make libgit2 thread-safe (requires pthreads)') @@ -62,6 +65,9 @@ def configure(conf): else: conf.env.PLATFORM = 'unix' + if conf.env.DEST_OS == 'sunos': + conf.env.DEFINES += ['NO_VIZ'] + if conf.options.threadsafe: if conf.env.PLATFORM == 'unix': conf.check_cc(lib='pthread', uselib_store='pthread') @@ -72,6 +78,12 @@ def configure(conf): lib='sqlite3', uselib_store='sqlite3', install_path=None, mandatory=False): conf.env.DEFINES += ['GIT2_SQLITE_BACKEND'] + # check for hiredis + if conf.options.use_hiredis and conf.check_cc( + lib='hiredis', uselib_store='hiredis', install_path=None, mandatory=False): + conf.env.DEFINES += ['GIT2_HIREDIS_BACKEND'] + + if conf.options.sha1 not in ['openssl', 'ppc', 'builtin']: conf.fatal('Invalid SHA1 option') diff --git a/wscript b/wscript index e6a5aa07b..4c6d9a816 100755 --- a/wscript +++ b/wscript @@ -4,7 +4,7 @@ import os, shutil, platform from os import system from os.path import exists, abspath -VERSION = '0.0.3' +VERSION = '0.0.4' APPNAME = 'nodegit' srcdir = '.' blddir = 'build'