diff --git a/Makefile b/Makefile index 580f85632..0ac04433d 100644 --- a/Makefile +++ b/Makefile @@ -35,7 +35,7 @@ clean: @@rm -rf $(BASE)/vendor/libgit2/build unittest: - $(NODE_JS) $(BASE)/test/index.js test + @@$(NODE_JS) $(BASE)/test/index.js test lint: - $(NODE_JS) $(BASE)/util/hint-check.js + @@$(NODE_JS) $(BASE)/util/hint-check.js diff --git a/README.md b/README.md index 0d817de03..d6489438d 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ This will install and configure everything you need to use `nodegit`. ### Windows via Cygwin ### -#### `nodegit` has been compiled and tested to work with the setup required to build and run `Node.js` itself. #### +#### `nodegit` has a build issue under Windows that current makes it impossible to use. #### Instructions on compiling `Node.js` on a Windows platform can be found here: [https://github.com/ry/node/wiki/Building-node.js-on-Cygwin-(Windows)](https://github.com/ry/node/wiki/Building-node.js-on-Cygwin-(Windows\)) @@ -73,9 +73,6 @@ API Example Usage console.log( '\n' ); }); }); - - // Memory cleanup - repo.free(); }); #### Raw API #### @@ -186,6 +183,13 @@ Release information __ Can keep track of current method coverage at: [http://bit.ly/tb_methods](http://bit.ly/tb_methods) __ +### v0.0.2: ### + * More methods implemented + * More unit tests + * More API development + * Tree and Blob support + * Updated libgit2 to version 0.8.0 + ### v0.0.1: ### * Some useful methods implemented * Some unit tests @@ -195,17 +199,9 @@ __ Can keep track of current method coverage at: [http://bit.ly/tb_methods](http * An API that can be easily extended with convenience methods in JS * An API that offers a familiar clean syntax that will make adoption and use much more likely * Open for public testing - * Be able to open and read a repo and fetch all its commits and lookup specific commits and their associated metadata + reading blob rawcontent. - -### v0.0.2: ### - * More methods implemented - * More unit tests - * GitHub landing page (already done) - * More API development - -### v0.0.3: ### - * Custom odb backend - * API coverage in GitHub Wiki + * GitHub landing page + * Repo, Oid, Commit, Error, Ref, and RevWalk support + * Built on libgit2 version 0.3.0 Getting involved ---------------- diff --git a/example/convenience-tree.js b/example/convenience-tree.js new file mode 100644 index 000000000..acd771d2f --- /dev/null +++ b/example/convenience-tree.js @@ -0,0 +1,15 @@ +var git = require( 'nodegit' ); + +git.repo( '../.git', function( err, repo ) { + if( err ) { throw err; } + + repo.branch( 'master', function( err, branch ) { + if( err ) { throw err; } + + branch.tree().each( function( i, entry ) { + console.log( entry.name ); + console.log( entry.contents ); + + }); + }); +}); diff --git a/lib/blob.js b/lib/blob.js index 0b835e2bb..88c0effd0 100644 --- a/lib/blob.js +++ b/lib/blob.js @@ -7,12 +7,24 @@ var _Blob = function( obj ) { self.repo = obj; self.blob = new git.raw.Blob( obj ); } - else if ( obj instanceof git.raw.Blob ) { + else if( obj instanceof git.raw.Blob ) { self.blob = obj; } - self.content = function() { - return self.blob.rawContent(); + Object.defineProperty( self, 'raw', { + get: function() { + return self.blob.rawContent(); + }, + enumerable: true + }); + + self.lookup = function( oid ) { + self.blob.lookup( self.repo, oid, function() { + var args = Array.prototype.slice.call( arguments ); + args[0] = git.util().error( args[0] ); + + callback.apply( self, args.concat( self ) ); + }); }; return self; diff --git a/lib/commit.js b/lib/commit.js index b95819e87..94e686da5 100644 --- a/lib/commit.js +++ b/lib/commit.js @@ -1,7 +1,7 @@ var git = require( '../' ); var _Commit = function( obj ) { - var self = {}; + var self = { _cache: {} }; if( obj instanceof git.raw.Repo ) { self.repo = obj; @@ -11,21 +11,6 @@ var _Commit = function( obj ) { self.commit = obj; } - Object.defineProperty( self, 'history', { - get: function() { - // Partially apply the commit - var revwalk = git.revwalk( self.repo ); - revwalk.each = function( callback ) { - return function( callback ) { - return revwalk.walk.apply( self.commit, [ self.commit, callback ] ); - }; - }(); - - return revwalk; - }, - enumerable: true - }); - Object.defineProperty( self, 'sha', { get: function() { var oid = new git.raw.Oid(); @@ -36,7 +21,6 @@ var _Commit = function( obj ) { enumerable: true }); - Object.defineProperty( self, 'msg', { get: function() { return self.commit.messageShort(); @@ -86,18 +70,61 @@ var _Commit = function( obj ) { }); }; - //self.tree = function() { - // var tree = new git.raw.Tree( self.repo ); - // if( tree.error ) { - // throw git.error( tree.error ); - // } - // else { - // self.commit.tree( tree ); - // } + self.tree = function() { + var tree = new git.raw.Tree( self.repo ); + if( tree.error ) { + throw git.error( tree.error ); + } + else { + self.commit.tree( tree ); + } + + return git.tree( tree ); + }; + + self.history = function( callback ) { + var revwalk = git.revwalk( self.repo ); + + + }; + + self.file = function( path ) { + return self.tree().entry( path ); + }; + + //Object.defineProperty( self, 'history', { + // get: function() { + // // Partially apply the commit + // var revwalk = git.revwalk( self.repo ); + // revwalk.each = function( callback ) { + // return function( callback ) { + // return revwalk.walk.apply( self.commit, [ self.commit, callback ] ); + // }; + // }(); + + // return revwalk; + // }, + // enumerable: true + //}); - // return git.tree( tree ); //}; + Object.defineProperty( self, 'history', { + get: function() { + // Partially apply the commit + var revwalk = git.revwalk( self.repo ); + revwalk.each = function( callback ) { + return function( callback ) { + return revwalk.walk.apply( self.commit, [ self.commit, callback ] ); + }; + }(); + + return revwalk; + }, + enumerable: true + }); + + return self; }; diff --git a/lib/index.js b/lib/index.js index 9be04db19..2756a5cdc 100755 --- a/lib/index.js +++ b/lib/index.js @@ -4,10 +4,12 @@ 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, ref = require( './ref.js' ).ref, revwalk = require( './revwalk.js' ).revwalk, commit = require( './commit.js' ).commit, - tree = require( './tree.js' ).tree; + tree = require( './tree.js' ).tree, + entry = require( './tree_entry.js' ).entry; exports.raw = require( '../build/default/nodegit' ); exports.blob = blob; @@ -15,8 +17,10 @@ exports.util = util; exports.repo = repo; exports.ref = ref; exports.oid = oid; +exports.obj = obj; exports.sig = sig; exports.error = error; exports.revwalk = revwalk; -exports.tree = tree; exports.commit = commit; +exports.tree = tree; +exports.entry = entry; diff --git a/lib/obj.js b/lib/obj.js new file mode 100644 index 000000000..163b02600 --- /dev/null +++ b/lib/obj.js @@ -0,0 +1,71 @@ +var git = require( '../' ); + +var _Object = function( obj ) { + var self = {}; + + if( obj instanceof git.raw.Object ) { + self.obj = obj; + } + else { + self.obj = new git.raw.Object(); + } + + Object.defineProperty( self, 'id', { + get: function() { + }, + enumerable: true + }); + + Object.defineProperty( self, 'type', { + get: function() { + return self.obj.type(); + }, + enumerable: true + }); + + Object.defineProperty( self, 'length', { + get: function() { + return self.obj.size(); + }, + enumerable: true + }); + + Object.defineProperty( self, 'isLoose', { + get: function() { + return self.obj.typeIsLoose(); + }, + enumerable: true + }); + + self.id = function() { + var oid = git.oid(); + + self.obj.id( oid.oid ); + + return oid; + }; + + self.owner = function() { + var repo = git.repo(); + + self.obj.owner( repo.repo ); + + return repo; + }; + + self.toString = function() { + return self.obj.type2String(); + }; + + self.toType = function( type ) { + return self.obj.toType( type ); + }; + + self.free = function() { + return self.obj.free(); + }; + + return self; +}; + +exports.obj = _Object; diff --git a/lib/ref.js b/lib/ref.js index b945c804a..84d786a0e 100644 --- a/lib/ref.js +++ b/lib/ref.js @@ -11,6 +11,17 @@ var _Ref = function( obj ) { self.ref = obj; } + self.lookup = function( name, callback ) { + if( !callback ) { return; } + + self.ref.lookup( self.repo, name, function() { + var args = Array.prototype.slice.call( arguments ); + args[0] = git.util().error( args[0] ); + + callback.apply( self, args.concat( self ) ); + }); + }; + self.oid = function() { var oid = git.oid(); diff --git a/lib/repo.js b/lib/repo.js index 610c45531..84d1b5ec5 100644 --- a/lib/repo.js +++ b/lib/repo.js @@ -26,7 +26,7 @@ var _Repo = function( dir, callback ) { self.branch = function( name, callback ) { if( !callback ) { return; } - self.ref( 'refs/heads/' + name, function( err, ref ) { + git.ref( self.repo ).lookup( 'refs/heads/' + name, function( err, ref ) { if( err ) { throw err; } git.commit( self.repo ).lookup( ref.oid().oid, function() { @@ -38,20 +38,6 @@ var _Repo = function( dir, callback ) { }); }; - // Work with a specific head reference - self.ref = function( name, callback ) { - if( !callback ) { return; } - - var ref = git.ref( self.repo ); - - self.repo.lookupRef( ref.ref, name, function() { - var args = Array.prototype.slice.call( arguments ); - args[0] = git.util().error( args[0] ); - - callback.apply( ref, args.concat( ref ) ); - }); - }; - // Find a single commit self.commit = function( sha, callback ) { if( !callback ) { return; } diff --git a/lib/tree.js b/lib/tree.js index e6becaf82..d2c9b8662 100644 --- a/lib/tree.js +++ b/lib/tree.js @@ -3,29 +3,13 @@ var git = require( '../' ); var _Tree = function( obj, tree ) { var self = {}; - //Object.defineProperty( self, 'length', { - // get: function() { - // return self.tree.entryCount(); - // }, - // enumerable: true - //}); - - self.each = function( callback ) { - if( !callback ) { return; } - - var commit, i; - for(i=0, len=self.length; i (http://twitter.com/tbranyen)", "main": "./lib/index.js", diff --git a/src/base.cc b/src/base.cc index cf2e332fe..925537bd5 100755 --- a/src/base.cc +++ b/src/base.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "reference.h" #include "sig.h" @@ -18,6 +18,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include "commit.h" #include "revwalk.h" #include "tree.h" +#include "tree_entry.h" extern "C" void init(Handle target) { HandleScope scope; @@ -32,4 +33,5 @@ extern "C" void init(Handle target) { Commit::Initialize(target); RevWalk::Initialize(target); GitTree::Initialize(target); + GitTreeEntry::Initialize(target); } diff --git a/src/blob.cc b/src/blob.cc index 45da1c592..8a722c81f 100755 --- a/src/blob.cc +++ b/src/blob.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "blob.h" @@ -74,7 +74,7 @@ Handle Blob::New(const Arguments& args) { Handle Blob::RawContent(const Arguments& args) { HandleScope scope; - Blob *blob = new Blob(); + Blob *blob = ObjectWrap::Unwrap(args.This()); return String::New(blob->RawContent()); } @@ -116,8 +116,7 @@ Handle Blob::Lookup(const Arguments& args) { int Blob::EIO_Lookup(eio_req *req) { lookup_request *ar = static_cast(req->data); - int err = ar->blob->Lookup(ar->repo->GetValue(), ar->oid->GetValue()); - ar->err = Persistent::New(Integer::New(err)); + ar->err = ar->blob->Lookup(ar->repo->GetValue(), ar->oid->GetValue()); return 0; } @@ -130,7 +129,7 @@ int Blob::EIO_AfterLookup(eio_req *req) { ar->blob->Unref(); Local argv[1]; - argv[0] = Number::Cast(*ar->err); + argv[0] = Integer::New(ar->err); TryCatch try_catch; @@ -139,7 +138,6 @@ int Blob::EIO_AfterLookup(eio_req *req) { if(try_catch.HasCaught()) FatalException(try_catch); - ar->err.Dispose(); ar->callback.Dispose(); delete ar; diff --git a/src/blob.h b/src/blob.h index 5f785f29d..5967f5118 100755 --- a/src/blob.h +++ b/src/blob.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" @@ -105,7 +105,7 @@ class Blob : public EventEmitter { Blob *blob; Repo *repo; Oid *oid; - Persistent err; + int err; Persistent callback; }; }; diff --git a/src/commit.cc b/src/commit.cc index ca6e83606..80df916d1 100755 --- a/src/commit.cc +++ b/src/commit.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "reference.h" #include "sig.h" @@ -151,7 +151,7 @@ Handle Commit::Lookup(const Arguments& args) { int Commit::EIO_Lookup(eio_req *req) { lookup_request *ar = static_cast(req->data); - ar->err = Persistent::New(Integer::New(ar->commit->Lookup(ar->repo->GetValue(), ar->oid->GetValue()))); + ar->err = ar->commit->Lookup(ar->repo->GetValue(), ar->oid->GetValue()); return 0; } @@ -166,7 +166,7 @@ int Commit::EIO_AfterLookup(eio_req *req) { git_commit *commit = ar->commit->GetValue(); Local argv[1]; - argv[0] = *ar->err; + argv[0] = Integer::New(ar->err); TryCatch try_catch; @@ -175,7 +175,6 @@ int Commit::EIO_AfterLookup(eio_req *req) { if(try_catch.HasCaught()) FatalException(try_catch); - ar->err.Dispose(); ar->callback.Dispose(); delete ar; diff --git a/src/commit.h b/src/commit.h index efc60c9db..ef2f86f98 100755 --- a/src/commit.h +++ b/src/commit.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "reference.h" #include "repo.h" @@ -83,7 +83,7 @@ class Commit : public EventEmitter { Commit* commit; Repo* repo; Oid* oid; - Persistent err; + int err; Persistent callback; }; diff --git a/src/error.cc b/src/error.cc index 7c9e32b1d..18f50cb47 100755 --- a/src/error.cc +++ b/src/error.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "error.h" diff --git a/src/error.h b/src/error.h index 8a21aad56..e6c7d7492 100755 --- a/src/error.h +++ b/src/error.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" using namespace v8; using namespace node; diff --git a/src/object.cc b/src/object.cc index 37e192d72..70476057a 100755 --- a/src/object.cc +++ b/src/object.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "object.h" #include "repo.h" @@ -27,7 +27,6 @@ void GitObject::Initialize (Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor_template, "id", Id); NODE_SET_PROTOTYPE_METHOD(constructor_template, "type", Type); NODE_SET_PROTOTYPE_METHOD(constructor_template, "owner", Owner); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "free", Free); NODE_SET_PROTOTYPE_METHOD(constructor_template, "type2String", Type2String); NODE_SET_PROTOTYPE_METHOD(constructor_template, "string2Type", String2Type); NODE_SET_PROTOTYPE_METHOD(constructor_template, "typeIsLoose", TypeIsLoose); @@ -71,10 +70,6 @@ git_repository* GitObject::Owner() { return git_object_owner(this->obj); } -void GitObject::Free() { - git_object_free(this->obj); -} - const char* GitObject::Type2String(git_otype type) { return git_object_type2string(type); } @@ -141,16 +136,6 @@ Handle GitObject::Owner(const Arguments& args) { return Undefined(); } -Handle GitObject::Free(const Arguments& args) { - HandleScope scope; - - GitObject *obj = ObjectWrap::Unwrap(args.This()); - - obj->Free(); - - return Undefined(); -} - Handle GitObject::Type2String(const Arguments& args) { HandleScope scope; diff --git a/src/object.h b/src/object.h index 8129a75c2..92a3914da 100755 --- a/src/object.h +++ b/src/object.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "oid.h" @@ -51,7 +51,6 @@ class GitObject : public EventEmitter { git_otype Type(); git_repository* Owner(); - void Free(); const char* Type2String(git_otype type); git_otype String2Type(const char* type); int TypeIsLoose(git_otype type); @@ -79,7 +78,6 @@ class GitObject : public EventEmitter { static Handle Id(const Arguments& args); static Handle Type(const Arguments& args); static Handle Owner(const Arguments& args); - static Handle Free(const Arguments& args); static Handle Type2String(const Arguments& args); static Handle String2Type(const Arguments& args); static Handle TypeIsLoose(const Arguments& args); diff --git a/src/oid.cc b/src/oid.cc index cc6ada3e8..513e134d4 100755 --- a/src/oid.cc +++ b/src/oid.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "oid.h" @@ -25,7 +25,11 @@ void Oid::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor_template, "mkstr", Mkstr); NODE_SET_PROTOTYPE_METHOD(constructor_template, "mkraw", Mkraw); NODE_SET_PROTOTYPE_METHOD(constructor_template, "fmt", Fmt); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "pathFmt", PathFmt); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "allocFmt", AllocFmt); NODE_SET_PROTOTYPE_METHOD(constructor_template, "toString", ToString); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "cpy", Cpy); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "cmp", Cmp); target->Set(String::NewSymbol("Oid"), constructor_template->GetFunction()); } @@ -47,7 +51,7 @@ void Oid::Mkraw(const unsigned char* raw) { } char* Oid::Fmt(char* buffer) { - git_oid_fmt(*&buffer, &this->oid); + git_oid_fmt(buffer, &this->oid); } void Oid::PathFmt(char* str) { @@ -113,7 +117,7 @@ Handle Oid::Fmt(const Arguments& args) { HandleScope scope; - char buffer[40]; + char buffer[32]; oid->Fmt(buffer); return String::New(buffer); } diff --git a/src/oid.h b/src/oid.h index 8812812f0..92550471e 100755 --- a/src/oid.h +++ b/src/oid.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" using namespace node; using namespace v8; diff --git a/src/reference.cc b/src/reference.cc index cad0765eb..fc2cdc4e9 100755 --- a/src/reference.cc +++ b/src/reference.cc @@ -5,8 +5,9 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include #include +#include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "reference.h" @@ -25,6 +26,7 @@ void Reference::Initialize(Handle target) { constructor_template->SetClassName(String::NewSymbol("Ref")); NODE_SET_PROTOTYPE_METHOD(constructor_template, "oid", _Oid); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookup", Lookup); target->Set(String::NewSymbol("Ref"), constructor_template->GetFunction()); } @@ -37,8 +39,8 @@ void Reference::SetValue(git_reference *ref) { this->ref = ref; } -int Reference::New(git_repository* repo) { - return git_reference_new(&this->ref, repo); +int Reference::Lookup(git_repository* repo, const char* name) { + return git_reference_lookup(&this->ref, repo, name); } const git_oid* Reference::_Oid() { @@ -50,16 +52,80 @@ Handle Reference::New(const Arguments& args) { Reference *ref = new Reference(); + ref->Wrap(args.This()); + + return args.This(); +} + +Handle Reference::Lookup(const Arguments& args) { + Reference *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 an Object."))); + return ThrowException(Exception::Error(String::New("Repo is required and must be a Object."))); } - Repo *repo = ObjectWrap::Unwrap(args[0]->ToObject()); - ref->New((git_repository *)repo); + if(args.Length() == 1 || !args[1]->IsString()) { + return ThrowException(Exception::Error(String::New("Name is required and must be a String."))); + } - ref->Wrap(args.This()); + if(args.Length() == 2 || !args[2]->IsFunction()) { + return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); + } - return args.This(); + callback = Local::Cast(args[2]); + + lookup_request *ar = new lookup_request(); + ar->ref = ref; + ar->repo = ObjectWrap::Unwrap(args[0]->ToObject()); + + String::Utf8Value name(args[1]); + ar->name = *name; + + ar->callback = Persistent::New(callback); + + ref->Ref(); + + eio_custom(EIO_Lookup, EIO_PRI_DEFAULT, EIO_AfterLookup, ar); + ev_ref(EV_DEFAULT_UC); + + return Undefined(); +} + +int Reference::EIO_Lookup(eio_req *req) { + lookup_request *ar = static_cast(req->data); + + git_repository* repo = ar->repo->GetValue(); + + ar->err = ar->ref->Lookup(repo, ar->name.c_str()); + + return 0; +} + +int Reference::EIO_AfterLookup(eio_req *req) { + HandleScope scope; + + lookup_request *ar = static_cast(req->data); + ev_unref(EV_DEFAULT_UC); + ar->ref->Unref(); + + Local argv[1]; + argv[0] = Integer::New(ar->err); + + TryCatch try_catch; + + ar->callback->Call(Context::GetCurrent()->Global(), 1, argv); + + if(try_catch.HasCaught()) + FatalException(try_catch); + + ar->callback.Dispose(); + + delete ar; + + return 0; } Handle Reference::_Oid(const Arguments& args) { diff --git a/src/reference.h b/src/reference.h index 34a46bf10..195bb438f 100755 --- a/src/reference.h +++ b/src/reference.h @@ -8,9 +8,11 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include #include +#include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" +#include "repo.h" #include "oid.h" using namespace node; @@ -21,8 +23,8 @@ class Reference : public EventEmitter { static Persistent constructor_template; static void Initialize(Handle target); git_reference* GetValue(); - int New(git_repository* repo); void SetValue(git_reference* ref); + int Lookup(git_repository* repo, const char* name); const git_oid* _Oid(); protected: @@ -30,10 +32,22 @@ class Reference : public EventEmitter { ~Reference() {} static Handle New(const Arguments& args); + static Handle Lookup(const Arguments& args); + static int EIO_Lookup(eio_req* req); + static int EIO_AfterLookup(eio_req* req); + static Handle _Oid(const Arguments& args); private: git_reference *ref; + + struct lookup_request { + Reference* ref; + Repo* repo; + int err; + std::string name; + Persistent callback; + }; }; #endif diff --git a/src/repo.cc b/src/repo.cc index b010f0c6f..2f3bafc2f 100755 --- a/src/repo.cc +++ b/src/repo.cc @@ -5,10 +5,10 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include #include +#include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" -#include "reference.h" #include "object.h" #include "repo.h" #include "commit.h" @@ -29,7 +29,6 @@ void Repo::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookup", Lookup); NODE_SET_PROTOTYPE_METHOD(constructor_template, "free", Free); NODE_SET_PROTOTYPE_METHOD(constructor_template, "init", Init); - NODE_SET_PROTOTYPE_METHOD(constructor_template, "lookupRef", LookupRef); target->Set(String::NewSymbol("Repo"), constructor_template->GetFunction()); } @@ -61,10 +60,6 @@ int Repo::Init(const char* path, bool is_bare) { return err; } -int Repo::LookupRef(git_reference** ref, const char* name) { - return git_repository_lookup_ref(ref, *&this->repo, name); -} - Handle Repo::New(const Arguments& args) { HandleScope scope; @@ -92,7 +87,10 @@ Handle Repo::Open(const Arguments& args) { open_request *ar = new open_request(); ar->repo = repo; - ar->path = Persistent::New(args[0]); + + String::Utf8Value path(args[0]); + ar->path = *path; + ar->callback = Persistent::New(callback); repo->Ref(); @@ -106,8 +104,7 @@ Handle Repo::Open(const Arguments& args) { int Repo::EIO_Open(eio_req *req) { open_request *ar = static_cast(req->data); - String::Utf8Value path(ar->path); - ar->err = Persistent::New( Integer::New(ar->repo->Open(*path)) ); + ar->err = ar->repo->Open(ar->path.c_str()); return 0; } @@ -120,7 +117,7 @@ int Repo::EIO_AfterOpen(eio_req *req) { ar->repo->Unref(); Local argv[1]; - argv[0] = Number::Cast(*ar->err); + argv[0] = Integer::New(ar->err); TryCatch try_catch; @@ -129,8 +126,6 @@ int Repo::EIO_AfterOpen(eio_req *req) { if(try_catch.HasCaught()) FatalException(try_catch); - ar->err.Dispose(); - ar->path.Dispose(); ar->callback.Dispose(); delete ar; @@ -168,8 +163,8 @@ Handle Repo::Lookup(const Arguments& args) { repo->Ref(); - eio_custom(EIO_LookupRef, EIO_PRI_DEFAULT, EIO_AfterLookupRef, ar); - ev_ref(EV_DEFAULT_UC); + //eio_custom(EIO_LookupRef, EIO_PRI_DEFAULT, EIO_AfterLookupRef, ar); + //ev_ref(EV_DEFAULT_UC); return Undefined(); } @@ -248,8 +243,11 @@ Handle Repo::Init(const Arguments& args) { init_request *ar = new init_request(); ar->repo = repo; - ar->path = Persistent::New( args[0] ); - ar->is_bare = Persistent::New( args[1]->ToBoolean() ); + + String::Utf8Value path(args[0]); + ar->path = *path; + + ar->is_bare = args[1]->ToBoolean()->Value(); ar->callback = Persistent::New(callback); repo->Ref(); @@ -263,9 +261,7 @@ Handle Repo::Init(const Arguments& args) { int Repo::EIO_Init(eio_req *req) { init_request *ar = static_cast(req->data); - String::Utf8Value path(ar->path); - Local is_bare = ar->is_bare->ToBoolean(); - ar->err = Persistent::New(Integer::New(ar->repo->Init(*path, *is_bare))); + ar->err = ar->repo->Init(ar->path.c_str(), ar->is_bare); return 0; } @@ -277,87 +273,8 @@ int Repo::EIO_AfterInit(eio_req *req) { ev_unref(EV_DEFAULT_UC); ar->repo->Unref(); - Local argv[3]; - argv[0] = Number::Cast(*ar->err); - argv[1] = *ar->is_bare; - - TryCatch try_catch; - - ar->callback->Call(Context::GetCurrent()->Global(), 2, argv); - - if(try_catch.HasCaught()) - FatalException(try_catch); - - ar->err.Dispose(); - ar->path.Dispose(); - ar->is_bare.Dispose(); - ar->callback.Dispose(); - - delete ar; - - return 0; -} - -Handle Repo::LookupRef(const Arguments& args) { - Repo *repo = ObjectWrap::Unwrap(args.This()); - Local callback; - - HandleScope scope; - - if(args.Length() == 0 || !args[0]->IsObject()) { - return ThrowException(Exception::Error(String::New("Reference is required and must be a Object."))); - } - - if(args.Length() == 1 || !args[1]->IsString()) { - return ThrowException(Exception::Error(String::New("Name is required and must be a String."))); - } - - if(args.Length() == 2 || !args[2]->IsFunction()) { - return ThrowException(Exception::Error(String::New("Callback is required and must be a Function."))); - } - - callback = Local::Cast(args[2]); - - lookupref_request *ar = new lookupref_request(); - ar->repo = repo; - ar->ref = ObjectWrap::Unwrap(args[0]->ToObject()); - ar->name = Persistent::New(args[1]->ToString()); - ar->callback = Persistent::New(callback); - - repo->Ref(); - - eio_custom(EIO_LookupRef, EIO_PRI_DEFAULT, EIO_AfterLookupRef, ar); - ev_ref(EV_DEFAULT_UC); - - return Undefined(); -} - -int Repo::EIO_LookupRef(eio_req *req) { - lookupref_request *ar = static_cast(req->data); - - String::Utf8Value name(ar->name); - git_reference* ref = ar->ref->GetValue(); - git_reference** out = &ref; - - int err = ar->repo->LookupRef(out, *name); - ar->err = Persistent::New(Integer::New(err)); - - if(Int32::Cast(*ar->err)->Value() == 0) { - ar->ref->SetValue(*out); - } - - return 0; -} - -int Repo::EIO_AfterLookupRef(eio_req *req) { - HandleScope scope; - - lookupref_request *ar = static_cast(req->data); - ev_unref(EV_DEFAULT_UC); - ar->repo->Unref(); - - Local argv[1]; - argv[0] = Number::Cast(*ar->err); + Local argv[2]; + argv[0] = Integer::New(ar->err); TryCatch try_catch; @@ -366,13 +283,10 @@ int Repo::EIO_AfterLookupRef(eio_req *req) { if(try_catch.HasCaught()) FatalException(try_catch); - ar->err.Dispose(); - ar->name.Dispose(); ar->callback.Dispose(); delete ar; return 0; } - Persistent Repo::constructor_template; diff --git a/src/repo.h b/src/repo.h index a0f614c45..cdfefc5ea 100755 --- a/src/repo.h +++ b/src/repo.h @@ -8,10 +8,10 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include #include +#include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" -#include "reference.h" #include "object.h" using namespace node; @@ -26,7 +26,6 @@ class Repo : public EventEmitter { // Asynchronous int Open(const char* path); int Init(const char* path, bool is_bare); - int LookupRef(git_reference** ref, const char* name); // Synchronous void Free(); @@ -44,51 +43,39 @@ class Repo : public EventEmitter { static Handle New(const Arguments& args); static Handle Open(const Arguments& args); - static int EIO_Open(eio_req *req); - static int EIO_AfterOpen(eio_req *req); + static int EIO_Open(eio_req* req); + static int EIO_AfterOpen(eio_req* req); static Handle Lookup(const Arguments& args); - static int EIO_Lookup(eio_req *req); - static int EIO_AfterLookup(eio_req *req); + static int EIO_Lookup(eio_req* req); + static int EIO_AfterLookup(eio_req* req); static Handle Free(const Arguments& args); static Handle Init(const Arguments& args); - static int EIO_Init(eio_req *req); - static int EIO_AfterInit(eio_req *req); - - static Handle LookupRef(const Arguments& args); - static int EIO_LookupRef(eio_req *req); - static int EIO_AfterLookupRef(eio_req *req); + static int EIO_Init(eio_req* req); + static int EIO_AfterInit(eio_req* req); private: - git_repository *repo; + git_repository* repo; struct open_request { - Repo *repo; - Persistent err; - Persistent path; + Repo* repo; + int err; + std::string path; Persistent callback; }; struct lookup_request { - Repo *repo; + Repo* repo; Persistent callback; }; struct init_request { - Repo *repo; - Persistent err; - Persistent path; - Persistent is_bare; - Persistent callback; - }; - - struct lookupref_request { - Repo *repo; - Reference *ref; - Persistent err; - Persistent name; + Repo* repo; + int err; + std::string path; + bool is_bare; Persistent callback; }; }; diff --git a/src/revwalk.cc b/src/revwalk.cc index 002009696..13554b583 100755 --- a/src/revwalk.cc +++ b/src/revwalk.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "revwalk.h" #include "repo.h" @@ -153,7 +153,7 @@ int RevWalk::EIO_Next(eio_req *req) { next_request *ar = static_cast(req->data); git_commit* ref = ar->commit->GetValue(); - ar->err = Persistent::New(Integer::New(ar->revwalk->Next(&ref))); + ar->err = ar->revwalk->Next(&ref); ar->commit->SetValue(ref); @@ -168,7 +168,7 @@ int RevWalk::EIO_AfterNext(eio_req *req) { ar->revwalk->Unref(); Local argv[1]; - argv[0] = *ar->err; + argv[0] = Integer::New(ar->err); TryCatch try_catch; @@ -177,7 +177,6 @@ int RevWalk::EIO_AfterNext(eio_req *req) { if(try_catch.HasCaught()) FatalException(try_catch); - ar->err.Dispose(); ar->callback.Dispose(); delete ar; diff --git a/src/revwalk.h b/src/revwalk.h index 679f09aa7..dd05b2287 100755 --- a/src/revwalk.h +++ b/src/revwalk.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "commit.h" @@ -55,7 +55,7 @@ class RevWalk : public EventEmitter { struct next_request { RevWalk *revwalk; Commit *commit; - Persistent err; + int err; Persistent callback; }; }; diff --git a/src/sig.cc b/src/sig.cc index 541f62953..aedac5f82 100755 --- a/src/sig.cc +++ b/src/sig.cc @@ -6,7 +6,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "sig.h" diff --git a/src/sig.h b/src/sig.h index 00acb5cd9..70a9647e2 100755 --- a/src/sig.h +++ b/src/sig.h @@ -9,7 +9,7 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" diff --git a/src/tree.cc b/src/tree.cc index df9beac59..1904cf7d9 100755 --- a/src/tree.cc +++ b/src/tree.cc @@ -6,10 +6,11 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" #include "tree.h" +#include "tree_entry.h" using namespace v8; using namespace node; @@ -25,6 +26,7 @@ void GitTree::Initialize (Handle target) { NODE_SET_PROTOTYPE_METHOD(constructor_template, "entryCount", EntryCount); NODE_SET_PROTOTYPE_METHOD(constructor_template, "entryByIndex", EntryByIndex); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "entryByName", EntryByName); NODE_SET_PROTOTYPE_METHOD(constructor_template, "sortEntries", EntryCount); NODE_SET_PROTOTYPE_METHOD(constructor_template, "clearEntries", ClearEntries); @@ -44,7 +46,15 @@ int GitTree::New(git_repository* repo) { } size_t GitTree::EntryCount() { - return git_tree_entrycount(&*this->tree); + return git_tree_entrycount(this->tree); +} + +git_tree_entry* GitTree::EntryByIndex(int idx) { + return git_tree_entry_byindex(this->tree, idx); +} + +git_tree_entry* GitTree::EntryByName(const char* name) { + return git_tree_entry_byname(this->tree, name); } int GitTree::SortEntries() { @@ -90,9 +100,45 @@ Handle GitTree::EntryByIndex(const Arguments& args) { GitTree *tree = ObjectWrap::Unwrap(args.This()); + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("TreeEntry is required and must be a Object."))); + } + + if(args.Length() == 1 || !args[1]->IsNumber()) { + return ThrowException(Exception::Error(String::New("Index is required and must be a Number."))); + } + + GitTreeEntry* entry = ObjectWrap::Unwrap(args[0]->ToObject()); + + int index = args[1]->ToInteger()->Value(); + + entry->SetValue(tree->EntryByIndex(index)); + + return Undefined(); +} + +Handle GitTree::EntryByName(const Arguments& args) { + HandleScope scope; + + GitTree *tree = ObjectWrap::Unwrap(args.This()); + + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("TreeEntry is required and must be a Object."))); + } + + if(args.Length() == 1 || !args[1]->IsString()) { + return ThrowException(Exception::Error(String::New("Name is required and must be a String."))); + } + + GitTreeEntry* entry = ObjectWrap::Unwrap(args[0]->ToObject()); + + int index = args[1]->ToInteger()->Value(); + + String::Utf8Value name(args[1]->ToString()); + + entry->SetValue(tree->EntryByName(*name)); return Undefined(); - //return Local::New(Integer::New(count)); } Handle GitTree::SortEntries(const Arguments& args) { diff --git a/src/tree.h b/src/tree.h index 4207f6853..c4d0579d8 100755 --- a/src/tree.h +++ b/src/tree.h @@ -9,9 +9,10 @@ Copyright (c) 2011, Tim Branyen @tbranyen #include #include -#include "../vendor/libgit2/src/git2.h" +#include "../vendor/libgit2/include/git2.h" #include "repo.h" +#include "tree_entry.h" using namespace v8; using namespace node; @@ -49,9 +50,9 @@ class GitTree : public EventEmitter { git_tree* GetValue(); /** - * Mutator for Object + * Mutator for GitTree * - * @param obj a git_object object + * @param obj a git_tree object */ void SetValue(git_tree* tree); @@ -76,15 +77,17 @@ class GitTree : public EventEmitter { /** * Get entry by index in the looked up tree. * + * @param idx index of the entry + * * @return git tree entry */ - //GitTree::Entry EntryByIndex(); + git_tree_entry* EntryByIndex(int idx); + + git_tree_entry* EntryByName(const char* name); int SortEntries(); void ClearEntries(); - - protected: /** * Constructor @@ -107,15 +110,10 @@ class GitTree : public EventEmitter { static Handle EntryCount(const Arguments& args); static Handle EntryByIndex(const Arguments& args); + static Handle EntryByName(const Arguments& args); static Handle SortEntries(const Arguments& args); static Handle ClearEntries(const Arguments& args); - // Experimental - class Entry : EventEmitter { - private: - git_tree_entry* entry; - }; - private: /** * Internal reference to git_tree object diff --git a/src/tree_entry.cc b/src/tree_entry.cc new file mode 100644 index 000000000..c1d545080 --- /dev/null +++ b/src/tree_entry.cc @@ -0,0 +1,101 @@ +/* +Copyright (c) 2011, Tim Branyen @tbranyen +*/ + +#include +#include +#include + +#include "../vendor/libgit2/include/git2.h" + +#include "repo.h" +#include "blob.h" +#include "tree.h" +#include "object.h" +#include "oid.h" +#include "tree_entry.h" + +using namespace v8; +using namespace node; + +void GitTreeEntry::Initialize(Handle target) { + Local t = FunctionTemplate::New(New); + + constructor_template = Persistent::New(t); + constructor_template->InstanceTemplate()->SetInternalFieldCount(1); + constructor_template->SetClassName(String::NewSymbol("TreeEntry")); + + NODE_SET_PROTOTYPE_METHOD(constructor_template, "name", Name); + NODE_SET_PROTOTYPE_METHOD(constructor_template, "toObject", ToObject); + + target->Set(String::NewSymbol("TreeEntry"), constructor_template->GetFunction()); +} + +void GitTreeEntry::SetValue(git_tree_entry* entry) { + this->entry = entry; +} + +const char* GitTreeEntry::Name() { + return git_tree_entry_name(this->entry); +} + +const git_oid* GitTreeEntry::Id() { + return git_tree_entry_id(this->entry); +} + +int GitTreeEntry::ToObject(git_object** obj) { + return git_tree_entry_2object(obj, this->entry); +} + +Handle GitTreeEntry::New(const Arguments& args) { + HandleScope scope; + + GitTreeEntry *entry = new GitTreeEntry(); + + entry->Wrap(args.This()); + + return args.This(); +} + +Handle GitTreeEntry::Name(const Arguments& args) { + HandleScope scope; + + GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); + + return String::New(entry->Name()); +} + +Handle GitTreeEntry::Id(const Arguments& args) { + HandleScope scope; + + GitTreeEntry *entry = 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."))); + } + + Oid* oid = ObjectWrap::Unwrap(args[0]->ToObject()); + + oid->SetValue(const_cast(entry->Id())); + + return Undefined(); +} + +Handle GitTreeEntry::ToObject(const Arguments& args) { + HandleScope scope; + + GitTreeEntry *entry = ObjectWrap::Unwrap(args.This()); + + if(args.Length() == 0 || !args[0]->IsObject()) { + return ThrowException(Exception::Error(String::New("Blob is required and must be an Object."))); + } + + Blob* blob = ObjectWrap::Unwrap(args[0]->ToObject()); + + git_object* out; + entry->ToObject(&out); + blob->SetValue((git_blob *)out); + + return Undefined(); +} +Persistent GitTreeEntry::constructor_template; diff --git a/src/tree_entry.h b/src/tree_entry.h new file mode 100644 index 000000000..775ab099e --- /dev/null +++ b/src/tree_entry.h @@ -0,0 +1,66 @@ +/* +Copyright (c) 2011, Tim Branyen @tbranyen +*/ + +#ifndef GITTREEENTRY_H +#define GITTREEENTRY_H + +#include +#include +#include + +#include "../vendor/libgit2/include/git2.h" + +#include "repo.h" +#include "tree.h" +#include "oid.h" +#include "object.h" + +using namespace v8; +using namespace node; + +/** + * Class wrapper for libgit2 git_tree_entry + */ +class GitTreeEntry : EventEmitter { + public: + /** + * v8::FunctionTemplate used to create Node.js constructor + */ + static Persistent constructor_template; + + /** + * Used to intialize the EventEmitter from Node.js + * + * @param target v8::Object the Node.js module object + */ + static void Initialize(Handle target); + + /** + * Accessor for GitTreeEntry + * + * @return the internal git_tree_entry reference + */ + git_tree_entry* GetValue(); + + /** + * Mutator for GitTreeEntry + * + * @param obj a git_tree_entry object + */ + void SetValue(git_tree_entry* tree); + const char* Name(); + const git_oid* Id(); + int ToObject(git_object** obj); + + protected: + static Handle New(const Arguments& args); + static Handle Name(const Arguments& args); + static Handle Id(const Arguments& args); + static Handle ToObject(const Arguments& args); + + private: + git_tree_entry* entry; +}; + +#endif diff --git a/test/index.js b/test/index.js index a28f8c524..843987578 100644 --- a/test/index.js +++ b/test/index.js @@ -5,7 +5,7 @@ require.paths.unshift( '../vendor' ); try { var reporter = require( '../vendor/nodeunit' ).reporters.default; } -catch(e) { +catch( e ) { var sys = require( 'sys' ); sys.puts( 'Cannot find nodeunit module.' ); sys.puts( 'You can download submodules for this project by doing:' ); @@ -34,15 +34,34 @@ process.chdir( './test' ); reporter.run( [ // Raw API - 'raw-repo.js', - 'raw-oid.js', + '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 + // Sig + // Tree + // Tree Entry + // Util // TODO: //'raw-revwalk.js', // Convenience API 'convenience-repo.js' + // Blob + // Commit + // Error + // Obj + // Oid + // Ref + // RevWalk + // Sig + // Tree + // TreeEntry ] ); diff --git a/test/raw-blob.js b/test/raw-blob.js new file mode 100644 index 000000000..c775298df --- /dev/null +++ b/test/raw-blob.js @@ -0,0 +1,67 @@ +var git = require( '../' ).raw, + rimraf = require( '../vendor/rimraf' ); + +var testRepo = new git.Repo(); + +// Helper functions +var helper = { + // Test if obj is a true function + testFunction: function( test, obj, label ) { + // The object reports itself as a function + test( typeof obj, 'function', label +' reports as a function.' ); + // This ensures the repo is actually a derivative of the Function [[Class]] + test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + }, + // Test code and handle exception thrown + testException: function( test, fun, label ) { + try { + fun(); + test( false, label ); + } + catch (ex) { + test( true, label ); + } + } +}; + +// Blob +exports.constructor = function( test ){ + test.expect( 3 ); + + // Test for function + helper.testFunction( test.equals, git.Blob, 'Blob' ); + + // Ensure we get an instance of Blob + test.ok( new git.Blob( testRepo ) instanceof git.Blob, 'Invocation returns an instance of Blob' ); + + test.done(); +}; + +// Blob::Lookup +exports.lookup = function( test ) { + var testOid = new git.Oid(), + testBlob = new git.Blob( testRepo ); + + test.expect( 3 ); + + // Test for function + helper.testFunction( test.equals, testBlob.lookup, 'Blob::Lookup' ); + + // Test repo argument existence + helper.testException( test.ok, function() { + testBlob.lookup(); + }, 'Throw an exception if no repo Object' ); + + // Test that both arguments result correctly + //helper.testException( test.ifError, function() { + // testOid.mkstr( "somestr" ); + //}, 'No exception is thrown with proper arguments' ); + + // Test invalid hex id string + //test.equals( -2, testOid.mkstr( '1392DLFJIOS' ), 'Invalid hex id String' ); + + // Test valid hex id string + //test.equals( 0, testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ), 'Valid hex id String' ); + + test.done(); +}; diff --git a/test/raw-commit.js b/test/raw-commit.js index cfe13d9bc..fbfe126ea 100644 --- a/test/raw-commit.js +++ b/test/raw-commit.js @@ -73,7 +73,6 @@ exports.lookup = function( test ) { }, 'No exception is thrown with proper arguments' ); testRepo.open( path.resolve( '../.git' ), function( err ) { - console.log( new git.Error().strError( err ) ); // Test invalid commit testOid.mkstr( '100644' ); testCommit.lookup( testRepo, testOid, function( err ) { diff --git a/test/raw-obj.js b/test/raw-obj.js new file mode 100644 index 000000000..5427334c6 --- /dev/null +++ b/test/raw-obj.js @@ -0,0 +1,38 @@ +var git = require( '../' ).raw, + rimraf = require( '../vendor/rimraf' ); + +// Helper functions +var helper = { + // Test if obj is a true function + testFunction: function( test, obj, label ) { + // The object reports itself as a function + test( typeof obj, 'function', label +' reports as a function.' ); + // This ensures the repo is actually a derivative of the Function [[Class]] + test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + }, + // Test code and handle exception thrown + testException: function( test, fun, label ) { + try { + fun(); + test( false, label ); + } + catch (ex) { + test( true, label ); + } + } +}; + +var repo = new git.Repo(); + +// Obj +exports.constructor = function( test ){ + test.expect( 3 ); + + // Test for function + helper.testFunction( test.equals, git.Object, 'GitObject' ); + + // Ensure we get an instance of Obj + test.ok( new git.Object() instanceof git.Object, 'Invocation returns an instance of GitObject' ); + + test.done(); +}; diff --git a/test/raw-oid.js b/test/raw-oid.js index 0c52ffa27..f5b6adfa2 100644 --- a/test/raw-oid.js +++ b/test/raw-oid.js @@ -62,3 +62,45 @@ exports.mkstr = function( test ) { test.done(); }; + +// Oid::Fmt +exports.fmt = function( test ) { + var testOid = new git.Oid(); + + test.expect( 4 ); + + // Test for function + helper.testFunction( test.equals, testOid.fmt, 'Oid::Fmt' ); + + // Test invalid hex id string + testOid.mkstr( 'NNNNN' ); + test.equals( '00000', testOid.fmt().substring(0, 5).toUpperCase(), 'Invalid hex id String' ); + + // Test valid hex id string + testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ); + + // Slight hackery to get this to work... should investigate oid fmt + test.equals( '1810DFF58D8A660512D4832E740F692884338CCD', testOid.fmt().substring(0, 40).toUpperCase(), 'Valid hex id String' ); + + test.done(); +}; + +// Oid::Fmt +exports.toString = function( test ) { + var testOid = new git.Oid(); + + test.expect( 4 ); + + // Test for function + helper.testFunction( test.equals, testOid.toString, 'Oid::ToString' ); + + // Test invalid hex id string + testOid.mkstr( 'NNNNN' ); + test.equals( '00000', testOid.toString( 5 ), 'Invalid hex id String' ); + + // Test valid hex id string + testOid.mkstr( '1810DFF58D8A660512D4832E740F692884338CCD' ); + test.equals( '1810DFF58D8A660512D4832E740F692884338CCD', testOid.toString( 40 ).toUpperCase(), 'Valid hex id String' ); + + test.done(); +}; diff --git a/test/raw-ref.js b/test/raw-ref.js new file mode 100644 index 000000000..14a7f203c --- /dev/null +++ b/test/raw-ref.js @@ -0,0 +1,82 @@ +var git = require( '../' ).raw, + rimraf = require( '../vendor/rimraf' ); + +// Helper functions +var helper = { + // Test if obj is a true function + testFunction: function( test, obj, label ) { + // The object reports itself as a function + test( typeof obj, 'function', label +' reports as a function.' ); + // This ensures the repo is actually a derivative of the Function [[Class]] + test( toString.call( obj ), '[object Function]', label +' [[Class]] is of type function.' ); + }, + // Test code and handle exception thrown + testException: function( test, fun, label ) { + try { + fun(); + test( false, label ); + } + catch (ex) { + test( true, label ); + } + } +}; + +// Ref +exports.constructor = function( test ){ + test.expect( 3 ); + + // Test for function + helper.testFunction( test.equals, git.Ref, 'Ref' ); + + // Ensure we get an instance of Ref + test.ok( new git.Ref() instanceof git.Ref, 'Invocation returns an instance of Ref' ); + + test.done(); +}; + +// Ref::Lookup +exports.lookup = function( test ) { + var testRepo = new git.Repo(), + master = new git.Ref(); + + test.expect( 5 ); + + // Test for function + helper.testFunction( test.equals, master.lookup, 'Ref::Lookup' ); + + // Test repo argument existence + helper.testException( test.ok, function() { + master.lookup(); + }, 'Throw an exception if no repo' ); + + // Test name argument existence + helper.testException( test.ok, function() { + master.lookup( testRepo ); + }, 'Throw an exception if no name' ); + + // Test callback argument existence + helper.testException( test.ok, function() { + master.lookup( testRepo, 'refs/heads/master' ); + }, 'Throw an exception if no callback' ); + + // Cleanup, remove test repo directory - if it exists + rimraf( './test.git', function() { + // // Create bare repo and test for creation + // testRepo.init( './test.git', true, function( err, path, is_bare ) { + // test.equals( 0, err, 'Successfully created bare repository' ); + // // Verify repo exists + // testRepo.open( './test.git', function(err, path) { + // test.equals( 0, err, 'Valid repository created' ); + // test.equals( true, is_bare, 'Returns valid is_bare value' ); + + // testRepo.free(); + + // // Cleanup, remove test repo directory + // rimraf( './test.git', function() { + test.done(); + // }); + // }); + // }); + }); +}; diff --git a/test/raw-repo.js b/test/raw-repo.js index 2bae615eb..5d50d16a1 100644 --- a/test/raw-repo.js +++ b/test/raw-repo.js @@ -127,49 +127,3 @@ exports.init = function( test ) { }); }); }; - -// Repo::LookupRef -exports.lookupRef = function( test ) { - var testRepo = new git.Repo(), - master = new git.Ref(testRepo); - - test.expect( 5 ); - - // Test for function - helper.testFunction( test.equals, testRepo.lookupRef, 'Repo::LookupRef' ); - - // Test ref argument existence - helper.testException( test.ok, function() { - testRepo.lookupRef(); - }, 'Throw an exception if no reference' ); - - // Test name argument existence - helper.testException( test.ok, function() { - testRepo.lookupRef( master ); - }, 'Throw an exception if no name' ); - - // Test callback argument existence - helper.testException( test.ok, function() { - testRepo.lookupRef( master, 'refs/heads/master' ); - }, 'Throw an exception if no callback' ); - - // Cleanup, remove test repo directory - if it exists - rimraf( './test.git', function() { - // // Create bare repo and test for creation - // testRepo.init( './test.git', true, function( err, path, is_bare ) { - // test.equals( 0, err, 'Successfully created bare repository' ); - // // Verify repo exists - // testRepo.open( './test.git', function(err, path) { - // test.equals( 0, err, 'Valid repository created' ); - // test.equals( true, is_bare, 'Returns valid is_bare value' ); - - // testRepo.free(); - - // // Cleanup, remove test repo directory - // rimraf( './test.git', function() { - test.done(); - // }); - // }); - // }); - }); -}; diff --git a/test/raw-revwalk.js b/test/raw-revwalk.js index 15cf96345..702d7e4ba 100644 --- a/test/raw-revwalk.js +++ b/test/raw-revwalk.js @@ -1,4 +1,4 @@ -var git = require( '../' ).git2, +var git = require( '../' ).raw, rimraf = require( '../vendor/rimraf' ) || require( 'rimraf' ); var testRepo = new git.Repo(); @@ -24,75 +24,17 @@ var helper = { } }; -// Oid +// RevWalk exports.constructor = function( test ){ test.expect( 3 ); // Test for function - helper.testFunction( test.equals, git.Commit, 'Commit' ); + helper.testFunction( test.equals, git.RevWalk, 'RevWalk' ); // Ensure we get an instance of Oid testRepo.open( './dummyrepo/.git', function( err, path ) { - test.ok( new git.Commit( testRepo ) instanceof git.Commit, 'Invocation returns an instance of Commit' ); + test.ok( new git.RevWalk( testRepo ) instanceof git.RevWalk, 'Invocation returns an instance of RevWalk' ); test.done(); }); }; - -// Oid::Mkstr -exports.lookup = function( test ) { - var testOid = new git.Oid(), - testCommit = new git.Commit(testRepo); - - testOid.mkstr( 'cb09e99e91d41705197e0fb60823fdc7df776691' ); - - test.expect( 8 ); - - // Test for function - helper.testFunction( test.equals, testCommit.lookup, 'Commit::Lookup' ); - - // Test repo argument existence - helper.testException( test.ok, function() { - testCommit.lookup(); - }, 'Throw an exception if no repo' ); - - // Test oid argument existence - helper.testException( test.ok, function() { - testCommit.lookup( testRepo ); - }, 'Throw an exception if no oid' ); - - // Test callback argument existence - helper.testException( test.ok, function() { - testCommit.lookup( testRepo, testOid ); - }, 'Throw an exception if no callback' ); - - // Test that both arguments result correctly - helper.testException( test.ifError, function() { - testCommit.lookup( testRepo, testOid, function() {} ); - }, 'No exception is thrown with proper arguments' ); - - testRepo.open( './dummyrepo/.git', function( err, path ) { - // Test invalid commit - testOid.mkstr( '100644' ); - testCommit.lookup( testRepo, testOid, function( err, details ) { - test.notEqual( 0, err, 'Not a valid commit' ); - - // Test valid commit - testOid.mkstr( 'cb09e99e91d41705197e0fb60823fdc7df776691' ); - testCommit.lookup( testRepo, testOid, function( err, details ) { - test.equals( 0, err, 'Valid commit'); - - //test.equals( 'object', typeof details, 'Details is an object' ); - - //test.equals( 'string', typeof details.message, 'Details message is a String' ); - //if(details.message) { - // test.equals( 'initial commit', details.message.trim(), 'Details has correct message' ); - //} - - testRepo.free(); - - test.done(); - }); - }); - }); -}; diff --git a/util/hint-check.js b/util/hint-check.js index 7bc5b7e26..1c531d212 100644 --- a/util/hint-check.js +++ b/util/hint-check.js @@ -1,11 +1,26 @@ var nodejshint = require( './nodejshint.js' ).test, -files = [ 'lib/index.js', 'lib/ref.js', 'lib/repo.js', 'lib/error.js', 'lib/revwalk.js', 'lib/commit.js', 'lib/util.js', 'lib/oid.js', 'lib/sig.js' ]; +files = [ + 'lib/blob.js', + 'lib/commit.js', + 'lib/error.js', + 'lib/index.js', + 'lib/obj.js', + 'lib/oid.js', + 'lib/ref.js', + 'lib/repo.js', + 'lib/revwalk.js', + 'lib/sig.js', + 'lib/tree.js', + 'lib/tree_entry.js', + 'lib/util.js' +]; nodejshint( files, function( failures ) { if( !files.length ) { process.exit( 0 ); - } else { + } + else { process.exit( 1 ); } }); diff --git a/vendor/libgit2/CMakeLists.txt b/vendor/libgit2/CMakeLists.txt old mode 100755 new mode 100644 index a7f96515c..ed015b61f --- a/vendor/libgit2/CMakeLists.txt +++ b/vendor/libgit2/CMakeLists.txt @@ -14,7 +14,7 @@ PROJECT(libgit2 C) CMAKE_MINIMUM_REQUIRED(VERSION 2.6) -FILE(STRINGS "src/git2.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") +FILE(STRINGS "include/git2.h" GIT2_HEADER REGEX "^#define LIBGIT2_VERSION \"[^\"]*\"$") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"([0-9]+).*$" "\\1" LIBGIT2_VERSION_MAJOR "${GIT2_HEADER}") STRING(REGEX REPLACE "^.*LIBGIT2_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" LIBGIT2_VERSION_MINOR "${GIT2_HEADER}") @@ -33,13 +33,24 @@ ELSEIF () SET(SHA1_TYPE "builtin" CACHE STRING "Which SHA1 implementation to use: builtin, ppc") ENDIF () -# Try to find SQLite3 to compile the SQLite backend -IF (NOT WIN32) - INCLUDE(FindPkgConfig) +INCLUDE(FindPkgConfig) + +# Show SQLite3 settings in GUI (if they won't be found out) +SET(SQLITE3_INCLUDE_DIRS "" CACHE PATH "SQLite include directory") +SET(SQLITE3_LIBRARIES "" CACHE FILEPATH "SQLite library") + +# Are SQLite3 variables already set up? (poor Windows/no pkg-config/no sqlite3.pc) +IF (SQLITE3_INCLUDE_DIRS AND SQLITE3_LIBRARIES) + SET(SQLITE3_FOUND 1) +ENDIF () + +# Try to find SQLite3 via pkg-config +IF (PKG_CONFIG_FOUND AND NOT SQLITE3_FOUND) pkg_check_modules(SQLITE3 sqlite3) ENDIF () -IF (SQLITE3_LIBRARIES AND SQLITE3_INCLUDE_DIRS) +# Compile SQLite backend if SQLite3 is available +IF (SQLITE3_FOUND) ADD_DEFINITIONS(-DGIT2_SQLITE_BACKEND) INCLUDE_DIRECTORIES(${SQLITE3_INCLUDE_DIRS}) ENDIF () @@ -62,7 +73,7 @@ ENDIF () FILE(GLOB SRC src/*.c src/backends/*.c) FILE(GLOB SRC_SHA1 src/block-sha1/*.c) FILE(GLOB SRC_PLAT src/unix/*.c) -FILE(GLOB SRC_H src/git/*.h) +FILE(GLOB SRC_H include/git2/*.h) # On Windows use specific platform sources IF (WIN32 AND NOT CYGWIN) @@ -96,8 +107,8 @@ INSTALL(TARGETS git2 LIBRARY DESTINATION ${INSTALL_LIB} ARCHIVE DESTINATION ${INSTALL_LIB} ) -INSTALL(DIRECTORY src/git2 DESTINATION ${INSTALL_INC} ) -INSTALL(FILES src/git2.h DESTINATION ${INSTALL_INC} ) +INSTALL(DIRECTORY include/git2 DESTINATION ${INSTALL_INC} ) +INSTALL(FILES include/git2.h DESTINATION ${INSTALL_INC} ) # Tests IF (BUILD_TESTS) diff --git a/vendor/libgit2/CONVENTIONS b/vendor/libgit2/CONVENTIONS old mode 100755 new mode 100644 diff --git a/vendor/libgit2/COPYING b/vendor/libgit2/COPYING old mode 100755 new mode 100644 diff --git a/vendor/libgit2/README.md b/vendor/libgit2/README.md old mode 100755 new mode 100644 index 444736dc5..1b3c68085 --- a/vendor/libgit2/README.md +++ b/vendor/libgit2/README.md @@ -78,6 +78,9 @@ 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. + You can run `./waf --help` to see a full list of install options and targets. diff --git a/vendor/libgit2/api.doxygen b/vendor/libgit2/api.doxygen old mode 100755 new mode 100644 diff --git a/vendor/libgit2/git.git-authors b/vendor/libgit2/git.git-authors old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/git2.h b/vendor/libgit2/include/git2.h old mode 100755 new mode 100644 similarity index 96% rename from vendor/libgit2/src/git2.h rename to vendor/libgit2/include/git2.h index 70ab811f1..b08c25ed1 --- a/vendor/libgit2/src/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.3.0" +#define LIBGIT2_VERSION "0.8.0" #define LIBGIT2_VER_MAJOR 0 -#define LIBGIT2_VER_MINOR 3 +#define LIBGIT2_VER_MINOR 8 #define LIBGIT2_VER_REVISION 0 #include "git2/common.h" diff --git a/vendor/libgit2/src/git2/blob.h b/vendor/libgit2/include/git2/blob.h old mode 100755 new mode 100644 similarity index 95% rename from vendor/libgit2/src/git2/blob.h rename to vendor/libgit2/include/git2/blob.h index b34b5bfe9..b527d61f4 --- a/vendor/libgit2/src/git2/blob.h +++ b/vendor/libgit2/include/git2/blob.h @@ -28,7 +28,7 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "repository.h" +#include "object.h" /** * @file git2/blob.h @@ -51,7 +51,7 @@ GIT_BEGIN_DECL */ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git_oid *id) { - return git_repository_lookup((git_object **)blob, repo, id, GIT_OBJ_BLOB); + return git_object_lookup((git_object **)blob, repo, id, GIT_OBJ_BLOB); } /** @@ -67,7 +67,7 @@ GIT_INLINE(int) git_blob_lookup(git_blob **blob, git_repository *repo, const git */ GIT_INLINE(int) git_blob_new(git_blob **blob, git_repository *repo) { - return git_repository_newobject((git_object **)blob, repo, GIT_OBJ_BLOB); + return git_object_new((git_object **)blob, repo, GIT_OBJ_BLOB); } /** diff --git a/vendor/libgit2/src/git2/commit.h b/vendor/libgit2/include/git2/commit.h old mode 100755 new mode 100644 similarity index 96% rename from vendor/libgit2/src/git2/commit.h rename to vendor/libgit2/include/git2/commit.h index 4d0b2ab99..21836dbbd --- a/vendor/libgit2/src/git2/commit.h +++ b/vendor/libgit2/include/git2/commit.h @@ -28,7 +28,7 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "repository.h" +#include "object.h" /** * @file git2/commit.h @@ -52,7 +52,7 @@ GIT_BEGIN_DECL */ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, const git_oid *id) { - return git_repository_lookup((git_object **)commit, repo, id, GIT_OBJ_COMMIT); + return git_object_lookup((git_object **)commit, repo, id, GIT_OBJ_COMMIT); } /** @@ -68,7 +68,7 @@ GIT_INLINE(int) git_commit_lookup(git_commit **commit, git_repository *repo, con */ GIT_INLINE(int) git_commit_new(git_commit **commit, git_repository *repo) { - return git_repository_newobject((git_object **)commit, repo, GIT_OBJ_COMMIT); + return git_object_new((git_object **)commit, repo, GIT_OBJ_COMMIT); } /** diff --git a/vendor/libgit2/src/git2/common.h b/vendor/libgit2/include/git2/common.h old mode 100755 new mode 100644 similarity index 98% rename from vendor/libgit2/src/git2/common.h rename to vendor/libgit2/include/git2/common.h index 3500a2b14..34efe808b --- a/vendor/libgit2/src/git2/common.h +++ b/vendor/libgit2/include/git2/common.h @@ -154,6 +154,9 @@ /** 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) + GIT_BEGIN_DECL /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/src/git2/errors.h b/vendor/libgit2/include/git2/errors.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/errors.h rename to vendor/libgit2/include/git2/errors.h diff --git a/vendor/libgit2/src/git2/index.h b/vendor/libgit2/include/git2/index.h old mode 100755 new mode 100644 similarity index 99% rename from vendor/libgit2/src/git2/index.h rename to vendor/libgit2/include/git2/index.h index f1716fead..605740c10 --- a/vendor/libgit2/src/git2/index.h +++ b/vendor/libgit2/include/git2/index.h @@ -27,6 +27,7 @@ #include "common.h" #include "types.h" +#include "oid.h" /** * @file git2/index.h diff --git a/vendor/libgit2/src/git2/object.h b/vendor/libgit2/include/git2/object.h old mode 100755 new mode 100644 similarity index 60% rename from vendor/libgit2/src/git2/object.h rename to vendor/libgit2/include/git2/object.h index 084d11177..af0f014e3 --- a/vendor/libgit2/src/git2/object.h +++ b/vendor/libgit2/include/git2/object.h @@ -38,6 +38,49 @@ */ GIT_BEGIN_DECL +/** + * Lookup a reference to one of the objects in a repostory. + * + * The generated reference is owned by the repository and + * should not be freed by the user. + * + * The 'type' parameter must match the type of the object + * in the odb; the method will fail otherwise. + * The special value 'GIT_OBJ_ANY' may be passed to let + * the method guess the object's type. + * + * @param object pointer to the looked-up object + * @param repo the repository to look up the object + * @param id the unique identifier for the object + * @param type the type of the object + * @return a reference to the object + */ +GIT_EXTERN(int) git_object_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type); + +/** + * Create a new in-memory repository object with + * the given type. + * + * The object's attributes can be filled in using the + * corresponding setter methods. + * + * The object will be written back to given git_repository + * when the git_object_write() function is called; objects + * cannot be written to disk until all their main + * attributes have been properly filled. + * + * Objects are instantiated with no SHA1 id; their id + * will be automatically generated when writing to the + * repository. + * + * @param object pointer to the new object + * @parem repo Repository where the object belongs + * @param type Type of the object to be created + * @return the new object + */ +GIT_EXTERN(int) git_object_new(git_object **object, git_repository *repo, git_otype type); + + /** * Write back an object to disk. * @@ -66,7 +109,7 @@ GIT_EXTERN(int) git_object_write(git_object *object); * @param obj the repository object * @return the SHA1 id */ -GIT_EXTERN(const git_oid *) git_object_id(git_object *obj); +GIT_EXTERN(const git_oid *) git_object_id(const git_object *obj); /** * Get the object type of an object @@ -74,7 +117,7 @@ GIT_EXTERN(const git_oid *) git_object_id(git_object *obj); * @param obj the repository object * @return the object's type */ -GIT_EXTERN(git_otype) git_object_type(git_object *obj); +GIT_EXTERN(git_otype) git_object_type(const git_object *obj); /** * Get the repository that owns this object @@ -82,21 +125,30 @@ GIT_EXTERN(git_otype) git_object_type(git_object *obj); * @param obj the object * @return the repository who owns this object */ -GIT_EXTERN(git_repository *) git_object_owner(git_object *obj); +GIT_EXTERN(git_repository *) git_object_owner(const git_object *obj); /** - * Free a reference to one of the objects in the repository. + * Close an open object + * + * This method instructs the library to close an existing + * object; note that git_objects are owned by the repository + * and are reference counted, so the object may or may not be + * freed after this library call, depending on whether any other + * objects still depend on it. * - * Repository objects are managed automatically by the library, - * but this method can be used to force freeing one of the - * objects. + * IMPORTANT: + * It is *not* necessary to call this method when you stop using + * an object, since all object memory is automatically reclaimed + * by the repository when it is freed. * - * Careful: freeing objects in the middle of a repository - * traversal will most likely cause errors. + * Forgetting to call `git_object_close` does not cause memory + * leaks, but it's is recommended to close as soon as possible + * the biggest objects (e.g. blobs) to prevent wasting memory + * space. * - * @param object the object to free + * @param object the object to close */ -GIT_EXTERN(void) git_object_free(git_object *object); +GIT_EXTERN(void) git_object_close(git_object *object); /** * Convert an object type to it's string representation. diff --git a/vendor/libgit2/src/git2/odb.h b/vendor/libgit2/include/git2/odb.h old mode 100755 new mode 100644 similarity index 91% rename from vendor/libgit2/src/git2/odb.h rename to vendor/libgit2/include/git2/odb.h index 2f2741135..0d285897c --- a/vendor/libgit2/src/git2/odb.h +++ b/vendor/libgit2/include/git2/odb.h @@ -79,7 +79,24 @@ GIT_EXTERN(int) git_odb_open(git_odb **out, const char *objects_dir); * @paramm backend pointer to a git_odb_backend instance * @return 0 on sucess; error code otherwise */ -GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend); +GIT_EXTERN(int) git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority); + +/** + * Add a custom backend to an existing Object DB; this + * backend will work as an alternate. + * + * Alternate backends are always checked for objects *after* + * all the main backends have been exhausted. + * + * Writing is disabled on alternate backends. + * + * Read for more information. + * + * @param odb database to add the backend to + * @paramm backend pointer to a git_odb_backend instance + * @return 0 on sucess; error code otherwise + */ +GIT_EXTERN(int) git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority); /** * Close an open object database. diff --git a/vendor/libgit2/src/git2/odb_backend.h b/vendor/libgit2/include/git2/odb_backend.h old mode 100755 new mode 100644 similarity index 99% rename from vendor/libgit2/src/git2/odb_backend.h rename to vendor/libgit2/include/git2/odb_backend.h index ee7e5dfde..0e817eb37 --- a/vendor/libgit2/src/git2/odb_backend.h +++ b/vendor/libgit2/include/git2/odb_backend.h @@ -28,6 +28,7 @@ #include "common.h" #include "types.h" #include "oid.h" +#include "odb.h" /** * @file git2/backend.h @@ -42,8 +43,6 @@ GIT_BEGIN_DECL struct git_odb_backend { git_odb *odb; - int priority; - int (* read)( git_rawobj *, struct git_odb_backend *, diff --git a/vendor/libgit2/src/git2/oid.h b/vendor/libgit2/include/git2/oid.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/oid.h rename to vendor/libgit2/include/git2/oid.h diff --git a/vendor/libgit2/src/git2/refs.h b/vendor/libgit2/include/git2/refs.h old mode 100755 new mode 100644 similarity index 50% rename from vendor/libgit2/src/git2/refs.h rename to vendor/libgit2/include/git2/refs.h index c9efac34f..1702d7ee1 --- a/vendor/libgit2/src/git2/refs.h +++ b/vendor/libgit2/include/git2/refs.h @@ -27,6 +27,7 @@ #include "common.h" #include "types.h" +#include "oid.h" /** * @file git2/refs.h @@ -38,18 +39,51 @@ GIT_BEGIN_DECL /** - * Create a new reference. + * Lookup a reference by its name in a repository. * - * The reference will be empty and exclusively - * in-memory until it is filled with the setter - * methods and written back to disk using - * `git_reference_write`. + * The generated reference is owned by the repository and + * should not be freed by the user. + * + * @param reference_out pointer to the looked-up reference + * @param repo the repository to look up the reference + * @param name the long name for the reference (e.g. HEAD, ref/heads/master, refs/tags/v0.1.0, ...) + * @return 0 on success; error code otherwise + */ +GIT_EXTERN(int) git_reference_lookup(git_reference **reference_out, git_repository *repo, const char *name); + +/** + * Create a new symbolic reference. + * + * 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(git_reference **ref_out, git_repository *repo, const char *name, const char *target); + +/** + * Create a new object id reference. + * + * 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 exists + * @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_new(git_reference **ref_out, git_repository *repo); +GIT_EXTERN(int) git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id); /** * Get the OID pointed to by a reference. @@ -105,70 +139,84 @@ GIT_EXTERN(const char *) git_reference_name(git_reference *ref); GIT_EXTERN(int) git_reference_resolve(git_reference **resolved_ref, git_reference *ref); /** - * Write a reference back to disk. + * Get the repository where a reference resides * - * The reference must have a valid name and a valid target - * (either direct or symbolic). + * @param ref The reference + * @return a pointer to the repo + */ +GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref); + +/** + * Set the symbolic target of a reference. * - * If the reference has been loaded from disk and no changes - * have been made, no action will take place. + * The reference must be a symbolic reference, otherwise + * this method will fail. * - * The writing to disk is atomic. + * The reference will be automatically updated in + * memory and on disk. * * @param ref The reference + * @param target The new target for the reference * @return 0 on success; error code otherwise */ -GIT_EXTERN(int) git_reference_write(git_reference *ref); +GIT_EXTERN(int) git_reference_set_target(git_reference *ref, const char *target); /** - * Get the repository where a reference resides + * Set the OID target of a reference. + * + * The reference must be a direct reference, otherwise + * this method will fail. + * + * The reference will be automatically updated in + * memory and on disk. * * @param ref The reference - * @return a pointer to the repo + * @param target The new target OID for the reference + * @return 0 on success; error code otherwise */ -GIT_EXTERN(git_repository *) git_reference_owner(git_reference *ref); +GIT_EXTERN(int) git_reference_set_oid(git_reference *ref, const git_oid *id); /** - * Set the name of a reference. + * Rename an existing reference * - * This marks the reference as modified; changes - * won't take effect until it is manually written back - * to disk. + * 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. * - * @param ref The reference - * @param name The new name for the reference */ -GIT_EXTERN(void) git_reference_set_name(git_reference *ref, const char *name); +GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name); /** - * Set the target reference of a reference. + * Delete an existing reference * - * This converts the reference into a symbolic - * reference. + * This method works for both direct and symbolic references. * - * This marks the reference as modified; changes - * won't take effect until it is manually written back - * to disk. + * The reference will be immediately removed on disk and from + * memory. The given reference pointer will no longer be valid. * - * @param ref The reference - * @param target The new target for the reference */ -GIT_EXTERN(void) git_reference_set_target(git_reference *ref, const char *target); +GIT_EXTERN(int) git_reference_delete(git_reference *ref); /** - * Set the OID target of a reference. + * Pack all the loose references in the repository * - * This converts the reference into a direct - * reference. + * This method will load into the cache all the loose + * references on the repository and update the + * `packed-refs` file with them. * - * This marks the reference as modified; changes - * won't take effect until it is manually written back - * to disk. + * Once the `packed-refs` file has been written properly, + * the loose references will be removed from disk. * - * @param ref The reference - * @param target The new target OID for the reference + * WARNING: calling this method may invalidate any existing + * references previously loaded on the cache. + * + * @param repo Repository where the loose refs will be packed + * @return 0 on success; error code otherwise */ -GIT_EXTERN(void) git_reference_set_oid(git_reference *ref, const git_oid *id); +GIT_EXTERN(int) git_reference_packall(git_repository *repo); /** @} */ GIT_END_DECL diff --git a/vendor/libgit2/src/git2/repository.h b/vendor/libgit2/include/git2/repository.h old mode 100755 new mode 100644 similarity index 74% rename from vendor/libgit2/src/git2/repository.h rename to vendor/libgit2/include/git2/repository.h index ec74305ae..5327f8c58 --- a/vendor/libgit2/src/git2/repository.h +++ b/vendor/libgit2/include/git2/repository.h @@ -132,26 +132,6 @@ GIT_EXTERN(int) git_repository_open3(git_repository **repository, const char *git_index_file, const char *git_work_tree); - -/** - * Lookup a reference to one of the objects in the repostory. - * - * The generated reference is owned by the repository and - * should not be freed by the user. - * - * The 'type' parameter must match the type of the object - * in the odb; the method will fail otherwise. - * The special value 'GIT_OBJ_ANY' may be passed to let - * the method guess the object's type. - * - * @param object pointer to the looked-up object - * @param repo the repository to look up the object - * @param id the unique identifier for the object - * @param type the type of the object - * @return a reference to the object - */ -GIT_EXTERN(int) git_repository_lookup(git_object **object, git_repository *repo, const git_oid *id, git_otype type); - /** * Get the object database behind a Git repository * @@ -172,35 +152,15 @@ GIT_EXTERN(git_odb *) git_repository_database(git_repository *repo); */ GIT_EXTERN(int) git_repository_index(git_index **index, git_repository *repo); -/** - * Create a new in-memory repository object with - * the given type. - * - * The object's attributes can be filled in using the - * corresponding setter methods. - * - * The object will be written back to given git_repository - * when the git_object_write() function is called; objects - * cannot be written to disk until all their main - * attributes have been properly filled. - * - * Objects are instantiated with no SHA1 id; their id - * will be automatically generated when writing to the - * repository. - * - * @param object pointer to the new object - * @parem repo Repository where the object belongs - * @param type Type of the object to be created - * @return the new object - */ -GIT_EXTERN(int) git_repository_newobject(git_object **object, git_repository *repo, git_otype type); - /** * Free a previously allocated repository * @param repo repository handle to close. If NULL nothing occurs. */ GIT_EXTERN(void) git_repository_free(git_repository *repo); + +GIT_EXTERN(void) git_repository_free__no_gc(git_repository *repo); + /** * Creates a new Git repository in the given folder. * @@ -218,22 +178,6 @@ 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); -/** - * Lookup a reference by its name in the repository. - * - * The generated reference is owned by the repository and - * should not be freed by the user. - * - * TODO: - * - Ensure the reference name is valid - * - * @param reference_out pointer to the looked-up reference - * @param repo the repository to look up the reference - * @param name the long name for the reference (e.g. HEAD, ref/heads/master, refs/tags/v0.1.0, ...) - * @return a reference to the reference - */ -GIT_EXTERN(int) git_repository_lookup_ref(git_reference **reference_out, git_repository *repo, const char *name); - /** @} */ GIT_END_DECL #endif diff --git a/vendor/libgit2/src/git2/revwalk.h b/vendor/libgit2/include/git2/revwalk.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/revwalk.h rename to vendor/libgit2/include/git2/revwalk.h diff --git a/vendor/libgit2/src/git2/signature.h b/vendor/libgit2/include/git2/signature.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/signature.h rename to vendor/libgit2/include/git2/signature.h diff --git a/vendor/libgit2/src/git2/tag.h b/vendor/libgit2/include/git2/tag.h old mode 100755 new mode 100644 similarity index 96% rename from vendor/libgit2/src/git2/tag.h rename to vendor/libgit2/include/git2/tag.h index e97c2badd..2ca25c8a0 --- a/vendor/libgit2/src/git2/tag.h +++ b/vendor/libgit2/include/git2/tag.h @@ -28,7 +28,7 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "repository.h" +#include "object.h" /** * @file git2/tag.h @@ -51,7 +51,7 @@ GIT_BEGIN_DECL */ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oid *id) { - return git_repository_lookup((git_object **)tag, repo, id, GIT_OBJ_TAG); + return git_object_lookup((git_object **)tag, repo, id, (git_otype)GIT_OBJ_TAG); } /** @@ -67,7 +67,7 @@ GIT_INLINE(int) git_tag_lookup(git_tag **tag, git_repository *repo, const git_oi */ GIT_INLINE(int) git_tag_new(git_tag **tag, git_repository *repo) { - return git_repository_newobject((git_object **)tag, repo, GIT_OBJ_TAG); + return git_object_new((git_object **)tag, repo, (git_otype)GIT_OBJ_TAG); } /** diff --git a/vendor/libgit2/src/git2/thread-utils.h b/vendor/libgit2/include/git2/thread-utils.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/thread-utils.h rename to vendor/libgit2/include/git2/thread-utils.h diff --git a/vendor/libgit2/src/git2/tree.h b/vendor/libgit2/include/git2/tree.h old mode 100755 new mode 100644 similarity index 83% rename from vendor/libgit2/src/git2/tree.h rename to vendor/libgit2/include/git2/tree.h index 6f79ac455..70040f058 --- a/vendor/libgit2/src/git2/tree.h +++ b/vendor/libgit2/include/git2/tree.h @@ -28,7 +28,7 @@ #include "common.h" #include "types.h" #include "oid.h" -#include "repository.h" +#include "object.h" /** * @file git2/tree.h @@ -51,7 +51,7 @@ GIT_BEGIN_DECL */ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git_oid *id) { - return git_repository_lookup((git_object **)tree, repo, id, GIT_OBJ_TREE); + return git_object_lookup((git_object **)tree, repo, id, GIT_OBJ_TREE); } /** @@ -67,7 +67,7 @@ GIT_INLINE(int) git_tree_lookup(git_tree **tree, git_repository *repo, const git */ GIT_INLINE(int) git_tree_new(git_tree **tree, git_repository *repo) { - return git_repository_newobject((git_object **)tree, repo, GIT_OBJ_TREE); + return git_object_new((git_object **)tree, repo, GIT_OBJ_TREE); } /** @@ -148,36 +148,6 @@ GIT_EXTERN(int) git_tree_entry_2object(git_object **object, git_tree_entry *entr */ GIT_EXTERN(int) git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes); -/** - * Add a new entry to a tree, returning that new entry. - * The only difference with this call is that it does not sort - * tree afterwards, this requirement is left to the caller. - * - * This will mark the tree as modified; the new entry will - * be written back to disk on the next git_object_write() - * - * @param entry Entry object which will be created - * @param tree Tree object to store the entry - * @iparam id OID for the tree entry - * @param filename Filename for the tree entry - * @param attributes UNIX file attributes for the entry - * @return 0 on success; otherwise error code - */ -GIT_EXTERN(int) git_tree_add_entry_unsorted(git_tree_entry **entry, git_tree *tree, const git_oid *id, const char *filename, int attributes); - -/** - * Sort the entries in a tree created using git_tree_add_entry2. - * - * This does not mark the tree as modified. It is intended to be used - * after several invocations of git_tree_add_entry2. - * git_tree_add_entry, on the other hand, sorts after each entry is - * added. - * - * @param tree Tree object whose entries are to be sorted - * @return 0 on success; otherwise error code - */ -GIT_EXTERN(int) git_tree_sort_entries(git_tree *tree); - /** * Remove an entry by its index. * diff --git a/vendor/libgit2/src/git2/types.h b/vendor/libgit2/include/git2/types.h old mode 100755 new mode 100644 similarity index 98% rename from vendor/libgit2/src/git2/types.h rename to vendor/libgit2/include/git2/types.h index 4f66742f0..62467ec45 --- a/vendor/libgit2/src/git2/types.h +++ b/vendor/libgit2/include/git2/types.h @@ -140,9 +140,11 @@ typedef struct git_reference git_reference; /** Basic type of any Git reference. */ typedef enum { - GIT_REF_INVALID = -1, /** Invalid reference */ + GIT_REF_INVALID = 0, /** Invalid reference */ GIT_REF_OID = 1, /** A reference which points at an object id */ GIT_REF_SYMBOLIC = 2, /** A reference which points at another reference */ + GIT_REF_PACKED = 4, + GIT_REF_HAS_PEEL = 8, } git_rtype; /** @} */ diff --git a/vendor/libgit2/src/git2/zlib.h b/vendor/libgit2/include/git2/zlib.h old mode 100755 new mode 100644 similarity index 100% rename from vendor/libgit2/src/git2/zlib.h rename to vendor/libgit2/include/git2/zlib.h diff --git a/vendor/libgit2/libgit2.pc.in b/vendor/libgit2/libgit2.pc.in old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/backends/sqlite.c b/vendor/libgit2/src/backends/sqlite.c old mode 100755 new mode 100644 index ad5b679f9..b4c941a59 --- a/vendor/libgit2/src/backends/sqlite.c +++ b/vendor/libgit2/src/backends/sqlite.c @@ -264,8 +264,6 @@ int git_odb_backend_sqlite(git_odb_backend **backend_out, const char *sqlite_db) backend->parent.exists = &sqlite_backend__exists; backend->parent.free = &sqlite_backend__free; - backend->parent.priority = 0; - *backend_out = (git_odb_backend *)backend; return GIT_SUCCESS; diff --git a/vendor/libgit2/src/blob.c b/vendor/libgit2/src/blob.c old mode 100755 new mode 100644 index c5a7143f0..f271cc7f6 --- a/vendor/libgit2/src/blob.c +++ b/vendor/libgit2/src/blob.c @@ -129,6 +129,10 @@ int git_blob_writefile(git_oid *written_id, git_repository *repo, const char *pa return error; git_oid_cpy(written_id, git_object_id((git_object *)blob)); + + /* FIXME: maybe we don't want to free this already? + * the user may want to access it again */ + git_object_close((git_object *)blob); return GIT_SUCCESS; } diff --git a/vendor/libgit2/src/blob.h b/vendor/libgit2/src/blob.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/block-sha1/sha1.c b/vendor/libgit2/src/block-sha1/sha1.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/block-sha1/sha1.h b/vendor/libgit2/src/block-sha1/sha1.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/bswap.h b/vendor/libgit2/src/bswap.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/cc-compat.h b/vendor/libgit2/src/cc-compat.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/commit.c b/vendor/libgit2/src/commit.c old mode 100755 new mode 100644 index 49e23545e..dff3f1e34 --- a/vendor/libgit2/src/commit.c +++ b/vendor/libgit2/src/commit.c @@ -44,6 +44,13 @@ static void clear_parents(git_commit *commit) { + unsigned int i; + + for (i = 0; i < commit->parents.length; ++i) { + git_commit *parent = git_vector_get(&commit->parents, i); + git_object_close((git_object *)parent); + } + git_vector_clear(&commit->parents); } @@ -55,6 +62,8 @@ void git_commit__free(git_commit *commit) git_signature_free(commit->author); git_signature_free(commit->committer); + git_object_close((git_object *)commit->tree); + free(commit->message); free(commit->message_short); free(commit); @@ -112,7 +121,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int /* first parse; the vector hasn't been initialized yet */ if (commit->parents.contents == NULL) { - git_vector_init(&commit->parents, 4, NULL, NULL); + git_vector_init(&commit->parents, 4, NULL); } clear_parents(commit); @@ -121,7 +130,8 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int if ((error = git__parse_oid(&oid, &buffer, buffer_end, "tree ")) < GIT_SUCCESS) return error; - if ((error = git_repository_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) + git_object_close((git_object *)commit->tree); + if ((error = git_object_lookup((git_object **)&commit->tree, commit->object.repo, &oid, GIT_OBJ_TREE)) < GIT_SUCCESS) return error; /* @@ -131,7 +141,7 @@ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int while (git__parse_oid(&oid, &buffer, buffer_end, "parent ") == GIT_SUCCESS) { git_commit *parent; - if ((error = git_repository_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) + if ((error = git_object_lookup((git_object **)&parent, commit->object.repo, &oid, GIT_OBJ_COMMIT)) < GIT_SUCCESS) return error; if (git_vector_insert(&commit->parents, parent) < GIT_SUCCESS) @@ -232,7 +242,17 @@ int git_commit__parse_full(git_commit *commit) if (!commit->object.in_memory && !commit->full_parse)\ git_commit__parse_full(commit); -GIT_COMMIT_GETTER(git_tree *, tree) +const git_tree *git_commit_tree(git_commit *commit) +{ + assert(commit); + + if (!commit->object.in_memory && commit->tree == NULL) + git_commit__parse_full(commit); + + GIT_OBJECT_INCREF(commit->tree); + return commit->tree; +} + GIT_COMMIT_GETTER(git_signature *, author) GIT_COMMIT_GETTER(git_signature *, committer) GIT_COMMIT_GETTER(char *, message) @@ -256,10 +276,15 @@ unsigned int git_commit_parentcount(git_commit *commit) return commit->parents.length; } -git_commit * git_commit_parent(git_commit *commit, unsigned int n) +git_commit *git_commit_parent(git_commit *commit, unsigned int n) { + git_commit *parent; + assert(commit); - return git_vector_get(&commit->parents, n); + + parent = git_vector_get(&commit->parents, n); + GIT_OBJECT_INCREF(parent); + return parent; } void git_commit_set_tree(git_commit *commit, git_tree *tree) @@ -267,6 +292,9 @@ void git_commit_set_tree(git_commit *commit, git_tree *tree) assert(commit && tree); commit->object.modified = 1; CHECK_FULL_PARSE(); + + git_object_close((git_object *)commit->tree); + GIT_OBJECT_INCREF(tree); commit->tree = tree; } @@ -321,7 +349,10 @@ void git_commit_set_message(git_commit *commit, const char *message) int git_commit_add_parent(git_commit *commit, git_commit *new_parent) { + assert(commit && new_parent); + CHECK_FULL_PARSE(); commit->object.modified = 1; + GIT_OBJECT_INCREF(new_parent); return git_vector_insert(&commit->parents, new_parent); } diff --git a/vendor/libgit2/src/commit.h b/vendor/libgit2/src/commit.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/common.h b/vendor/libgit2/src/common.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/delta-apply.c b/vendor/libgit2/src/delta-apply.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/delta-apply.h b/vendor/libgit2/src/delta-apply.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/dir.h b/vendor/libgit2/src/dir.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/errors.c b/vendor/libgit2/src/errors.c old mode 100755 new mode 100644 index 3616fdb93..880163f78 --- a/vendor/libgit2/src/errors.c +++ b/vendor/libgit2/src/errors.c @@ -26,7 +26,8 @@ static struct { {GIT_ETOONESTEDSYMREF, "The specified symbolic reference is too deeply nested"}, {GIT_EPACKEDREFSCORRUPTED, "The pack-refs file is either corrupted of its format is not currently supported"}, {GIT_EINVALIDPATH, "The path is invalid" }, - {GIT_EREVWALKOVER, "The revision walker is empty; there are no more commits left to iterate"} + {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"} }; const char *git_strerror(int num) diff --git a/vendor/libgit2/src/filebuf.c b/vendor/libgit2/src/filebuf.c new file mode 100644 index 000000000..73f0a70f4 --- /dev/null +++ b/vendor/libgit2/src/filebuf.c @@ -0,0 +1,286 @@ +/* + * 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 + +#include "common.h" +#include "filebuf.h" +#include "fileops.h" + +static const size_t WRITE_BUFFER_SIZE = (4096 * 2); + +static int lock_file(git_filebuf *file, int flags) +{ + if (gitfo_exists(file->path_lock) == 0) { + if (flags & GIT_FILEBUF_FORCE) + gitfo_unlink(file->path_lock); + else + return GIT_EOSERR; + } + + file->fd = gitfo_creat(file->path_lock, 0644); + + if (file->fd < 0) + return GIT_EOSERR; + + /* TODO: do a flock() in the descriptor file_lock */ + + if ((flags & GIT_FILEBUF_APPEND) && gitfo_exists(file->path_original) == 0) { + git_file source; + char buffer[2048]; + size_t read_bytes; + + source = gitfo_open(file->path_original, O_RDONLY); + if (source < 0) + return GIT_EOSERR; + + while ((read_bytes = gitfo_read(source, buffer, 2048)) > 0) { + gitfo_write(file->fd, buffer, read_bytes); + if (file->digest) + git_hash_update(file->digest, buffer, read_bytes); + } + + gitfo_close(source); + } + + return GIT_SUCCESS; +} + +void git_filebuf_cleanup(git_filebuf *file) +{ + if (file->fd >= 0) + gitfo_close(file->fd); + + if (gitfo_exists(file->path_lock) == GIT_SUCCESS) + gitfo_unlink(file->path_lock); + + if (file->digest) + git_hash_free_ctx(file->digest); + + free(file->buffer); + +#ifdef GIT_FILEBUF_THREADS + free(file->buffer_back); +#endif + + free(file->path_original); + free(file->path_lock); +} + +static int flush_buffer(git_filebuf *file) +{ + int result = GIT_SUCCESS; + + if (file->buf_pos > 0) { + result = gitfo_write(file->fd, file->buffer, file->buf_pos); + if (file->digest) + git_hash_update(file->digest, file->buffer, file->buf_pos); + + file->buf_pos = 0; + } + + return result; +} + +int git_filebuf_open(git_filebuf *file, const char *path, int flags) +{ + int error; + size_t path_len; + + if (file == NULL || path == NULL) + return GIT_ERROR; + + memset(file, 0x0, sizeof(git_filebuf)); + + file->buf_size = WRITE_BUFFER_SIZE; + file->buf_pos = 0; + file->fd = -1; + + path_len = strlen(path); + + file->path_original = git__strdup(path); + if (file->path_original == NULL) { + error = GIT_ENOMEM; + goto cleanup; + } + + file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH); + if (file->path_lock == NULL) { + error = GIT_ENOMEM; + goto cleanup; + } + + memcpy(file->path_lock, file->path_original, path_len); + memcpy(file->path_lock + path_len, GIT_FILELOCK_EXTENSION, GIT_FILELOCK_EXTLENGTH); + + file->buffer = git__malloc(file->buf_size); + if (file->buffer == NULL){ + error = GIT_ENOMEM; + goto cleanup; + } + +#ifdef GIT_FILEBUF_THREADS + file->buffer_back = git__malloc(file->buf_size); + if (file->buffer_back == NULL){ + error = GIT_ENOMEM; + goto cleanup; + } +#endif + + if (flags & GIT_FILEBUF_HASH_CONTENTS) { + if ((file->digest = git_hash_new_ctx()) == NULL) { + error = GIT_ENOMEM; + goto cleanup; + } + } + + if ((error = lock_file(file, flags)) < GIT_SUCCESS) + goto cleanup; + + return GIT_SUCCESS; + +cleanup: + git_filebuf_cleanup(file); + return error; +} + +int git_filebuf_hash(git_oid *oid, git_filebuf *file) +{ + int error; + + if (file->digest == NULL) + return GIT_ERROR; + + if ((error = flush_buffer(file)) < GIT_SUCCESS) + return error; + + git_hash_final(oid, file->digest); + git_hash_free_ctx(file->digest); + file->digest = NULL; + + return GIT_SUCCESS; +} + +int git_filebuf_commit(git_filebuf *file) +{ + int error; + + if ((error = flush_buffer(file)) < GIT_SUCCESS) + goto cleanup; + + gitfo_close(file->fd); + file->fd = -1; + + error = gitfo_mv(file->path_lock, file->path_original); + +cleanup: + git_filebuf_cleanup(file); + return error; +} + +GIT_INLINE(void) add_to_cache(git_filebuf *file, void *buf, size_t len) +{ + memcpy(file->buffer + file->buf_pos, buf, len); + file->buf_pos += len; +} + +int git_filebuf_write(git_filebuf *file, void *buff, size_t len) +{ + int error; + unsigned char *buf = buff; + + for (;;) { + size_t space_left = file->buf_size - file->buf_pos; + + /* cache if it's small */ + if (space_left > len) { + add_to_cache(file, buf, len); + return GIT_SUCCESS; + } + + /* flush the cache if it doesn't fit */ + if (file->buf_pos > 0) { + add_to_cache(file, buf, space_left); + + if ((error = flush_buffer(file)) < GIT_SUCCESS) + return error; + + len -= space_left; + buf += space_left; + } + + /* write too-large chunks immediately */ + if (len > file->buf_size) { + error = gitfo_write(file->fd, buf, len); + if (file->digest) + git_hash_update(file->digest, buf, len); + } + } +} + +int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len) +{ + int error; + size_t space_left = file->buf_size - file->buf_pos; + + *buffer = NULL; + + if (len > file->buf_size) + return GIT_ENOMEM; + + if (space_left <= len) { + if ((error = flush_buffer(file)) < GIT_SUCCESS) + return error; + } + + *buffer = (file->buffer + file->buf_pos); + file->buf_pos += len; + + return GIT_SUCCESS; +} + +int git_filebuf_printf(git_filebuf *file, const char *format, ...) +{ + va_list arglist; + size_t space_left = file->buf_size - file->buf_pos; + int len, error; + + va_start(arglist, format); + + len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); + + if (len < 0 || (size_t)len >= space_left) { + if ((error = flush_buffer(file)) < GIT_SUCCESS) + return error; + + len = vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); + if (len < 0 || (size_t)len > file->buf_size) + return GIT_ENOMEM; + } + + file->buf_pos += len; + return GIT_SUCCESS; + +} + diff --git a/vendor/libgit2/src/filebuf.h b/vendor/libgit2/src/filebuf.h new file mode 100644 index 000000000..9db615fbd --- /dev/null +++ b/vendor/libgit2/src/filebuf.h @@ -0,0 +1,44 @@ +#ifndef INCLUDE_filebuf_h__ +#define INCLUDE_filebuf_h__ + +#include "fileops.h" +#include "hash.h" + +#ifdef GIT_THREADS +# define GIT_FILEBUF_THREADS +#endif + +#define GIT_FILEBUF_HASH_CONTENTS 0x1 +#define GIT_FILEBUF_APPEND 0x2 +#define GIT_FILEBUF_FORCE 0x4 + +#define GIT_FILELOCK_EXTENSION ".lock\0" +#define GIT_FILELOCK_EXTLENGTH 6 + +struct git_filebuf { + char *path_original; + char *path_lock; + + git_hash_ctx *digest; + + unsigned char *buffer; +#ifdef GIT_FILEBUF_THREADS + unsigned char *buffer_back; +#endif + + size_t buf_size, buf_pos; + git_file fd; +}; + +typedef struct git_filebuf git_filebuf; + +int git_filebuf_write(git_filebuf *lock, void *buff, size_t len); +int git_filebuf_reserve(git_filebuf *file, void **buff, size_t len); +int git_filebuf_printf(git_filebuf *file, const char *format, ...); + +int git_filebuf_open(git_filebuf *lock, const char *path, int flags); +int git_filebuf_commit(git_filebuf *lock); +void git_filebuf_cleanup(git_filebuf *lock); +int git_filebuf_hash(git_oid *oid, git_filebuf *file); + +#endif diff --git a/vendor/libgit2/src/filelock.c b/vendor/libgit2/src/filelock.c deleted file mode 100755 index 9db1cd720..000000000 --- a/vendor/libgit2/src/filelock.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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 "filelock.h" -#include "fileops.h" - -static const char *GIT_FILELOCK_EXTENSION = ".lock\0"; -static const size_t GIT_FILELOCK_EXTLENGTH = 6; - -#define BUILD_PATH_LOCK(_lock, _path) { \ - memcpy(_path, _lock->path, _lock->path_length); \ - memcpy(_path + _lock->path_length, GIT_FILELOCK_EXTENSION,\ - GIT_FILELOCK_EXTLENGTH);\ -} - -int git_filelock_init(git_filelock *lock, const char *path) -{ - if (lock == NULL || path == NULL) - return GIT_ERROR; - - memset(lock, 0x0, sizeof(git_filelock)); - - lock->path_length = strlen(path); - - if (lock->path_length + GIT_FILELOCK_EXTLENGTH >= GIT_PATH_MAX) - return GIT_ERROR; - - memcpy(lock->path, path, lock->path_length); - return GIT_SUCCESS; -} - -int git_filelock_lock(git_filelock *lock, int append) -{ - char path_lock[GIT_PATH_MAX]; - BUILD_PATH_LOCK(lock, path_lock); - - /* If file already exists, we cannot create a lock */ - if (gitfo_exists(path_lock) == 0) - return GIT_EOSERR; - - lock->file_lock = gitfo_creat(path_lock, 0666); - - if (lock->file_lock < 0) - return GIT_EOSERR; - - lock->is_locked = 1; - - /* TODO: do a flock() in the descriptor file_lock */ - - if (append && gitfo_exists(lock->path) == 0) { - git_file source; - char buffer[2048]; - size_t read_bytes; - - source = gitfo_open(lock->path, O_RDONLY); - if (source < 0) - return GIT_EOSERR; - - while ((read_bytes = gitfo_read(source, buffer, 2048)) > 0) - gitfo_write(lock->file_lock, buffer, read_bytes); - - gitfo_close(source); - } - - return GIT_SUCCESS; -} - -void git_filelock_unlock(git_filelock *lock) -{ - char path_lock[GIT_PATH_MAX]; - BUILD_PATH_LOCK(lock, path_lock); - - if (lock->is_locked) { - /* The flock() in lock->file_lock is removed - * automatically when closing the descriptor */ - gitfo_close(lock->file_lock); - gitfo_unlink(path_lock); - lock->is_locked = 0; - } -} - -int git_filelock_commit(git_filelock *lock) -{ - int error; - char path_lock[GIT_PATH_MAX]; - BUILD_PATH_LOCK(lock, path_lock); - - if (!lock->is_locked || lock->file_lock < 0) - return GIT_ERROR; - - /* FIXME: flush the descriptor? */ - gitfo_close(lock->file_lock); - - error = gitfo_move_file(path_lock, lock->path); - - if (error < GIT_SUCCESS) - gitfo_unlink(path_lock); - - lock->is_locked = 0; - return error; -} - -int git_filelock_write(git_filelock *lock, const void *buffer, size_t length) -{ - if (!lock->is_locked || lock->file_lock < 0) - return GIT_ERROR; - - return gitfo_write(lock->file_lock, (void *)buffer, length); -} diff --git a/vendor/libgit2/src/filelock.h b/vendor/libgit2/src/filelock.h deleted file mode 100755 index bff861811..000000000 --- a/vendor/libgit2/src/filelock.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef INCLUDE_filelock_h__ -#define INCLUDE_filelock_h__ - -#include "fileops.h" - -struct git_filelock { - - char path[GIT_PATH_MAX]; - size_t path_length; - - git_file file_lock; - int is_locked; -}; - -typedef struct git_filelock git_filelock; - -int git_filelock_init(git_filelock *lock, const char *path); -int git_filelock_lock(git_filelock *lock, int append); -void git_filelock_unlock(git_filelock *lock); -int git_filelock_commit(git_filelock *lock); -int git_filelock_write(git_filelock *lock, const void *buffer, size_t length); - -#endif diff --git a/vendor/libgit2/src/fileops.c b/vendor/libgit2/src/fileops.c old mode 100755 new mode 100644 index 461dcf0ad..7691129f6 --- a/vendor/libgit2/src/fileops.c +++ b/vendor/libgit2/src/fileops.c @@ -142,8 +142,17 @@ void gitfo_free_buf(gitfo_buf *obj) obj->data = NULL; } -int gitfo_move_file(char *from, char *to) +int gitfo_mv(const char *from, const char *to) { +#ifdef GIT_WIN32 + /* + * Win32 POSIX compilance my ass. If the destination + * file exists, the `rename` call fails. This is as + * close as it gets with the Win32 API. + */ + return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING) ? GIT_SUCCESS : GIT_EOSERR; +#else + /* Don't even try this on Win32 */ if (!link(from, to)) { gitfo_unlink(from); return GIT_SUCCESS; @@ -153,6 +162,30 @@ int gitfo_move_file(char *from, char *to) return GIT_SUCCESS; return GIT_EOSERR; +#endif +} + +int gitfo_mv_force(const char *from, const char *to) +{ + const int mode = 0755; /* or 0777 ? */ + int error = GIT_SUCCESS; + char target_folder_path[GIT_PATH_MAX]; + + error = git__dirname_r(target_folder_path, sizeof(target_folder_path), to); + if (error < GIT_SUCCESS) + return error; + + /* Does the containing folder exist? */ + if (gitfo_isdir(target_folder_path)) { + git__joinpath(target_folder_path, target_folder_path, ""); /* Ensure there's a trailing slash */ + + /* Let's create the tree structure */ + error = gitfo_mkdir_recurs(target_folder_path, mode); + if (error < GIT_SUCCESS) + return error; + } + + return gitfo_mv(from, to); } int gitfo_map_ro(git_map *out, git_file fd, git_off_t begin, size_t len) @@ -483,3 +516,22 @@ int gitfo_prettify_file_path(char *buffer_out, const char *path) return GIT_SUCCESS; } + +int gitfo_cmp_path(const char *name1, int len1, int isdir1, + const char *name2, int len2, int isdir2) +{ + int len = len1 < len2 ? len1 : len2; + int cmp; + + cmp = memcmp(name1, name2, len); + if (cmp) + return cmp; + if (len1 < len2) + return ((!isdir1 && !isdir2) ? -1 : + (isdir1 ? '/' - name2[len1] : name2[len1] - '/')); + if (len1 > len2) + return ((!isdir1 && !isdir2) ? 1 : + (isdir2 ? name1[len2] - '/' : '/' - name1[len2])); + return 0; +} + diff --git a/vendor/libgit2/src/fileops.h b/vendor/libgit2/src/fileops.h old mode 100755 new mode 100644 index d333805d9..fd150df5e --- a/vendor/libgit2/src/fileops.h +++ b/vendor/libgit2/src/fileops.h @@ -68,7 +68,13 @@ extern git_off_t gitfo_size(git_file fd); extern int gitfo_read_file(gitfo_buf *obj, const char *path); extern void gitfo_free_buf(gitfo_buf *obj); -extern int gitfo_move_file(char *from, char *to); + +/* Move (rename) a file; this operation is atomic */ +extern int gitfo_mv(const char *from, const char *to); + +/* Move a file (forced); this will create the destination + * path if it doesn't exist */ +extern int gitfo_mv_force(const char *from, const char *to); #define gitfo_stat(p,b) stat(p, b) #define gitfo_fstat(f,b) fstat(f, b) @@ -131,6 +137,10 @@ extern int gitfo_write_cached(gitfo_cache *ioc, void *buf, size_t len); extern int gitfo_flush_cached(gitfo_cache *ioc); extern int gitfo_close_cached(gitfo_cache *ioc); + +extern int gitfo_cmp_path(const char *name1, int len1, int isdir1, + const char *name2, int len2, int isdir2); + /** * Clean up a provided absolute or relative directory path. * diff --git a/vendor/libgit2/src/hash.c b/vendor/libgit2/src/hash.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/hash.h b/vendor/libgit2/src/hash.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/hashtable.c b/vendor/libgit2/src/hashtable.c old mode 100755 new mode 100644 index 67fd49a46..c36d8a8e6 --- a/vendor/libgit2/src/hashtable.c +++ b/vendor/libgit2/src/hashtable.c @@ -27,46 +27,113 @@ #include "repository.h" #include "commit.h" +#define MAX_LOOPS 5 static const double max_load_factor = 0.65; -static void hashtable_resize(git_hashtable *table) +static int resize_to(git_hashtable *self, size_t new_size); +static int set_size(git_hashtable *self, size_t new_size); +static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id); +static void node_swap_with(git_hashtable_node *self, git_hashtable_node *other); +static int node_insert(git_hashtable *self, git_hashtable_node *new_node); +static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size); + +static int resize_to(git_hashtable *self, size_t new_size) { - git_hashtable_node **new_nodes; - unsigned int new_size, i; + git_hashtable_node *old_nodes = self->nodes; + size_t old_size = self->size; + + self->is_resizing = 1; + + do { + self->size = new_size; + self->size_mask = new_size - 1; + self->key_count = 0; + self->nodes = git__calloc(1, sizeof(git_hashtable_node) * self->size); + + if (self->nodes == NULL) + return GIT_ENOMEM; + + if (insert_nodes(self, old_nodes, old_size) == 0) + self->is_resizing = 0; + else { + new_size *= 2; + free(self->nodes); + } + } while(self->is_resizing); + + free(old_nodes); + return GIT_SUCCESS; +} - assert(table); +static int set_size(git_hashtable *self, size_t new_size) +{ + self->nodes = realloc(self->nodes, new_size * sizeof(git_hashtable_node)); + if (self->nodes == NULL) + return GIT_ENOMEM; - new_size = (table->size_mask + 1) * 2; + if (new_size > self->size) { + memset(&self->nodes[self->size], 0x0, (new_size - self->size) * sizeof(git_hashtable_node)); + } - new_nodes = git__malloc(new_size * sizeof(git_hashtable_node *)); - if (new_nodes == NULL) - return; + self->size = new_size; + self->size_mask = new_size - 1; + return GIT_SUCCESS; +} - memset(new_nodes, 0x0, new_size * sizeof(git_hashtable_node *)); +static git_hashtable_node *node_with_hash(git_hashtable *self, const void *key, int hash_id) +{ + size_t pos = self->hash(key, hash_id) & self->size_mask; + return git_hashtable_node_at(self->nodes, pos); +} - for (i = 0; i <= table->size_mask; ++i) { - git_hashtable_node *n; - unsigned int index; +static void node_swap_with(git_hashtable_node *self, git_hashtable_node *other) +{ + git_hashtable_node tmp = *self; + *self = *other; + *other = tmp; +} - while ((n = table->nodes[i]) != NULL) { - table->nodes[i] = n->next; - index = n->hash & (new_size - 1); - n->next = new_nodes[index]; - new_nodes[index] = n; +static int node_insert(git_hashtable *self, git_hashtable_node *new_node) +{ + int iteration, hash_id; + + for (iteration = 0; iteration < MAX_LOOPS; iteration++) { + for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { + git_hashtable_node *node; + node = node_with_hash(self, new_node->key, hash_id); + node_swap_with(new_node, node); + if(new_node->key == 0x0){ + self->key_count++; + return GIT_SUCCESS; + } } } - free(table->nodes); - table->nodes = new_nodes; - table->size_mask = (new_size - 1); - table->max_count = (unsigned int)(new_size * max_load_factor); + if (self->is_resizing) + return GIT_EBUSY; + + resize_to(self, self->size * 2); + git_hashtable_insert(self, new_node->key, new_node->value); + return GIT_SUCCESS; +} + +static int insert_nodes(git_hashtable *self, git_hashtable_node *old_nodes, size_t old_size) +{ + size_t i; + + for (i = 0; i < old_size; ++i) { + git_hashtable_node *node = git_hashtable_node_at(old_nodes, i); + if (node->key && git_hashtable_insert(self, node->key, node->value) < GIT_SUCCESS) + return GIT_ENOMEM; + } + + return GIT_SUCCESS; } -git_hashtable *git_hashtable_alloc(unsigned int min_size, +git_hashtable *git_hashtable_alloc(size_t min_size, git_hash_ptr hash, git_hash_keyeq_ptr key_eq) { - unsigned int i; git_hashtable *table; assert(hash && key_eq); @@ -74,6 +141,11 @@ git_hashtable *git_hashtable_alloc(unsigned int min_size, if ((table = git__malloc(sizeof(git_hashtable))) == NULL) return NULL; + memset(table, 0x0, sizeof(git_hashtable)); + + if (min_size < 8) + min_size = 8; + /* round up size to closest power of 2 */ min_size--; min_size |= min_size >> 1; @@ -82,167 +154,102 @@ git_hashtable *git_hashtable_alloc(unsigned int min_size, min_size |= min_size >> 8; min_size |= min_size >> 16; - table->size_mask = min_size; - table->count = 0; - table->max_count = (unsigned int)((min_size + 1) * max_load_factor); - table->hash = hash; table->key_equal = key_eq; - table->nodes = git__malloc((min_size + 1) * sizeof(git_hashtable_node *)); - - if (table->nodes == NULL) { - free(table); - return NULL; - } - - for (i = 0; i <= min_size; ++i) - table->nodes[i] = NULL; + set_size(table, min_size + 1); return table; } -void git_hashtable_clear(git_hashtable *table) +void git_hashtable_clear(git_hashtable *self) { - unsigned int index; - - assert(table); - - for (index = 0; index <= table->size_mask; ++index) { - git_hashtable_node *node, *next_node; + assert(self); - node = table->nodes[index]; - while (node != NULL) { - next_node = node->next; - free(node); - node = next_node; - } - - table->nodes[index] = NULL; - } - - table->count = 0; + memset(self->nodes, 0x0, sizeof(git_hashtable_node) * self->size); + self->key_count = 0; } -void git_hashtable_free(git_hashtable *table) +void git_hashtable_free(git_hashtable *self) { - assert(table); + assert(self); - git_hashtable_clear(table); - free(table->nodes); - free(table); + free(self->nodes); + free(self); } -int git_hashtable_insert(git_hashtable *table, const void *key, void *value) +int git_hashtable_insert2(git_hashtable *self, const void *key, void *value, void **old_value) { + int hash_id; git_hashtable_node *node; - uint32_t index, hash; - assert(table); + *old_value = NULL; - if (table->count + 1 > table->max_count) - hashtable_resize(table); + for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { + node = node_with_hash(self, key, hash_id); - node = git__malloc(sizeof(git_hashtable_node)); - if (node == NULL) - return GIT_ENOMEM; - - hash = table->hash(key); - index = (hash & table->size_mask); - - node->object = value; - node->hash = hash; - node->next = table->nodes[index]; + if (!node->key) { + node->key = key; + node->value = value; + self->key_count++; + return GIT_SUCCESS; + } - table->nodes[index] = node; - table->count++; + if (key == node->key || self->key_equal(key, node->key) == 0) { + *old_value = node->value; + node->key = key; + node->value = value; + return GIT_SUCCESS; + } + } - return GIT_SUCCESS; + /* no space in table; must do cuckoo dance */ + { + git_hashtable_node x; + x.key = key; + x.value = value; + return node_insert(self, &x); + } } -void *git_hashtable_lookup(git_hashtable *table, const void *key) +void *git_hashtable_lookup(git_hashtable *self, const void *key) { + int hash_id; git_hashtable_node *node; - uint32_t index, hash; - assert(table); - - hash = table->hash(key); - index = (hash & table->size_mask); - node = table->nodes[index]; - - while (node != NULL) { - if (node->hash == hash && table->key_equal(node->object, key)) - return node->object; - - node = node->next; + for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { + node = node_with_hash(self, key, hash_id); + if (node->key && self->key_equal(key, node->key) == 0) + return node->value; } return NULL; } -int git_hashtable_remove(git_hashtable *table, const void *key) +int git_hashtable_remove(git_hashtable *self, const void *key) { - git_hashtable_node *node, *prev_node; - uint32_t index, hash; - - assert(table); - - hash = table->hash(key); - index = (hash & table->size_mask); - node = table->nodes[index]; - - prev_node = NULL; - - while (node != NULL) { - if (node->hash == hash && table->key_equal(node->object, key)) { - if (prev_node == NULL) - table->nodes[index] = node->next; - else - prev_node->next = node->next; + int hash_id; + git_hashtable_node *node; - free(node); + for (hash_id = 0; hash_id < GIT_HASHTABLE_HASHES; ++hash_id) { + node = node_with_hash(self, key, hash_id); + if (node->key && self->key_equal(key, node->key) == 0) { + node->key = NULL; + node->value = NULL; + self->key_count--; return GIT_SUCCESS; } - - prev_node = node; - node = node->next; } return GIT_ENOTFOUND; } - - -void git_hashtable_iterator_init(git_hashtable *table, git_hashtable_iterator *it) -{ - assert(table && it); - - memset(it, 0x0, sizeof(git_hashtable_iterator)); - - it->nodes = table->nodes; - it->current_node = NULL; - it->current_pos = 0; - it->size = table->size_mask + 1; -} - -void *git_hashtable_iterator_next(git_hashtable_iterator *it) +int git_hashtable_merge(git_hashtable *self, git_hashtable *other) { - git_hashtable_node *next = NULL; - - assert(it); - - while (it->current_node == NULL) { - if (it->current_pos >= it->size) - return NULL; - - it->current_node = it->nodes[it->current_pos++]; - } - - next = it->current_node; - it->current_node = it->current_node->next; + if (resize_to(self, (self->size + other->size) * 2) < GIT_SUCCESS) + return GIT_ENOMEM; - return next->object; + return insert_nodes(self, other->nodes, other->key_count); } diff --git a/vendor/libgit2/src/hashtable.h b/vendor/libgit2/src/hashtable.h old mode 100755 new mode 100644 index 69535040d..c3475b6ed --- a/vendor/libgit2/src/hashtable.h +++ b/vendor/libgit2/src/hashtable.h @@ -5,48 +5,69 @@ #include "git2/oid.h" #include "git2/odb.h" +#define GIT_HASHTABLE_HASHES 3 -typedef uint32_t (*git_hash_ptr)(const void *); -typedef int (*git_hash_keyeq_ptr)(void *obj, const void *obj_key); +typedef uint32_t (*git_hash_ptr)(const void *, int hash_id); +typedef int (*git_hash_keyeq_ptr)(const void *key_a, const void *key_b); struct git_hashtable_node { - void *object; - uint32_t hash; - struct git_hashtable_node *next; + const void *key; + void *value; }; struct git_hashtable { - struct git_hashtable_node **nodes; + struct git_hashtable_node *nodes; - unsigned int size_mask; - unsigned int count; - unsigned int max_count; + size_t size_mask; + size_t size; + size_t key_count; + + int is_resizing; git_hash_ptr hash; git_hash_keyeq_ptr key_equal; }; -struct git_hashtable_iterator { - struct git_hashtable_node **nodes; - struct git_hashtable_node *current_node; - unsigned int current_pos; - unsigned int size; -}; - typedef struct git_hashtable_node git_hashtable_node; typedef struct git_hashtable git_hashtable; -typedef struct git_hashtable_iterator git_hashtable_iterator; -git_hashtable *git_hashtable_alloc(unsigned int min_size, +git_hashtable *git_hashtable_alloc(size_t min_size, git_hash_ptr hash, git_hash_keyeq_ptr key_eq); -int git_hashtable_insert(git_hashtable *h, const void *key, void *value); void *git_hashtable_lookup(git_hashtable *h, const void *key); int git_hashtable_remove(git_hashtable *table, const void *key); void git_hashtable_free(git_hashtable *h); void git_hashtable_clear(git_hashtable *h); +int git_hashtable_merge(git_hashtable *self, git_hashtable *other); + +int git_hashtable_insert2(git_hashtable *h, const void *key, void *value, void **old_value); + +GIT_INLINE(int) git_hashtable_insert(git_hashtable *h, const void *key, void *value) +{ + void *_unused; + return git_hashtable_insert2(h, key, value, &_unused); +} + +#define git_hashtable_node_at(nodes, pos) ((git_hashtable_node *)(&nodes[pos])) + +#define GIT_HASHTABLE_FOREACH(self, pkey, pvalue, code) {\ + git_hashtable *_self = (self);\ + git_hashtable_node *_nodes = _self->nodes;\ + unsigned int _i, _size = _self->size;\ + for (_i = 0; _i < _size; _i ++) {\ + git_hashtable_node *_node = git_hashtable_node_at(_nodes, _i);\ + if (_node->key)\ + {\ + pkey = _node->key;\ + pvalue = _node->value;\ + code;\ + }\ + }\ +} + +#define GIT_HASHTABLE_FOREACH_DELETE() {\ + _node->key = NULL; _node->value = NULL; _self->key_count--;\ +} -void *git_hashtable_iterator_next(git_hashtable_iterator *it); -void git_hashtable_iterator_init(git_hashtable *h, git_hashtable_iterator *it); #endif diff --git a/vendor/libgit2/src/index.c b/vendor/libgit2/src/index.c old mode 100755 new mode 100644 index 6fdb46e18..95e56b7d5 --- a/vendor/libgit2/src/index.c +++ b/vendor/libgit2/src/index.c @@ -32,23 +32,20 @@ #include "git2/odb.h" #include "git2/blob.h" -#define entry_padding(type, len) (8 - ((offsetof(type, path) + (len)) & 0x7)) -#define short_entry_padding(len) entry_padding(struct entry_short, len) -#define long_entry_padding(len) entry_padding(struct entry_long, len) - #define entry_size(type,len) ((offsetof(type, path) + (len) + 8) & ~7) #define short_entry_size(len) entry_size(struct entry_short, len) #define long_entry_size(len) entry_size(struct entry_long, len) #define minimal_entry_size (offsetof(struct entry_short, path)) -static const char INDEX_HEADER_SIG[] = {'D', 'I', 'R', 'C'}; -static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; - static const size_t INDEX_FOOTER_SIZE = GIT_OID_RAWSZ; static const size_t INDEX_HEADER_SIZE = 12; static const unsigned int INDEX_VERSION_NUMBER = 2; +static const unsigned int INDEX_VERSION_NUMBER_EXT = 3; + +static const unsigned int INDEX_HEADER_SIG = 0x44495243; +static const char INDEX_EXT_TREECACHE_SIG[] = {'T', 'R', 'E', 'E'}; struct index_header { uint32_t signature; @@ -103,6 +100,9 @@ static int read_header(struct index_header *dest, const void *buffer); 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 void sort_index(git_index *index); +static int write_index(git_index *index, git_filebuf *file); int index_srch(const void *key, const void *array_member) { @@ -141,7 +141,7 @@ static int index_initialize(git_index **index_out, git_repository *owner, const index->repository = owner; - git_vector_init(&index->entries, 32, index_cmp, index_srch); + git_vector_init(&index->entries, 32, index_cmp); /* Check if index file is stored on disk already */ if (gitfo_exists(index->index_file_path) == 0) @@ -164,6 +164,33 @@ int git_index_open_inrepo(git_index **index_out, git_repository *repo) return index_initialize(index_out, repo, repo->path_index); } +void git_index_free(git_index *index) +{ + if (index == NULL || index->repository != NULL) + return; + + git_index_clear(index); + git_vector_free(&index->entries); + + free(index->index_file_path); + free(index); +} + +static void free_tree(git_index_tree *tree) +{ + unsigned int i; + + if (tree == NULL) + return; + + for (i = 0; i < tree->children_count; ++i) + free_tree(tree->children[i]); + + free(tree->name); + free(tree->children); + free(tree); +} + void git_index_clear(git_index *index) { unsigned int i; @@ -179,25 +206,11 @@ void git_index_clear(git_index *index) git_vector_clear(&index->entries); index->last_modified = 0; - index->sorted = 1; - git_index_tree__free(index->tree); + free_tree(index->tree); index->tree = NULL; } -void git_index_free(git_index *index) -{ - if (index == NULL) - return; - - git_index_clear(index); - git_vector_free(&index->entries); - - free(index->index_file_path); - free(index); -} - - int git_index_read(git_index *index) { struct stat indexst; @@ -225,7 +238,7 @@ int git_index_read(git_index *index) return GIT_EOSERR; git_index_clear(index); - error = git_index__parse(index, buffer.data, buffer.len); + error = parse_index(index, buffer.data, buffer.len); if (error == GIT_SUCCESS) index->last_modified = indexst.st_mtime; @@ -238,25 +251,22 @@ int git_index_read(git_index *index) int git_index_write(git_index *index) { - git_filelock file; + git_filebuf file; struct stat indexst; + int error; - if (!index->sorted) - git_index__sort(index); - - if (git_filelock_init(&file, index->index_file_path) < GIT_SUCCESS) - return GIT_EFLOCKFAIL; + sort_index(index); - if (git_filelock_lock(&file, 0) < GIT_SUCCESS) - return GIT_EFLOCKFAIL; + if ((error = git_filebuf_open(&file, index->index_file_path, GIT_FILEBUF_HASH_CONTENTS)) < GIT_SUCCESS) + return error; - if (git_index__write(index, &file) < GIT_SUCCESS) { - git_filelock_unlock(&file); - return GIT_EOSERR; + if ((error = write_index(index, &file)) < GIT_SUCCESS) { + git_filebuf_cleanup(&file); + return error; } - if (git_filelock_commit(&file) < GIT_SUCCESS) - return GIT_EFLOCKFAIL; + if ((error = git_filebuf_commit(&file)) < GIT_SUCCESS) + return error; if (gitfo_stat(index->index_file_path, &indexst) == 0) { index->last_modified = indexst.st_mtime; @@ -275,7 +285,7 @@ unsigned int git_index_entrycount(git_index *index) git_index_entry *git_index_get(git_index *index, int n) { assert(index); - git_index__sort(index); + sort_index(index); return git_vector_get(&index->entries, (unsigned int)n); } @@ -289,8 +299,7 @@ int git_index_add(git_index *index, const char *rel_path, int stage) if (index->repository == NULL) return GIT_EBAREINDEX; - strcpy(full_path, index->repository->path_workdir); - strcat(full_path, rel_path); + git__joinpath(full_path, index->repository->path_workdir, rel_path); if (gitfo_exists(full_path) < 0) return GIT_ENOTFOUND; @@ -324,12 +333,9 @@ int git_index_add(git_index *index, const char *rel_path, int stage) return git_index_insert(index, &entry); } -void git_index__sort(git_index *index) +void sort_index(git_index *index) { - if (index->sorted == 0) { - git_vector_sort(&index->entries); - index->sorted = 1; - } + git_vector_sort(&index->entries); } int git_index_insert(git_index *index, const git_index_entry *source_entry) @@ -374,8 +380,6 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry) if (git_vector_insert(&index->entries, entry) < GIT_SUCCESS) return GIT_ENOMEM; - index->sorted = 0; - /* if a previous entry exists, replace it */ } else { git_index_entry **entry_array = (git_index_entry **)index->entries.contents; @@ -392,29 +396,14 @@ int git_index_insert(git_index *index, const git_index_entry *source_entry) int git_index_remove(git_index *index, int position) { assert(index); - git_index__sort(index); + sort_index(index); return git_vector_remove(&index->entries, (unsigned int)position); } int git_index_find(git_index *index, const char *path) { - git_index__sort(index); - return git_vector_search(&index->entries, path); -} - -void git_index_tree__free(git_index_tree *tree) -{ - unsigned int i; - - if (tree == NULL) - return; - - for (i = 0; i < tree->children_count; ++i) - git_index_tree__free(tree->children[i]); - - free(tree->name); - free(tree->children); - free(tree); + sort_index(index); + return git_vector_bsearch2(&index->entries, index_srch, path); } static git_index_tree *read_tree_internal( @@ -476,7 +465,7 @@ static git_index_tree *read_tree_internal( return tree; error_cleanup: - git_index_tree__free(tree); + free_tree(tree); return NULL; } @@ -557,12 +546,13 @@ static int read_header(struct index_header *dest, const void *buffer) const struct index_header *source; source = (const struct index_header *)(buffer); - dest->signature = source->signature; - if (memcmp(&dest->signature, INDEX_HEADER_SIG, 4) != 0) + dest->signature = ntohl(source->signature); + if (dest->signature != INDEX_HEADER_SIG) return GIT_EOBJCORRUPTED; dest->version = ntohl(source->version); - if (dest->version != INDEX_VERSION_NUMBER) + if (dest->version != INDEX_VERSION_NUMBER_EXT && + dest->version != INDEX_VERSION_NUMBER) return GIT_EOBJCORRUPTED; dest->entry_count = ntohl(source->entry_count); @@ -602,7 +592,7 @@ static size_t read_extension(git_index *index, const char *buffer, size_t buffer return total_size; } -int git_index__parse(git_index *index, const char *buffer, size_t buffer_size) +static int parse_index(git_index *index, const char *buffer, size_t buffer_size) { unsigned int i; struct index_header header; @@ -678,90 +668,101 @@ int git_index__parse(git_index *index, const char *buffer, size_t buffer_size) #undef seek_forward + /* force sorting in the vector: the entries are + * assured to be sorted on the index */ + index->entries.sorted = 1; return GIT_SUCCESS; } -int git_index__write(git_index *index, git_filelock *file) +static int write_disk_entry(git_filebuf *file, git_index_entry *entry) { - static const char NULL_BYTES[] = {0, 0, 0, 0, 0, 0, 0, 0}; - - int error = GIT_SUCCESS; - unsigned int i; + struct entry_short *ondisk; + size_t path_len, disk_size; + char *path; - git_hash_ctx *digest; - git_oid hash_final; + path_len = strlen(entry->path); - assert(index && file && file->is_locked); + if (entry->flags & GIT_IDXENTRY_EXTENDED) + disk_size = long_entry_size(path_len); + else + disk_size = short_entry_size(path_len); - if ((digest = git_hash_new_ctx()) == NULL) + if (git_filebuf_reserve(file, (void **)&ondisk, disk_size) < GIT_SUCCESS) return GIT_ENOMEM; -#define WRITE_WORD(_word) {\ - uint32_t network_word = htonl(((uint32_t)(_word)));\ - git_filelock_write(file, &network_word, 4);\ - git_hash_update(digest, &network_word, 4);\ -} + memset(ondisk, 0x0, disk_size); -#define WRITE_SHORT(_shrt) {\ - uint16_t network_shrt = htons((_shrt));\ - git_filelock_write(file, &network_shrt, 2);\ - git_hash_update(digest, &network_shrt, 2);\ -} + ondisk->ctime.seconds = htonl((unsigned long)entry->ctime.seconds); + ondisk->mtime.seconds = htonl((unsigned long)entry->mtime.seconds); + ondisk->ctime.nanoseconds = htonl(entry->ctime.nanoseconds); + ondisk->mtime.nanoseconds = htonl(entry->mtime.nanoseconds); + ondisk->dev = htonl(entry->dev); + ondisk->ino = htonl(entry->ino); + ondisk->mode = htonl(entry->mode); + ondisk->uid = htonl(entry->uid); + ondisk->gid = htonl(entry->gid); + ondisk->file_size = htonl((unsigned long)entry->file_size); -#define WRITE_BYTES(_bytes, _n) {\ - git_filelock_write(file, _bytes, _n);\ - git_hash_update(digest, _bytes, _n);\ -} + git_oid_cpy(&ondisk->oid, &entry->oid); + + ondisk->flags = htons(entry->flags); + + if (entry->flags & GIT_IDXENTRY_EXTENDED) { + struct entry_long *ondisk_ext; + ondisk_ext = (struct entry_long *)ondisk; + ondisk_ext->flags_extended = htons(entry->flags_extended); + path = ondisk_ext->path; + } + else + path = ondisk->path; + + memcpy(path, entry->path, path_len); - WRITE_BYTES(INDEX_HEADER_SIG, 4); + return GIT_SUCCESS; +} - WRITE_WORD(INDEX_VERSION_NUMBER); - WRITE_WORD(index->entries.length); +static int write_entries(git_index *index, git_filebuf *file) +{ + unsigned int i; for (i = 0; i < index->entries.length; ++i) { git_index_entry *entry; - size_t path_length, padding; - entry = git_vector_get(&index->entries, i); - path_length = strlen(entry->path); - - WRITE_WORD(entry->ctime.seconds); - WRITE_WORD(entry->ctime.nanoseconds); - WRITE_WORD(entry->mtime.seconds); - WRITE_WORD(entry->mtime.nanoseconds); - WRITE_WORD(entry->dev); - WRITE_WORD(entry->ino); - WRITE_WORD(entry->mode); - WRITE_WORD(entry->uid); - WRITE_WORD(entry->gid); - WRITE_WORD(entry->file_size); - WRITE_BYTES(entry->oid.id, GIT_OID_RAWSZ); - - if (entry->flags_extended != 0) - entry->flags |= GIT_IDXENTRY_EXTENDED; - - WRITE_SHORT(entry->flags); - - if (entry->flags & GIT_IDXENTRY_EXTENDED) { - WRITE_SHORT(entry->flags_extended); - padding = long_entry_padding(path_length); - } else - padding = short_entry_padding(path_length); - - WRITE_BYTES(entry->path, path_length); - WRITE_BYTES(NULL_BYTES, padding); + if (write_disk_entry(file, entry) < GIT_SUCCESS) + return GIT_ENOMEM; } -#undef WRITE_WORD -#undef WRITE_BYTES -#undef WRITE_SHORT -#undef WRITE_FLAGS + return GIT_SUCCESS; +} + +static int write_index(git_index *index, git_filebuf *file) +{ + int error = GIT_SUCCESS; + git_oid hash_final; + + struct index_header header; + + int is_extended = 1; + + assert(index && file); + + header.signature = htonl(INDEX_HEADER_SIG); + header.version = htonl(is_extended ? INDEX_VERSION_NUMBER : INDEX_VERSION_NUMBER_EXT); + header.entry_count = htonl(index->entries.length); + + git_filebuf_write(file, &header, sizeof(struct index_header)); + + error = write_entries(index, file); + if (error < GIT_SUCCESS) + return error; /* TODO: write extensions (tree cache) */ - git_hash_final(&hash_final, digest); - git_hash_free_ctx(digest); - git_filelock_write(file, hash_final.id, GIT_OID_RAWSZ); + /* get out the hash for all the contents we've appended to the file */ + git_filebuf_hash(&hash_final, file); + + /* write it at the end of the file */ + git_filebuf_write(file, hash_final.id, GIT_OID_RAWSZ); return error; } diff --git a/vendor/libgit2/src/index.h b/vendor/libgit2/src/index.h old mode 100755 new mode 100644 index 9e45a6372..e1e752f7c --- a/vendor/libgit2/src/index.h +++ b/vendor/libgit2/src/index.h @@ -2,7 +2,7 @@ #define INCLUDE_index_h__ #include "fileops.h" -#include "filelock.h" +#include "filebuf.h" #include "vector.h" #include "git2/odb.h" #include "git2/index.h" @@ -27,18 +27,8 @@ struct git_index { time_t last_modified; git_vector entries; - unsigned int sorted:1, - on_disk:1; - + unsigned int on_disk:1; git_index_tree *tree; }; -int git_index__write(git_index *index, git_filelock *file); -void git_index__sort(git_index *index); -int git_index__parse(git_index *index, const char *buffer, size_t buffer_size); -int git_index__remove_pos(git_index *index, unsigned int position); -int git_index__append(git_index *index, const git_index_entry *entry); - -void git_index_tree__free(git_index_tree *tree); - #endif diff --git a/vendor/libgit2/src/map.h b/vendor/libgit2/src/map.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/mingw-compat.h b/vendor/libgit2/src/mingw-compat.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/msvc-compat.h b/vendor/libgit2/src/msvc-compat.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/object.c b/vendor/libgit2/src/object.c old mode 100755 new mode 100644 index dd84cb5d7..de02ef5f2 --- a/vendor/libgit2/src/object.c +++ b/vendor/libgit2/src/object.c @@ -166,8 +166,12 @@ static int write_back(git_object *object) if ((error = git_odb_write(&new_id, object->repo->db, &object->source.raw)) < GIT_SUCCESS) return error; - if (!object->in_memory) + if (object->in_memory) { + int idx = git_vector_search(&object->repo->memory_objects, object); + git_vector_remove(&object->repo->memory_objects, idx); + } else { git_hashtable_remove(object->repo->objects, &object->id); + } git_oid_cpy(&object->id, &new_id); git_hashtable_insert(object->repo->objects, &object->id, object); @@ -209,6 +213,128 @@ void git_object__source_close(git_object *object) } } +static int create_object(git_object **object_out, git_otype type) +{ + git_object *object = NULL; + + assert(object_out); + + *object_out = NULL; + + switch (type) { + case GIT_OBJ_COMMIT: + case GIT_OBJ_TAG: + case GIT_OBJ_BLOB: + object = git__malloc(git_object__size(type)); + if (object == NULL) + return GIT_ENOMEM; + memset(object, 0x0, git_object__size(type)); + break; + + case GIT_OBJ_TREE: + object = (git_object *)git_tree__new(); + if (object == NULL) + return GIT_ENOMEM; + break; + + default: + return GIT_EINVALIDTYPE; + } + + *object_out = object; + return GIT_SUCCESS; +} + +int git_object_new(git_object **object_out, git_repository *repo, git_otype type) +{ + git_object *object = NULL; + int error; + + assert(object_out && repo); + + if ((error = create_object(&object, type)) < GIT_SUCCESS) + return error; + + object->repo = repo; + object->in_memory = 1; + object->modified = 1; + + object->source.raw.type = type; + + object->refcount++; + *object_out = object; + return GIT_SUCCESS; +} + +int git_object_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) +{ + git_object *object = NULL; + git_rawobj obj_file; + int error = GIT_SUCCESS; + + assert(repo && object_out && id); + + object = git_hashtable_lookup(repo->objects, id); + if (object != NULL) { + *object_out = object; + GIT_OBJECT_INCREF(object); + return GIT_SUCCESS; + } + + error = git_odb_read(&obj_file, repo->db, id); + if (error < GIT_SUCCESS) + return error; + + if (type != GIT_OBJ_ANY && type != obj_file.type) { + git_rawobj_close(&obj_file); + return GIT_EINVALIDTYPE; + } + + type = obj_file.type; + + if ((error = create_object(&object, type)) < GIT_SUCCESS) + return error; + + /* Initialize parent object */ + git_oid_cpy(&object->id, id); + object->repo = repo; + memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj)); + object->source.open = 1; + + switch (type) { + case GIT_OBJ_COMMIT: + error = git_commit__parse((git_commit *)object); + break; + + case GIT_OBJ_TREE: + error = git_tree__parse((git_tree *)object); + break; + + case GIT_OBJ_TAG: + error = git_tag__parse((git_tag *)object); + break; + + case GIT_OBJ_BLOB: + error = git_blob__parse((git_blob *)object); + break; + + default: + break; + } + + if (error < GIT_SUCCESS) { + git_object__free(object); + return error; + } + + git_object__source_close(object); + git_hashtable_insert(repo->objects, &object->id, object); + + GIT_OBJECT_INCREF(object); + *object_out = object; + return GIT_SUCCESS; +} + int git_object_write(git_object *object) { int error; @@ -252,13 +378,20 @@ int git_object_write(git_object *object) return write_back(object); } -void git_object_free(git_object *object) +void git_object__free(git_object *object) { - if (object == NULL) - return; + assert(object); git_object__source_close(object); - git_hashtable_remove(object->repo->objects, &object->id); + + if (object->repo != NULL) { + if (object->in_memory) { + int idx = git_vector_search(&object->repo->memory_objects, object); + git_vector_remove(&object->repo->memory_objects, idx); + } else { + git_hashtable_remove(object->repo->objects, &object->id); + } + } switch (object->source.raw.type) { case GIT_OBJ_COMMIT: @@ -283,7 +416,16 @@ void git_object_free(git_object *object) } } -const git_oid *git_object_id(git_object *obj) +void git_object_close(git_object *object) +{ + if (object == NULL) + return; + + if (--object->refcount <= 0) + git_object__free(object); +} + +const git_oid *git_object_id(const git_object *obj) { assert(obj); @@ -293,13 +435,13 @@ const git_oid *git_object_id(git_object *obj) return &obj->id; } -git_otype git_object_type(git_object *obj) +git_otype git_object_type(const git_object *obj) { assert(obj); return obj->source.raw.type; } -git_repository *git_object_owner(git_object *obj) +git_repository *git_object_owner(const git_object *obj) { assert(obj); return obj->repo; diff --git a/vendor/libgit2/src/odb.c b/vendor/libgit2/src/odb.c old mode 100755 new mode 100644 index 26b457b7c..2013ac24c --- a/vendor/libgit2/src/odb.c +++ b/vendor/libgit2/src/odb.c @@ -33,6 +33,19 @@ #include "git2/odb_backend.h" +#define GIT_ALTERNATES_FILE "info/alternates" + +/* TODO: is this correct? */ +#define GIT_LOOSE_PRIORITY 2 +#define GIT_PACKED_PRIORITY 1 + +typedef struct +{ + git_odb_backend *backend; + int priority; + int is_alternate; +} backend_internal; + static int format_object_header(char *hdr, size_t n, git_rawobj *obj) { const char *type_str = git_object_type2string(obj->type); @@ -134,10 +147,13 @@ int git_odb__inflate_buffer(void *in, size_t inlen, void *out, size_t outlen) int backend_sort_cmp(const void *a, const void *b) { - const git_odb_backend *backend_a = *(const git_odb_backend **)(a); - const git_odb_backend *backend_b = *(const git_odb_backend **)(b); + const backend_internal *backend_a = *(const backend_internal **)(a); + const backend_internal *backend_b = *(const backend_internal **)(b); - return (backend_b->priority - backend_a->priority); + if (backend_a->is_alternate == backend_b->is_alternate) + return (backend_b->priority - backend_a->priority); + + return backend_a->is_alternate ? 1 : -1; } int git_odb_new(git_odb **out) @@ -146,7 +162,7 @@ int git_odb_new(git_odb **out) if (!db) return GIT_ENOMEM; - if (git_vector_init(&db->backends, 4, backend_sort_cmp, NULL) < 0) { + if (git_vector_init(&db->backends, 4, backend_sort_cmp) < 0) { free(db); return GIT_ENOMEM; } @@ -155,48 +171,114 @@ int git_odb_new(git_odb **out) return GIT_SUCCESS; } -int git_odb_add_backend(git_odb *odb, git_odb_backend *backend) +static int add_backend_internal(git_odb *odb, git_odb_backend *backend, int priority, int is_alternate) { + backend_internal *internal; + assert(odb && backend); if (backend->odb != NULL && backend->odb != odb) return GIT_EBUSY; - backend->odb = odb; + internal = git__malloc(sizeof(backend_internal)); + if (internal == NULL) + return GIT_ENOMEM; + + internal->backend = backend; + internal->priority = priority; + internal->is_alternate = is_alternate; - if (git_vector_insert(&odb->backends, backend) < 0) + if (git_vector_insert(&odb->backends, internal) < 0) { + free(internal); return GIT_ENOMEM; + } git_vector_sort(&odb->backends); + internal->backend->odb = odb; return GIT_SUCCESS; } +int git_odb_add_backend(git_odb *odb, git_odb_backend *backend, int priority) +{ + return add_backend_internal(odb, backend, priority, 0); +} -int git_odb_open(git_odb **out, const char *objects_dir) +int git_odb_add_alternate(git_odb *odb, git_odb_backend *backend, int priority) +{ + return add_backend_internal(odb, backend, priority, 1); +} + +static int add_default_backends(git_odb *db, const char *objects_dir, int as_alternates) { - git_odb *db; git_odb_backend *loose, *packed; int error; - if ((error = git_odb_new(&db)) < 0) + /* add the loose object backend */ + error = git_odb_backend_loose(&loose, objects_dir); + if (error < GIT_SUCCESS) return error; - /* add the loose object backend */ - if (git_odb_backend_loose(&loose, objects_dir) == 0) { - error = git_odb_add_backend(db, loose); - if (error < 0) - goto cleanup; - } + error = add_backend_internal(db, loose, GIT_LOOSE_PRIORITY, as_alternates); + if (error < GIT_SUCCESS) + return error; /* add the packed file backend */ - if (git_odb_backend_pack(&packed, objects_dir) == 0) { - error = git_odb_add_backend(db, packed); - if (error < 0) - goto cleanup; - } + error = git_odb_backend_pack(&packed, objects_dir); + if (error < GIT_SUCCESS) + return error; + + error = add_backend_internal(db, packed, GIT_PACKED_PRIORITY, as_alternates); + if (error < GIT_SUCCESS) + return error; - /* TODO: add altenernates as new backends; - * how elevant is that? very elegant. */ + return GIT_SUCCESS; +} + +static int load_alternates(git_odb *odb, const char *objects_dir) +{ + char alternates_path[GIT_PATH_MAX]; + char alternate[GIT_PATH_MAX]; + char *buffer; + + gitfo_buf alternates_buf = GITFO_BUF_INIT; + int error; + + git__joinpath(alternates_path, objects_dir, GIT_ALTERNATES_FILE); + + if (gitfo_exists(alternates_path) < GIT_SUCCESS) + return GIT_SUCCESS; + + if (gitfo_read_file(&alternates_buf, alternates_path) < GIT_SUCCESS) + return GIT_EOSERR; + + buffer = (char *)alternates_buf.data; + error = GIT_SUCCESS; + + /* add each alternate as a new backend; one alternate per line */ + while ((error == GIT_SUCCESS) && (buffer = git__strtok(alternate, buffer, "\r\n")) != NULL) + error = add_default_backends(odb, alternate, 1); + + gitfo_free_buf(&alternates_buf); + return error; +} + +int git_odb_open(git_odb **out, const char *objects_dir) +{ + git_odb *db; + int error; + + assert(out && objects_dir); + + *out = NULL; + + if ((error = git_odb_new(&db)) < 0) + return error; + + if ((error = add_default_backends(db, objects_dir, 0)) < GIT_SUCCESS) + goto cleanup; + + if ((error = load_alternates(db, objects_dir)) < GIT_SUCCESS) + goto cleanup; *out = db; return GIT_SUCCESS; @@ -214,10 +296,13 @@ void git_odb_close(git_odb *db) return; for (i = 0; i < db->backends.length; ++i) { - git_odb_backend *b = git_vector_get(&db->backends, i); + backend_internal *internal = git_vector_get(&db->backends, i); + git_odb_backend *backend = internal->backend; + + if (backend->free) backend->free(backend); + else free(backend); - if (b->free) b->free(b); - else free(b); + free(internal); } git_vector_free(&db->backends); @@ -232,7 +317,8 @@ int git_odb_exists(git_odb *db, const git_oid *id) assert(db && id); for (i = 0; i < db->backends.length && !found; ++i) { - git_odb_backend *b = git_vector_get(&db->backends, i); + backend_internal *internal = git_vector_get(&db->backends, i); + git_odb_backend *b = internal->backend; if (b->exists != NULL) found = b->exists(b, id); @@ -249,7 +335,8 @@ int git_odb_read_header(git_rawobj *out, git_odb *db, const git_oid *id) assert(out && db && id); for (i = 0; i < db->backends.length && error < 0; ++i) { - git_odb_backend *b = git_vector_get(&db->backends, i); + backend_internal *internal = git_vector_get(&db->backends, i); + git_odb_backend *b = internal->backend; if (b->read_header != NULL) error = b->read_header(out, b, id); @@ -275,7 +362,8 @@ int git_odb_read(git_rawobj *out, git_odb *db, const git_oid *id) assert(out && db && id); for (i = 0; i < db->backends.length && error < 0; ++i) { - git_odb_backend *b = git_vector_get(&db->backends, i); + backend_internal *internal = git_vector_get(&db->backends, i); + git_odb_backend *b = internal->backend; if (b->read != NULL) error = b->read(out, b, id); @@ -292,7 +380,12 @@ int git_odb_write(git_oid *id, git_odb *db, git_rawobj *obj) assert(obj && db && id); for (i = 0; i < db->backends.length && error < 0; ++i) { - git_odb_backend *b = git_vector_get(&db->backends, i); + backend_internal *internal = git_vector_get(&db->backends, i); + git_odb_backend *b = internal->backend; + + /* we don't write in alternates! */ + if (internal->is_alternate) + continue; if (b->write != NULL) error = b->write(id, b, obj); diff --git a/vendor/libgit2/src/odb.h b/vendor/libgit2/src/odb.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/odb_loose.c b/vendor/libgit2/src/odb_loose.c old mode 100755 new mode 100644 index f89eb71ff..4e2d9a639 --- a/vendor/libgit2/src/odb_loose.c +++ b/vendor/libgit2/src/odb_loose.c @@ -528,7 +528,7 @@ static int write_obj(gitfo_buf *buf, git_oid *id, loose_backend *backend) gitfo_close(fd); gitfo_chmod(temp, 0444); - if (gitfo_move_file(temp, file) < 0) { + if (gitfo_mv(temp, file) < 0) { gitfo_unlink(temp); return GIT_EOSERR; } @@ -653,8 +653,6 @@ int git_odb_backend_loose(git_odb_backend **backend_out, const char *objects_dir backend->parent.exists = &loose_backend__exists; backend->parent.free = &loose_backend__free; - backend->parent.priority = 2; /* higher than packfiles */ - *backend_out = (git_odb_backend *)backend; return GIT_SUCCESS; } diff --git a/vendor/libgit2/src/odb_pack.c b/vendor/libgit2/src/odb_pack.c old mode 100755 new mode 100644 index 6141c57ef..664b00139 --- a/vendor/libgit2/src/odb_pack.c +++ b/vendor/libgit2/src/odb_pack.c @@ -1203,8 +1203,6 @@ int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir) backend->parent.exists = &pack_backend__exists; backend->parent.free = &pack_backend__free; - backend->parent.priority = 1; - *backend_out = (git_odb_backend *)backend; return GIT_SUCCESS; } diff --git a/vendor/libgit2/src/oid.c b/vendor/libgit2/src/oid.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/ppc/sha1.c b/vendor/libgit2/src/ppc/sha1.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/ppc/sha1.h b/vendor/libgit2/src/ppc/sha1.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/ppc/sha1ppc.S b/vendor/libgit2/src/ppc/sha1ppc.S old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/refs.c b/vendor/libgit2/src/refs.c old mode 100755 new mode 100644 index eca50ddaa..542401c2f --- a/vendor/libgit2/src/refs.c +++ b/vendor/libgit2/src/refs.c @@ -28,39 +28,64 @@ #include "repository.h" #include "fileops.h" -#define HASH_SEED 2147483647 -#define MAX_NESTING_LEVEL 5 - -static const int default_table_size = 32; - -static uint32_t reftable_hash(const void *key) -{ - return git__hash(key, strlen((const char *)key), HASH_SEED); -} +#include +#include -static int reftable_haskey(void *reference, const void *key) -{ - git_reference *ref; - char *name; +#define MAX_NESTING_LEVEL 5 - ref = (git_reference *)reference; - name = (char *)key; +typedef struct { + git_reference ref; + git_oid oid; + git_oid peel_target; +} reference_oid; - return strcmp(name, ref->name) == 0; -} +typedef struct { + git_reference ref; + char *target; +} reference_symbolic; +static const int default_table_size = 32; -static int check_refname(const char *name) +static uint32_t reftable_hash(const void *key, int hash_id) { - /* - * TODO: To be implemented - * Check if the given name is a valid name - * for a reference - */ - - return name ? GIT_SUCCESS : GIT_ERROR; + static uint32_t hash_seeds[GIT_HASHTABLE_HASHES] = { + 2147483647, + 0x5d20bb23, + 0x7daaab3c + }; + + return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]); } +static void reference_free(git_reference *reference); +static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type); + +/* loose refs */ +static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content); +static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content); +static int loose_read(gitfo_buf *file_content, const char *name, const char *repo_path); +static int loose_lookup( git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic); +static int loose_write(git_reference *ref); + +/* packed refs */ +static int packed_readpack(gitfo_buf *packfile, const char *repo_path); +static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end); +static int packed_parse_oid(reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end); +static int packed_load(git_repository *repo); +static int packed_loadloose(git_repository *repository); +static int packed_write_ref(reference_oid *ref, git_filebuf *file); +static int packed_find_peel(reference_oid *ref); +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); + +/* name normalization */ +static int check_valid_ref_char(char ch); +static int normalize_name(char *buffer_out, const char *name, int is_oid_ref); + +/***************************************** + * Internal methods - Constructor/destructor + *****************************************/ static void reference_free(git_reference *reference) { if (reference == NULL) @@ -70,36 +95,72 @@ static void reference_free(git_reference *reference) free(reference->name); if (reference->type == GIT_REF_SYMBOLIC) - free(reference->target.ref); + free(((reference_symbolic *)reference)->target); free(reference); } -int git_reference_new(git_reference **ref_out, git_repository *repo) +static int reference_create( + git_reference **ref_out, + git_repository *repo, + const char *name, + git_rtype type) { + char normalized[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + int error = GIT_SUCCESS, size; git_reference *reference = NULL; - assert(ref_out && repo); + assert(ref_out && repo && name); + + if (type == GIT_REF_SYMBOLIC) + size = sizeof(reference_symbolic); + else if (type == GIT_REF_OID) + size = sizeof(reference_oid); + else + return GIT_EINVALIDREFSTATE; - reference = git__malloc(sizeof(git_reference)); + reference = git__malloc(size); if (reference == NULL) return GIT_ENOMEM; - memset(reference, 0x0, sizeof(git_reference)); - reference->type = GIT_REF_INVALID; + memset(reference, 0x0, size); reference->owner = repo; + reference->type = type; + + error = normalize_name(normalized, name, (type & GIT_REF_OID)); + if (error < GIT_SUCCESS) + goto cleanup; + + reference->name = git__strdup(normalized); + if (reference->name == NULL) { + error = GIT_ENOMEM; + goto cleanup; + } *ref_out = reference; - return GIT_SUCCESS; + + return error; + +cleanup: + reference_free(reference); + return error; } -static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content) + + + +/***************************************** + * Internal methods - Loose references + *****************************************/ +static int loose_parse_symbolic(git_reference *ref, gitfo_buf *file_content) { const unsigned int header_len = strlen(GIT_SYMREF); const char *refname_start; char *eol; + reference_symbolic *ref_sym; refname_start = (const char *)file_content->data; + ref_sym = (reference_symbolic *)ref; if (file_content->len < (header_len + 1)) return GIT_EREFCORRUPTED; @@ -111,12 +172,12 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content) refname_start += header_len; - ref->target.ref = git__strdup(refname_start); - if (ref->target.ref == NULL) + ref_sym->target = git__strdup(refname_start); + if (ref_sym->target == NULL) return GIT_ENOMEM; /* remove newline at the end of file */ - eol = strchr(ref->target.ref, '\n'); + eol = strchr(ref_sym->target, '\n'); if (eol == NULL) return GIT_EREFCORRUPTED; @@ -124,22 +185,22 @@ static int parse_sym_ref(git_reference *ref, gitfo_buf *file_content) if (eol[-1] == '\r') eol[-1] = '\0'; - ref->type = GIT_REF_SYMBOLIC; - return GIT_SUCCESS; } -static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content) +static int loose_parse_oid(git_reference *ref, gitfo_buf *file_content) { + reference_oid *ref_oid; char *buffer; buffer = (char *)file_content->data; + ref_oid = (reference_oid *)ref; /* File format: 40 chars (OID) + newline */ if (file_content->len < GIT_OID_HEXSZ + 1) return GIT_EREFCORRUPTED; - if (git_oid_mkstr(&ref->target.oid, buffer) < GIT_SUCCESS) + if (git_oid_mkstr(&ref_oid->oid, buffer) < GIT_SUCCESS) return GIT_EREFCORRUPTED; buffer = buffer + GIT_OID_HEXSZ; @@ -149,18 +210,16 @@ static int parse_oid_ref(git_reference *ref, gitfo_buf *file_content) if (*buffer != '\n') return GIT_EREFCORRUPTED; - ref->type = GIT_REF_OID; return GIT_SUCCESS; } -static int read_loose_ref(gitfo_buf *file_content, const char *name, const char *repo_path) +static int loose_read(gitfo_buf *file_content, const char *name, const char *repo_path) { int error = GIT_SUCCESS; char ref_path[GIT_PATH_MAX]; /* Determine the full path of the ref */ - strcpy(ref_path, repo_path); - strcat(ref_path, name); + git__joinpath(ref_path, repo_path, name); /* Does it even exist ? */ if (gitfo_exists(ref_path) < GIT_SUCCESS) @@ -176,10 +235,11 @@ static int read_loose_ref(gitfo_buf *file_content, const char *name, const char return error; } -static int lookup_loose_ref( +static int loose_lookup( git_reference **ref_out, git_repository *repo, - const char *name) + const char *name, + int skip_symbolic) { int error = GIT_SUCCESS; gitfo_buf ref_file = GITFO_BUF_INIT; @@ -187,29 +247,27 @@ static int lookup_loose_ref( *ref_out = NULL; - error = read_loose_ref(&ref_file, name, repo->path_repository); + error = loose_read(&ref_file, name, repo->path_repository); if (error < GIT_SUCCESS) goto cleanup; - error = git_reference_new(&ref, repo); - if (error < GIT_SUCCESS) - goto cleanup; + if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) { + if (skip_symbolic) + return GIT_SUCCESS; - ref->name = git__strdup(name); - if (ref->name == NULL) { - error = GIT_ENOMEM; - goto cleanup; - } + error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC); + if (error < GIT_SUCCESS) + goto cleanup; - if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) - error = parse_sym_ref(ref, &ref_file); - else - error = parse_oid_ref(ref, &ref_file); + error = loose_parse_symbolic(ref, &ref_file); + } else { + error = reference_create(&ref, repo, name, GIT_REF_OID); + if (error < GIT_SUCCESS) + goto cleanup; - if (error < GIT_SUCCESS) - goto cleanup; + error = loose_parse_oid(ref, &ref_file); + } - error = git_hashtable_insert(repo->references.cache, ref->name, ref); if (error < GIT_SUCCESS) goto cleanup; @@ -222,14 +280,80 @@ static int lookup_loose_ref( return error; } +static int loose_write(git_reference *ref) +{ + git_filebuf file; + char ref_path[GIT_PATH_MAX]; + int error, contents_size; + char *ref_contents = NULL; + + assert((ref->type & GIT_REF_PACKED) == 0); + + git__joinpath(ref_path, ref->owner->path_repository, ref->name); + + if ((error = git_filebuf_open(&file, ref_path, 0)) < GIT_SUCCESS) + return error; + + if (ref->type & GIT_REF_OID) { + reference_oid *ref_oid = (reference_oid *)ref; + + contents_size = GIT_OID_HEXSZ + 1; + ref_contents = git__malloc(contents_size); + if (ref_contents == NULL) { + error = GIT_ENOMEM; + goto unlock; + } + + git_oid_fmt(ref_contents, &ref_oid->oid); + + } else if (ref->type & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */ + reference_symbolic *ref_sym = (reference_symbolic *)ref; + + contents_size = strlen(GIT_SYMREF) + strlen(ref_sym->target) + 1; + ref_contents = git__malloc(contents_size); + if (ref_contents == NULL) { + error = GIT_ENOMEM; + goto unlock; + } + + strcpy(ref_contents, GIT_SYMREF); + strcat(ref_contents, ref_sym->target); + } else { + error = GIT_EINVALIDREFSTATE; + goto unlock; + } + + /* TODO: win32 carriage return when writing references in Windows? */ + ref_contents[contents_size - 1] = '\n'; + + if ((error = git_filebuf_write(&file, ref_contents, contents_size)) < GIT_SUCCESS) + goto unlock; + + error = git_filebuf_commit(&file); + + free(ref_contents); + return error; + +unlock: + git_filebuf_cleanup(&file); + free(ref_contents); + return error; +} + + + -static int read_packed_refs(gitfo_buf *packfile, const char *repo_path) + + +/***************************************** + * Internal methods - Packed references + *****************************************/ +static int packed_readpack(gitfo_buf *packfile, const char *repo_path) { char ref_path[GIT_PATH_MAX]; /* Determine the full path of the file */ - strcpy(ref_path, repo_path); - strcat(ref_path, GIT_PACKEDREFS_FILE); + git__joinpath(ref_path, repo_path, GIT_PACKEDREFS_FILE); /* Does it even exist ? */ if (gitfo_exists(ref_path) < GIT_SUCCESS) @@ -238,13 +362,11 @@ static int read_packed_refs(gitfo_buf *packfile, const char *repo_path) return gitfo_read_file(packfile, ref_path); } -static int parse_packed_line_peel( - git_reference **ref_out, - const git_reference *tag_ref, +static int packed_parse_peel( + reference_oid *tag_ref, const char **buffer_out, const char *buffer_end) { - git_oid oid; const char *buffer = *buffer_out + 1; assert(buffer[-1] == '^'); @@ -254,14 +376,14 @@ static int parse_packed_line_peel( return GIT_EPACKEDREFSCORRUPTED; /* Ensure reference is a tag */ - if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0) + if (git__prefixcmp(tag_ref->ref.name, GIT_REFS_TAGS_DIR) != 0) return GIT_EPACKEDREFSCORRUPTED; if (buffer + GIT_OID_HEXSZ >= buffer_end) return GIT_EPACKEDREFSCORRUPTED; /* Is this a valid object id? */ - if (git_oid_mkstr(&oid, buffer) < GIT_SUCCESS) + if (git_oid_mkstr(&tag_ref->peel_target, buffer) < GIT_SUCCESS) return GIT_EPACKEDREFSCORRUPTED; buffer = buffer + GIT_OID_HEXSZ; @@ -272,34 +394,26 @@ static int parse_packed_line_peel( return GIT_EPACKEDREFSCORRUPTED; *buffer_out = buffer + 1; + tag_ref->ref.type |= GIT_REF_HAS_PEEL; - /* - * TODO: do we need the packed line? - * Right now we don't, so we don't create a new - * reference. - */ - - *ref_out = NULL; return GIT_SUCCESS; } -static int parse_packed_line( - git_reference **ref_out, +static int packed_parse_oid( + reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end) { - git_reference *ref; + reference_oid *ref; const char *buffer = *buffer_out; const char *refname_begin, *refname_end; int error = GIT_SUCCESS; int refname_len; - - error = git_reference_new(&ref, repo); - if (error < GIT_SUCCESS) - goto cleanup; + char refname[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + git_oid id; refname_begin = (buffer + GIT_OID_HEXSZ + 1); if (refname_begin >= buffer_end || @@ -309,7 +423,7 @@ static int parse_packed_line( } /* Is this a valid object id? */ - if ((error = git_oid_mkstr(&ref->target.oid, buffer)) < GIT_SUCCESS) + if ((error = git_oid_mkstr(&id, buffer)) < GIT_SUCCESS) goto cleanup; refname_end = memchr(refname_begin, '\n', buffer_end - refname_begin); @@ -320,20 +434,18 @@ static int parse_packed_line( refname_len = refname_end - refname_begin; - ref->name = git__malloc(refname_len + 1); - if (ref->name == NULL) { - error = GIT_ENOMEM; - goto cleanup; - } + memcpy(refname, refname_begin, refname_len); + refname[refname_len] = 0; - memcpy(ref->name, refname_begin, refname_len); - ref->name[refname_len] = 0; + if (refname[refname_len - 1] == '\r') + refname[refname_len - 1] = 0; - if (ref->name[refname_len - 1] == '\r') - ref->name[refname_len - 1] = 0; + error = reference_create((git_reference **)&ref, repo, refname, GIT_REF_OID); + if (error < GIT_SUCCESS) + goto cleanup; - ref->type = GIT_REF_OID; - ref->packed = 1; + git_oid_cpy(&ref->oid, &id); + ref->ref.type |= GIT_REF_PACKED; *ref_out = ref; *buffer_out = refname_end + 1; @@ -341,17 +453,36 @@ static int parse_packed_line( return GIT_SUCCESS; cleanup: - reference_free(ref); + reference_free((git_reference *)ref); return error; } -static int parse_packed_refs(git_refcache *ref_cache, git_repository *repo) +static int packed_load(git_repository *repo) { int error = GIT_SUCCESS; gitfo_buf packfile = GITFO_BUF_INIT; const char *buffer_start, *buffer_end; + git_refcache *ref_cache = &repo->references; + + /* already loaded */ + if (repo->references.packfile != NULL) + return GIT_SUCCESS; + + repo->references.packfile = git_hashtable_alloc( + default_table_size, + reftable_hash, + (git_hash_keyeq_ptr)strcmp); + + if (repo->references.packfile == NULL) + return GIT_ENOMEM; + + /* read the packfile from disk */ + error = packed_readpack(&packfile, repo->path_repository); + + /* there is no packfile on disk; that's ok */ + if (error == GIT_ENOTFOUND) + return GIT_SUCCESS; - error = read_packed_refs(&packfile, repo->path_repository); if (error < GIT_SUCCESS) goto cleanup; @@ -376,296 +507,936 @@ static int parse_packed_refs(git_refcache *ref_cache, git_repository *repo) buffer_start++; while (buffer_start < buffer_end) { + reference_oid *ref = NULL; - git_reference *ref = NULL; - git_reference *ref_tag = NULL; - - error = parse_packed_line(&ref, repo, &buffer_start, buffer_end); + error = packed_parse_oid(&ref, repo, &buffer_start, buffer_end); if (error < GIT_SUCCESS) goto cleanup; if (buffer_start[0] == '^') { - error = parse_packed_line_peel(&ref_tag, ref, &buffer_start, buffer_end); + error = packed_parse_peel(ref, &buffer_start, buffer_end); if (error < GIT_SUCCESS) goto cleanup; } - /* - * If a loose reference exists with the same name, - * we assume that the loose reference is more up-to-date. - * We don't need to cache this ref from the packfile. - */ - if (read_loose_ref(NULL, ref->name, repo->path_repository) == GIT_SUCCESS) { - reference_free(ref); - reference_free(ref_tag); - continue; - } - - error = git_hashtable_insert(ref_cache->cache, ref->name, ref); + error = git_hashtable_insert(ref_cache->packfile, ref->ref.name, ref); if (error < GIT_SUCCESS) { - reference_free(ref); - reference_free(ref_tag); + reference_free((git_reference *)ref); goto cleanup; } } - ref_cache->pack_loaded = 1; - cleanup: gitfo_free_buf(&packfile); return error; } -void git_reference_set_oid(git_reference *ref, const git_oid *id) +static int _dirent_loose_load(void *data, char *full_path) { - if (ref->type == GIT_REF_SYMBOLIC) - free(ref->target.ref); + git_repository *repository = (git_repository *)data; + git_reference *reference, *old_ref; + char *file_path; + int error; - git_oid_cpy(&ref->target.oid, id); - ref->type = GIT_REF_OID; + if (gitfo_isdir(full_path) == GIT_SUCCESS) + return gitfo_dirent(full_path, GIT_PATH_MAX, _dirent_loose_load, repository); - ref->modified = 1; -} + file_path = full_path + strlen(repository->path_repository); + error = loose_lookup(&reference, repository, file_path, 1); + if (error == GIT_SUCCESS && reference != NULL) { + reference->type |= GIT_REF_PACKED; -void git_reference_set_target(git_reference *ref, const char *target) -{ - if (ref->type == GIT_REF_SYMBOLIC) - free(ref->target.ref); + if (git_hashtable_insert2(repository->references.packfile, reference->name, reference, (void **)&old_ref) < GIT_SUCCESS) { + reference_free(reference); + return GIT_ENOMEM; + } - ref->target.ref = git__strdup(target); - ref->type = GIT_REF_SYMBOLIC; + if (old_ref != NULL) + reference_free(old_ref); + } - ref->modified = 1; + return error; } -void git_reference_set_name(git_reference *ref, const char *name) +/* + * Load all the loose references from the repository + * into the in-memory Packfile, and build a vector with + * all the references so it can be written back to + * disk. + */ +static int packed_loadloose(git_repository *repository) { - if (ref->name != NULL) { - git_hashtable_remove(ref->owner->references.cache, ref->name); - free(ref->name); + char refs_path[GIT_PATH_MAX]; + + /* the packfile must have been previously loaded! */ + assert(repository->references.packfile); + + git__joinpath(refs_path, repository->path_repository, GIT_REFS_DIR); + + /* Remove any loose references from the cache */ + { + const void *_unused; + git_reference *reference; + + GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference, + reference_free(reference); + ); } - ref->name = git__strdup(name); - git_hashtable_insert(ref->owner->references.cache, ref->name, ref); + git_hashtable_clear(repository->references.loose_cache); - ref->modified = 1; + /* + * Load all the loose files from disk into the Packfile table. + * This will overwrite any old packed entries with their + * updated loose versions + */ + return gitfo_dirent(refs_path, GIT_PATH_MAX, _dirent_loose_load, repository); } -const git_oid *git_reference_oid(git_reference *ref) +/* + * Write a single reference into a packfile + */ +static int packed_write_ref(reference_oid *ref, git_filebuf *file) { - assert(ref); + int error; + char oid[GIT_OID_HEXSZ + 1]; - if (ref->type != GIT_REF_OID) - return NULL; + git_oid_fmt(oid, &ref->oid); + oid[GIT_OID_HEXSZ] = 0; + + /* + * For references that peel to an object in the repo, we must + * write the resulting peel on a separate line, e.g. + * + * 6fa8a902cc1d18527e1355773c86721945475d37 refs/tags/libgit2-0.4 + * ^2ec0cb7959b0bf965d54f95453f5b4b34e8d3100 + * + * This obviously only applies to tags. + * The required peels have already been loaded into `ref->peel_target`. + */ + if (ref->ref.type & GIT_REF_HAS_PEEL) { + char peel[GIT_OID_HEXSZ + 1]; + git_oid_fmt(peel, &ref->peel_target); + peel[GIT_OID_HEXSZ] = 0; + + error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->ref.name, peel); + } else { + error = git_filebuf_printf(file, "%s %s\n", oid, ref->ref.name); + } - return &ref->target.oid; + return error; } -const char *git_reference_target(git_reference *ref) +/* + * Find out what object this reference resolves to. + * + * For references that point to a 'big' tag (e.g. an + * actual tag object on the repository), we need to + * cache on the packfile the OID of the object to + * which that 'big tag' is pointing to. + */ +static int packed_find_peel(reference_oid *ref) { - if (ref->type != GIT_REF_SYMBOLIC) - return NULL; + git_tag *tag; + const git_object *peeled_target; + int error; - return ref->target.ref; -} + if (ref->ref.type & GIT_REF_HAS_PEEL) + return GIT_SUCCESS; -git_rtype git_reference_type(git_reference *ref) -{ - assert(ref); - return ref->type; -} + /* + * Only applies to tags, i.e. references + * in the /refs/tags folder + */ + if (git__prefixcmp(ref->ref.name, GIT_REFS_TAGS_DIR) != 0) + return GIT_SUCCESS; -const char *git_reference_name(git_reference *ref) -{ - assert(ref); - return ref->name; -} + /* + * Find the tag in the repository. The tag must exist, + * otherwise this reference is broken and we shouldn't + * pack it. + */ + error = git_tag_lookup(&tag, ref->ref.owner, &ref->oid); + if (error < GIT_SUCCESS) + return GIT_EOBJCORRUPTED; -git_repository *git_reference_owner(git_reference *ref) -{ - assert(ref); - return ref->owner; + /* + * Find the object pointed at by this tag + */ + peeled_target = git_tag_target(tag); + if (peeled_target == NULL) + return GIT_EOBJCORRUPTED; + + git_oid_cpy(&ref->peel_target, git_object_id(peeled_target)); + 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 + */ + + return GIT_SUCCESS; } -int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) +/* + * Remove all loose references + * + * Once we have successfully written a packfile, + * all the loose references that were packed must be + * removed from disk. + * + * This is a dangerous method; make sure the packfile + * is well-written, because we are destructing references + * here otherwise. + */ +static int packed_remove_loose(git_repository *repo, git_vector *packing_list) { - git_repository *repo; - int error, i; + unsigned int i; + char full_path[GIT_PATH_MAX]; + int error = GIT_SUCCESS; + git_reference *reference; - assert(resolved_ref && ref); - *resolved_ref = NULL; - - repo = ref->owner; + for (i = 0; i < packing_list->length; ++i) { + git_reference *ref = git_vector_get(packing_list, i); - for (i = 0; i < MAX_NESTING_LEVEL; ++i) { + /* Ensure the packed reference doesn't exist + * in a (more up-to-date?) state as a loose reference + */ + reference = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name); + if (reference != NULL) + continue; - if (ref->type == GIT_REF_OID) { - *resolved_ref = ref; - return GIT_SUCCESS; - } + git__joinpath(full_path, repo->path_repository, ref->name); - if ((error = git_repository_lookup_ref(&ref, repo, ref->target.ref)) < GIT_SUCCESS) - return error; + if (gitfo_exists(full_path) == GIT_SUCCESS && + gitfo_unlink(full_path) < GIT_SUCCESS) + error = GIT_EOSERR; + + /* + * if we fail to remove a single file, this is *not* good, + * but we should keep going and remove as many as possible. + * After we've removed as many files as possible, we return + * the error code anyway. + * + * TODO: mark this with a very special error code? + * GIT_EFAILTORMLOOSE + */ } - return GIT_ETOONESTEDSYMREF; + return error; } -int git_reference_write(git_reference *ref) +static int packed_sort(const void *a, const void *b) { - git_filelock lock; - char ref_path[GIT_PATH_MAX]; - int error, contents_size; - char *ref_contents = NULL; + const git_reference *ref_a = *(const git_reference **)a; + const git_reference *ref_b = *(const git_reference **)b; - if (ref->type == GIT_REF_INVALID || - ref->name == NULL) - return GIT_EMISSINGOBJDATA; + return strcmp(ref_a->name, ref_b->name); +} - if (ref->modified == 0) - return GIT_SUCCESS; +/* + * Write all the contents in the in-memory packfile to disk. + */ +static int packed_write(git_repository *repo) +{ + git_filebuf pack_file; + int error; + unsigned int i; + char pack_file_path[GIT_PATH_MAX]; - if ((error = check_refname(ref->name)) < GIT_SUCCESS) - return error; + git_vector packing_list; + size_t total_refs; - strcpy(ref_path, ref->owner->path_repository); - strcat(ref_path, ref->name); + assert(repo && repo->references.packfile); - if ((error = git_filelock_init(&lock, ref_path)) < GIT_SUCCESS) - goto error_cleanup; + total_refs = repo->references.packfile->key_count; + if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS) + return error; - if ((error = git_filelock_lock(&lock, 0)) < GIT_SUCCESS) - goto error_cleanup; + /* Load all the packfile into a vector */ + { + git_reference *reference; + const void *_unused; - if (ref->type == GIT_REF_OID) { + GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference, + git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */ + ); + } - contents_size = GIT_OID_HEXSZ + 1; - ref_contents = git__malloc(contents_size); - if (ref_contents == NULL) { - error = GIT_ENOMEM; - goto error_cleanup; - } + /* sort the vector so the entries appear sorted on the packfile */ + git_vector_sort(&packing_list); - git_oid_fmt(ref_contents, &ref->target.oid); - ref_contents[contents_size - 1] = '\n'; + /* Now we can open the file! */ + git__joinpath(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE); + if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS) + return error; - } else { /* GIT_REF_SYMBOLIC */ + /* Packfiles have a header! */ + if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS) + return error; - contents_size = strlen(GIT_SYMREF) + strlen(ref->target.ref) + 1; - ref_contents = git__malloc(contents_size); - if (ref_contents == NULL) { - error = GIT_ENOMEM; - goto error_cleanup; - } + for (i = 0; i < packing_list.length; ++i) { + reference_oid *ref = (reference_oid *)git_vector_get(&packing_list, i); - strcpy(ref_contents, GIT_SYMREF); - strcat(ref_contents, ref->target.ref); - ref_contents[contents_size - 1] = '\n'; - } + /* only direct references go to the packfile; otherwise + * this is a disaster */ + assert(ref->ref.type & GIT_REF_OID); - if ((error = git_filelock_write(&lock, ref_contents, contents_size)) < GIT_SUCCESS) - goto error_cleanup; + if ((error = packed_find_peel(ref)) < GIT_SUCCESS) + goto cleanup; - if ((error = git_filelock_commit(&lock)) < GIT_SUCCESS) - goto error_cleanup; + if ((error = packed_write_ref(ref, &pack_file)) < GIT_SUCCESS) + goto cleanup; + } - ref->modified = 0; +cleanup: + /* if we've written all the references properly, we can commit + * the packfile to make the changes effective */ + if (error == GIT_SUCCESS) { + error = git_filebuf_commit(&pack_file); + + /* when and only when the packfile has been properly written, + * we can go ahead and remove the loose refs */ + if (error == GIT_SUCCESS) + error = packed_remove_loose(repo, &packing_list); + } + else git_filebuf_cleanup(&pack_file); - free(ref_contents); - return GIT_SUCCESS; + git_vector_free(&packing_list); -error_cleanup: - free(ref_contents); - git_filelock_unlock(&lock); return error; } -int git_repository_lookup_ref(git_reference **ref_out, git_repository *repo, const char *name) + + + +/***************************************** + * External Library API + *****************************************/ + +/** + * Constructors + */ +int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name) { int error; + char normalized_name[GIT_PATH_MAX]; assert(ref_out && repo && name); *ref_out = NULL; - error = check_refname(name); + error = normalize_name(normalized_name, name, 0); if (error < GIT_SUCCESS) return error; - /* - * First, check if the reference is on the local cache; - * references on the cache are assured to be up-to-date - */ - *ref_out = git_hashtable_lookup(repo->references.cache, name); + /* First, check has been previously loaded and cached */ + *ref_out = git_hashtable_lookup(repo->references.loose_cache, normalized_name); if (*ref_out != NULL) return GIT_SUCCESS; - /* - * Then check if there is a loose file for that reference. - * If the file exists, we parse it and store it on the - * cache. - */ - error = lookup_loose_ref(ref_out, repo, name); + /* Then check if there is a loose file for that reference.*/ + error = loose_lookup(ref_out, repo, normalized_name, 0); + /* If the file exists, we store it on the cache */ if (error == GIT_SUCCESS) - return GIT_SUCCESS; + return git_hashtable_insert(repo->references.loose_cache, (*ref_out)->name, (*ref_out)); + /* The loose lookup has failed, but not because the reference wasn't found; + * probably the loose reference is corrupted. this is bad. */ if (error != GIT_ENOTFOUND) return error; /* - * Check if we have loaded the packed references. - * If the packed references have been loaded, they would be - * stored already on the cache: that means that the ref - * we are looking for doesn't exist. - * - * If they haven't been loaded yet, we load the packfile - * and check if our reference is inside of it. + * If we cannot find a loose reference, we look into the packfile + * Load the packfile first if it hasn't been loaded */ - if (!repo->references.pack_loaded) { - + if (!repo->references.packfile) { /* load all the packed references */ - error = parse_packed_refs(&repo->references, repo); + error = packed_load(repo); if (error < GIT_SUCCESS) return error; - - /* check the cache again -- hopefully the reference will be there */ - *ref_out = git_hashtable_lookup(repo->references.cache, name); - if (*ref_out != NULL) - return GIT_SUCCESS; } + /* Look up on the packfile */ + *ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name); + if (*ref_out != NULL) + return GIT_SUCCESS; + /* The reference doesn't exist anywhere */ return GIT_ENOTFOUND; } +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; + +cleanup: + reference_free(ref); + return error; +} + +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; +} + + +/** + * Getters + */ +git_rtype git_reference_type(git_reference *ref) +{ + assert(ref); + + if (ref->type & GIT_REF_OID) + return GIT_REF_OID; + + if (ref->type & GIT_REF_SYMBOLIC) + return GIT_REF_SYMBOLIC; + + return GIT_REF_INVALID; +} + +const char *git_reference_name(git_reference *ref) +{ + assert(ref); + return ref->name; +} + +git_repository *git_reference_owner(git_reference *ref) +{ + assert(ref); + return ref->owner; +} + +const git_oid *git_reference_oid(git_reference *ref) +{ + assert(ref); + + if ((ref->type & GIT_REF_OID) == 0) + return NULL; + + return &((reference_oid *)ref)->oid; +} + +const char *git_reference_target(git_reference *ref) +{ + assert(ref); + + if ((ref->type & GIT_REF_SYMBOLIC) == 0) + return NULL; + + return ((reference_symbolic *)ref)->target; +} + +/** + * Setters + */ + +/* + * Change the OID target of a reference. + * + * For loose references, just change the oid in memory + * and overwrite the file in disk. + * + * For packed files, this is not pretty: + * For performance reasons, we write the new reference + * loose on disk (it replaces the old on the packfile), + * but we cannot invalidate the pointer to the reference, + * and most importantly, the `packfile` object must stay + * consistent with the representation of the packfile + * on disk. This is what we need to: + * + * 1. Copy the reference + * 2. Change the oid on the original + * 3. Write the original to disk + * 4. Write the original to the loose cache + * 5. Replace the original with the copy (old reference) in the packfile cache + */ +int git_reference_set_oid(git_reference *ref, const git_oid *id) +{ + reference_oid *ref_oid; + reference_oid *ref_old = NULL; + int error = GIT_SUCCESS; + + if ((ref->type & GIT_REF_OID) == 0) + return GIT_EINVALIDREFSTATE; + + ref_oid = (reference_oid *)ref; + + /* duplicate the reference; + * this copy will stay on the packfile cache */ + if (ref->type & GIT_REF_PACKED) { + ref_old = git__malloc(sizeof(reference_oid)); + if (ref_old == NULL) + return GIT_ENOMEM; + + ref_old->ref.name = git__strdup(ref->name); + if (ref_old->ref.name == NULL) { + free(ref_old); + return GIT_ENOMEM; + } + } + + git_oid_cpy(&ref_oid->oid, id); + ref->type &= ~GIT_REF_HAS_PEEL; + + error = loose_write(ref); + if (error < GIT_SUCCESS) + goto cleanup; + + if (ref->type & GIT_REF_PACKED) { + /* insert the original on the loose cache */ + error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref); + if (error < GIT_SUCCESS) + goto cleanup; + + ref->type &= ~GIT_REF_PACKED; + + /* replace the original in the packfile with the copy */ + error = git_hashtable_insert(ref->owner->references.packfile, ref_old->ref.name, ref_old); + if (error < GIT_SUCCESS) + goto cleanup; + } + + return GIT_SUCCESS; + +cleanup: + reference_free((git_reference *)ref_old); + return error; +} + +/* + * Change the target of a symbolic reference. + * + * This is easy because symrefs cannot be inside + * a pack. We just change the target in memory + * and overwrite the file on disk. + */ +int git_reference_set_target(git_reference *ref, const char *target) +{ + reference_symbolic *ref_sym; + + if ((ref->type & GIT_REF_SYMBOLIC) == 0) + return GIT_EINVALIDREFSTATE; + + ref_sym = (reference_symbolic *)ref; + + free(ref_sym->target); + ref_sym->target = git__strdup(target); + if (ref_sym->target == NULL) + return GIT_ENOMEM; + + return loose_write(ref); +} + +/** + * Other + */ + +/* + * Delete a reference. + * + * If the reference is packed, this is an expensive + * operation. We need to remove the reference from + * the memory cache and then rewrite the whole pack + * + * If the reference is loose, we remove it on + * the filesystem and update the in-memory cache + * accordingly. We also make sure that an older version + * of it doesn't exist as a packed reference. If this + * is the case, this packed reference is removed as well. + * + * This obviously invalidates the `ref` pointer. + */ +int git_reference_delete(git_reference *ref) +{ + int error; + git_reference *reference; + + assert(ref); + + if (ref->type & GIT_REF_PACKED) { + git_hashtable_remove(ref->owner->references.packfile, ref->name); + error = packed_write(ref->owner); + } else { + char full_path[GIT_PATH_MAX]; + git__joinpath(full_path, ref->owner->path_repository, ref->name); + git_hashtable_remove(ref->owner->references.loose_cache, ref->name); + error = gitfo_unlink(full_path); + if (error < GIT_SUCCESS) + goto cleanup; + + /* When deleting a loose reference, we have to ensure that an older + * packed version of it doesn't exist + */ + if (!git_reference_lookup(&reference, ref->owner, ref->name)) { + assert((reference->type & GIT_REF_PACKED) != 0); + error = git_reference_delete(reference); + } + } + +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. + */ +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 error; +} + +int git_reference_resolve(git_reference **resolved_ref, git_reference *ref) +{ + git_repository *repo; + int error, i; + + assert(resolved_ref && ref); + *resolved_ref = NULL; + + repo = ref->owner; + + for (i = 0; i < MAX_NESTING_LEVEL; ++i) { + reference_symbolic *ref_sym; + + if (ref->type & GIT_REF_OID) { + *resolved_ref = ref; + return GIT_SUCCESS; + } + + ref_sym = (reference_symbolic *)ref; + if ((error = git_reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS) + return error; + } + + return GIT_ETOONESTEDSYMREF; +} + +int git_reference_packall(git_repository *repo) +{ + int error; + + /* load the existing packfile */ + if ((error = packed_load(repo)) < GIT_SUCCESS) + return error; + + /* update it in-memory with all the loose references */ + if ((error = packed_loadloose(repo)) < GIT_SUCCESS) + return error; + + /* write it back to disk */ + return packed_write(repo); +} + + + + + +/***************************************** + * Init/free (repository API) + *****************************************/ int git_repository__refcache_init(git_refcache *refs) { assert(refs); - refs->cache = git_hashtable_alloc( - default_table_size, + refs->loose_cache = git_hashtable_alloc( + default_table_size, reftable_hash, - reftable_haskey); + (git_hash_keyeq_ptr)strcmp); - return refs->cache ? GIT_SUCCESS : GIT_ENOMEM; + /* packfile loaded lazily */ + refs->packfile = NULL; + + return (refs->loose_cache) ? GIT_SUCCESS : GIT_ENOMEM; } void git_repository__refcache_free(git_refcache *refs) { - git_hashtable_iterator it; git_reference *reference; + const void *_unused; assert(refs); - git_hashtable_iterator_init(refs->cache, &it); - - while ((reference = (git_reference *)git_hashtable_iterator_next(&it)) != NULL) { - git_hashtable_remove(refs->cache, reference->name); + GIT_HASHTABLE_FOREACH(refs->loose_cache, _unused, reference, reference_free(reference); + ); + + git_hashtable_free(refs->loose_cache); + + if (refs->packfile) { + GIT_HASHTABLE_FOREACH(refs->packfile, _unused, reference, + reference_free(reference); + ); + + git_hashtable_free(refs->packfile); + } +} + + + +/***************************************** + * Name normalization + *****************************************/ +static int check_valid_ref_char(char ch) +{ + if (ch <= ' ') + return GIT_ERROR; + + switch (ch) { + case '~': + case '^': + case ':': + case '\\': + case '?': + case '[': + case '*': + return GIT_ERROR; + break; + + default: + return GIT_SUCCESS; + } +} + +static int normalize_name(char *buffer_out, const char *name, int is_oid_ref) +{ + int error = GIT_SUCCESS; + const char *name_end, *buffer_out_start; + char *current; + int contains_a_slash = 0; + + assert(name && buffer_out); + + buffer_out_start = buffer_out; + current = (char *)name; + name_end = name + strlen(name); + + /* A refname can not be empty */ + if (name_end == name) + return GIT_EINVALIDREFNAME; + + /* A refname can not end with a dot or a slash */ + if (*(name_end - 1) == '.' || *(name_end - 1) == '/') + return GIT_EINVALIDREFNAME; + + while (current < name_end) { + if (check_valid_ref_char(*current)) + return GIT_EINVALIDREFNAME; + + if (buffer_out > buffer_out_start) { + char prev = *(buffer_out - 1); + + /* A refname can not start with a dot nor contain a double dot */ + if (*current == '.' && ((prev == '.') || (prev == '/'))) + return GIT_EINVALIDREFNAME; + + /* '@{' is forbidden within a refname */ + if (*current == '{' && prev == '@') + return GIT_EINVALIDREFNAME; + + /* Prevent multiple slashes from being added to the output */ + if (*current == '/' && prev == '/') { + current++; + continue; + } + } + + if (*current == '/') + contains_a_slash = 1; + + *buffer_out++ = *current++; } - git_hashtable_free(refs->cache); + /* Object id refname have to contain at least one slash */ + if (is_oid_ref && !contains_a_slash) + return GIT_EINVALIDREFNAME; + + /* A refname can not end with ".lock" */ + if (!git__suffixcmp(name, GIT_FILELOCK_EXTENSION)) + return GIT_EINVALIDREFNAME; + + *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))) + return GIT_EINVALIDREFNAME; + + return error; +} + +int git_reference__normalize_name(char *buffer_out, const char *name) +{ + return normalize_name(buffer_out, name, 0); +} + +int git_reference__normalize_name_oid(char *buffer_out, const char *name) +{ + return normalize_name(buffer_out, name, 1); } diff --git a/vendor/libgit2/src/refs.h b/vendor/libgit2/src/refs.h old mode 100755 new mode 100644 index 70196aa95..a542ac0f2 --- a/vendor/libgit2/src/refs.h +++ b/vendor/libgit2/src/refs.h @@ -9,33 +9,32 @@ #define GIT_REFS_DIR "refs/" #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/" #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/" +#define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/" #define GIT_SYMREF "ref: " #define GIT_PACKEDREFS_FILE "packed-refs" #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled " #define MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH 100 +#define GIT_HEAD_FILE "HEAD" +#define GIT_REFS_HEADS_MASTER_FILE GIT_REFS_HEADS_DIR "master" + struct git_reference { git_repository *owner; - git_rtype type; char *name; - - unsigned packed:1, - modified:1; - - union { - char *ref; - git_oid oid; - } target; + unsigned int type; }; typedef struct { - git_hashtable *cache; - unsigned pack_loaded:1; + git_hashtable *packfile; + git_hashtable *loose_cache; } git_refcache; void git_repository__refcache_free(git_refcache *refs); int git_repository__refcache_init(git_refcache *refs); +int git_reference__normalize_name(char *buffer_out, const char *name); +int git_reference__normalize_name_oid(char *buffer_out, const char *name); + #endif diff --git a/vendor/libgit2/src/repository.c b/vendor/libgit2/src/repository.c old mode 100755 new mode 100644 index 81d112568..d3852d3ad --- a/vendor/libgit2/src/repository.c +++ b/vendor/libgit2/src/repository.c @@ -35,14 +35,9 @@ #include "refs.h" -#define GIT_DIR ".git/" -#define GIT_OBJECTS_DIR "objects/" #define GIT_OBJECTS_INFO_DIR GIT_OBJECTS_DIR "info/" #define GIT_OBJECTS_PACK_DIR GIT_OBJECTS_DIR "pack/" -#define GIT_INDEX_FILE "index" -#define GIT_HEAD_FILE "HEAD" - #define GIT_BRANCH_MASTER "master" static const int OBJECT_TABLE_SIZE = 32; @@ -58,28 +53,16 @@ typedef struct { * Callbacks for the ODB cache, implemented * as a hash table */ -uint32_t object_table_hash(const void *key) +uint32_t object_table_hash(const void *key, int hash_id) { uint32_t r; git_oid *id; id = (git_oid *)key; - memcpy(&r, id->id, sizeof(r)); + memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r)); return r; } -int object_table_hashkey(void *object, const void *key) -{ - git_object *obj; - git_oid *oid; - - obj = (git_object *)object; - oid = (git_oid *)key; - - return (git_oid_cmp(oid, &obj->id) == 0); -} - - /* * Git repository open methods * @@ -89,7 +72,8 @@ static int assign_repository_DIRs(git_repository *repo, const char *git_dir, const char *git_object_directory, const char *git_index_file, - const char *git_work_tree) + const char *git_work_tree, + int is_repo_being_created) { char path_aux[GIT_PATH_MAX]; size_t git_dir_path_len; @@ -104,110 +88,101 @@ static int assign_repository_DIRs(git_repository *repo, if (error < GIT_SUCCESS) return error; - if (gitfo_isdir(path_aux) < GIT_SUCCESS) - return GIT_ENOTFOUND; - git_dir_path_len = strlen(path_aux); /* store GIT_DIR */ repo->path_repository = git__strdup(path_aux); + if (repo->path_repository == NULL) + return GIT_ENOMEM; - /* store GIT_OBJECT_DIRECTORY */ + /* path to GIT_OBJECT_DIRECTORY */ if (git_object_directory == NULL) - strcpy(repo->path_repository + git_dir_path_len, GIT_OBJECTS_DIR); + git__joinpath(path_aux, repo->path_repository, GIT_OBJECTS_DIR); else { error = gitfo_prettify_dir_path(path_aux, git_object_directory); if (error < GIT_SUCCESS) return error; } + /* Ensure GIT_OBJECT_DIRECTORY exists */ if (gitfo_isdir(path_aux) < GIT_SUCCESS) return GIT_ENOTFOUND; + /* Store GIT_OBJECT_DIRECTORY */ repo->path_odb = git__strdup(path_aux); + if (repo->path_odb == NULL) + return GIT_ENOMEM; - - /* store GIT_INDEX_FILE */ - if (git_index_file == NULL) - strcpy(repo->path_repository + git_dir_path_len, GIT_INDEX_FILE); - else { - error = gitfo_prettify_file_path(path_aux, git_index_file); - if (error < GIT_SUCCESS) - return error; + if (!is_repo_being_created) { + /* Ensure HEAD file exists */ + git__joinpath(path_aux, repo->path_repository, GIT_HEAD_FILE); + if (gitfo_exists(path_aux) < 0) + return GIT_ENOTAREPO; } - if (gitfo_exists(path_aux) < 0) - return GIT_ENOTFOUND; - - repo->path_index = git__strdup(path_aux); - - - /* store GIT_WORK_TREE */ + /* path to GIT_WORK_TREE */ if (git_work_tree == NULL) repo->is_bare = 1; else { error = gitfo_prettify_dir_path(path_aux, git_work_tree); if (error < GIT_SUCCESS) return error; + + /* Store GIT_WORK_TREE */ repo->path_workdir = git__strdup(path_aux); + if (repo->path_workdir == NULL) + return GIT_ENOMEM; + + /* Path to GIT_INDEX_FILE */ + if (git_index_file == NULL) + git__joinpath(path_aux, repo->path_repository, GIT_INDEX_FILE); + else { + error = gitfo_prettify_file_path(path_aux, git_index_file); + if (error < GIT_SUCCESS) + return error; + } + + if (!is_repo_being_created) { + /* Ensure GIT_INDEX_FILE exists */ + if (gitfo_exists(path_aux) < 0) + return GIT_ENOTAREPO; + } + + /* store GIT_INDEX_FILE */ + repo->path_index = git__strdup(path_aux); + if (repo->path_index == NULL) + return GIT_ENOMEM; } return GIT_SUCCESS; } -static int guess_repository_DIRs(git_repository *repo, const char *repository_path) +static int guess_repository_DIRs(git_repository *repo, const char *repository_path, int is_repo_being_created) { - char path_aux[GIT_PATH_MAX]; - const char *topdir; + char path_odb[GIT_PATH_MAX] = "\0", path_index[GIT_PATH_MAX] = "\0", path_work_tree[GIT_PATH_MAX] = "\0"; + char dir_name[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; - int path_len; int error = GIT_SUCCESS; - error = gitfo_prettify_dir_path(path_aux, repository_path); - if (error < GIT_SUCCESS) - return error; - - if (gitfo_isdir(path_aux) < GIT_SUCCESS) - return GIT_ENOTAREPO; - - path_len = strlen(path_aux); - - repo->path_repository = git__strdup(path_aux); - - /* objects database */ - strcpy(path_aux + path_len, GIT_OBJECTS_DIR); - if (gitfo_isdir(path_aux) < GIT_SUCCESS) - return GIT_ENOTAREPO; - repo->path_odb = git__strdup(path_aux); - - /* HEAD file */ - strcpy(path_aux + path_len, GIT_HEAD_FILE); - if (gitfo_exists(path_aux) < 0) - return GIT_ENOTAREPO; - - path_aux[path_len] = 0; + /* Path to objects database */ + git__joinpath(path_odb, repository_path, GIT_OBJECTS_DIR); - if ((topdir = git__topdir(path_aux)) == NULL) + /* Git directory name */ + if (git__basename_r(dir_name, sizeof(dir_name), repository_path) < 0) return GIT_EINVALIDPATH; - if (strcmp(topdir, GIT_DIR) == 0) { - repo->is_bare = 0; - - /* index file */ - strcpy(path_aux + path_len, GIT_INDEX_FILE); - repo->path_index = git__strdup(path_aux); + if (strcmp(dir_name, DOT_GIT) == 0) { + + /* Path to index file */ + git__joinpath(path_index, repository_path, GIT_INDEX_FILE); - /* working dir */ - repo->path_workdir = git__dirname(path_aux); - if (repo->path_workdir == NULL) + /* Path to working dir */ + if (git__dirname_r(path_work_tree, sizeof(path_work_tree), repository_path) < 0) return GIT_EINVALIDPATH; - - } else { - repo->is_bare = 1; - repo->path_workdir = NULL; } - return GIT_SUCCESS; + error = assign_repository_DIRs(repo, repository_path, path_odb, !*path_index ? NULL : path_index, !*path_work_tree ? NULL : path_work_tree, is_repo_being_created); + return error; } static git_repository *repository_alloc() @@ -221,9 +196,9 @@ static git_repository *repository_alloc() repo->objects = git_hashtable_alloc( OBJECT_TABLE_SIZE, object_table_hash, - object_table_hashkey); + (git_hash_keyeq_ptr)git_oid_cmp); - if (repo->objects == NULL) { + if (repo->objects == NULL) { free(repo); return NULL; } @@ -234,6 +209,13 @@ static git_repository *repository_alloc() return NULL; } + if (git_vector_init(&repo->memory_objects, 16, NULL) < GIT_SUCCESS) { + git_hashtable_free(repo->objects); + git_repository__refcache_free(&repo->references); + free(repo); + return NULL; + } + return repo; } @@ -264,7 +246,8 @@ int git_repository_open3(git_repository **repo_out, git_dir, NULL, git_index_file, - git_work_tree); + git_work_tree, + 0); if (error < GIT_SUCCESS) goto cleanup; @@ -299,7 +282,8 @@ int git_repository_open2(git_repository **repo_out, git_dir, git_object_directory, git_index_file, - git_work_tree); + git_work_tree, + 0); if (error < GIT_SUCCESS) goto cleanup; @@ -316,7 +300,7 @@ int git_repository_open2(git_repository **repo_out, return error; } -int git_repository_open(git_repository **repo_out, const char *path) +static int repository_open_internal(git_repository **repo_out, const char *path, int is_repo_being_created) { git_repository *repo; int error = GIT_SUCCESS; @@ -327,7 +311,7 @@ int git_repository_open(git_repository **repo_out, const char *path) if (repo == NULL) return GIT_ENOMEM; - error = guess_repository_DIRs(repo, path); + error = guess_repository_DIRs(repo, path, is_repo_being_created); if (error < GIT_SUCCESS) goto cleanup; @@ -343,26 +327,22 @@ int git_repository_open(git_repository **repo_out, const char *path) return error; } -void git_repository_free(git_repository *repo) +int git_repository_open(git_repository **repo_out, const char *path) { - git_hashtable_iterator it; - git_object *object; + return repository_open_internal(repo_out, path, 0); +} - if (repo == NULL) - return; +static void repository_free(git_repository *repo) +{ + assert(repo); free(repo->path_workdir); free(repo->path_index); free(repo->path_repository); free(repo->path_odb); - git_hashtable_iterator_init(repo->objects, &it); - - while ((object = (git_object *) - git_hashtable_iterator_next(&it)) != NULL) - git_object_free(object); - git_hashtable_free(repo->objects); + git_vector_free(&repo->memory_objects); git_repository__refcache_free(&repo->references); @@ -375,147 +355,79 @@ void git_repository_free(git_repository *repo) free(repo); } -int git_repository_index(git_index **index_out, git_repository *repo) +void git_repository_free__no_gc(git_repository *repo) { - int error; + git_object *object; + const void *_unused; + unsigned int i; - assert(index_out && repo); + if (repo == NULL) + return; - if (repo->index == NULL) { - error = git_index_open_inrepo(&repo->index, repo); - if (error < GIT_SUCCESS) - return error; + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + object->repo = NULL; + object->refcount = 0; + ); - assert(repo->index != NULL); + for (i = 0; i < repo->memory_objects.length; ++i) { + object = git_vector_get(&repo->memory_objects, i); + object->repo = NULL; + object->refcount = 0; } - *index_out = repo->index; - return GIT_SUCCESS; -} - -git_odb *git_repository_database(git_repository *repo) -{ - assert(repo); - return repo->db; + repository_free(repo); } -static int create_object(git_object **object_out, git_otype type) +void git_repository_free(git_repository *repo) { - git_object *object = NULL; + git_object *object; + const void *_unused; + unsigned int i; - assert(object_out); + if (repo == NULL) + return; - *object_out = NULL; + /* Increment the refcount of all the objects in the repository + * to prevent freeing dependencies */ + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + GIT_OBJECT_INCREF(object); + ); - switch (type) { - case GIT_OBJ_COMMIT: - case GIT_OBJ_TAG: - case GIT_OBJ_BLOB: - object = git__malloc(git_object__size(type)); - if (object == NULL) - return GIT_ENOMEM; - memset(object, 0x0, git_object__size(type)); - break; - - case GIT_OBJ_TREE: - object = (git_object *)git_tree__new(); - if (object == NULL) - return GIT_ENOMEM; - break; + /* force free all the objects */ + GIT_HASHTABLE_FOREACH(repo->objects, _unused, object, + git_object__free(object); + ); - default: - return GIT_EINVALIDTYPE; + for (i = 0; i < repo->memory_objects.length; ++i) { + object = git_vector_get(&repo->memory_objects, i); + git_object__free(object); } - *object_out = object; - return GIT_SUCCESS; + repository_free(repo); } -int git_repository_newobject(git_object **object_out, git_repository *repo, git_otype type) +int git_repository_index(git_index **index_out, git_repository *repo) { - git_object *object = NULL; int error; - assert(object_out && repo); - - if ((error = create_object(&object, type)) < GIT_SUCCESS) - return error; + assert(index_out && repo); - object->repo = repo; - object->in_memory = 1; - object->modified = 1; + if (repo->index == NULL) { + error = git_index_open_inrepo(&repo->index, repo); + if (error < GIT_SUCCESS) + return error; - object->source.raw.type = type; + assert(repo->index != NULL); + } - *object_out = object; + *index_out = repo->index; return GIT_SUCCESS; } -int git_repository_lookup(git_object **object_out, git_repository *repo, const git_oid *id, git_otype type) +git_odb *git_repository_database(git_repository *repo) { - git_object *object = NULL; - git_rawobj obj_file; - int error = GIT_SUCCESS; - - assert(repo && object_out && id); - - object = git_hashtable_lookup(repo->objects, id); - if (object != NULL) { - *object_out = object; - return GIT_SUCCESS; - } - - error = git_odb_read(&obj_file, repo->db, id); - if (error < GIT_SUCCESS) - return error; - - if (type != GIT_OBJ_ANY && type != obj_file.type) { - git_rawobj_close(&obj_file); - return GIT_EINVALIDTYPE; - } - - type = obj_file.type; - - if ((error = create_object(&object, type)) < GIT_SUCCESS) - return error; - - /* Initialize parent object */ - git_oid_cpy(&object->id, id); - object->repo = repo; - memcpy(&object->source.raw, &obj_file, sizeof(git_rawobj)); - object->source.open = 1; - - switch (type) { - case GIT_OBJ_COMMIT: - error = git_commit__parse((git_commit *)object); - break; - - case GIT_OBJ_TREE: - error = git_tree__parse((git_tree *)object); - break; - - case GIT_OBJ_TAG: - error = git_tag__parse((git_tag *)object); - break; - - case GIT_OBJ_BLOB: - error = git_blob__parse((git_blob *)object); - break; - - default: - break; - } - - if (error < GIT_SUCCESS) { - git_object_free(object); - return error; - } - - git_object__source_close(object); - git_hashtable_insert(repo->objects, &object->id, object); - - *object_out = object; - return GIT_SUCCESS; + assert(repo); + return repo->db; } static int repo_init_reinit(repo_init *results) @@ -525,21 +437,18 @@ static int repo_init_reinit(repo_init *results) return GIT_SUCCESS; } -static int repo_init_createhead(const char *head_path) +static int repo_init_createhead(git_repository *repo) { - git_file fd; - int error = GIT_SUCCESS; - char head_symlink[50]; - - sprintf(head_symlink, "%s %s%s\n", GIT_SYMREF, GIT_REFS_HEADS_DIR, GIT_BRANCH_MASTER); - - if ((fd = gitfo_creat(head_path, S_IREAD | S_IWRITE)) < GIT_SUCCESS) - return GIT_ERROR; + git_reference *head_reference; + return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE); +} - error = gitfo_write(fd, (void*)head_symlink, strlen(head_symlink)); +static int repo_init_check_head_existence(char * repository_path) +{ + char temp_path[GIT_PATH_MAX]; - gitfo_close(fd); - return error; + git__joinpath(temp_path, repository_path, GIT_HEAD_FILE); + return gitfo_exists(temp_path); } static int repo_init_structure(repo_init *results) @@ -547,41 +456,28 @@ static int repo_init_structure(repo_init *results) const int mode = 0755; /* or 0777 ? */ char temp_path[GIT_PATH_MAX]; - int path_len; char *git_dir = results->path_repository; if (gitfo_mkdir_recurs(git_dir, mode)) return GIT_ERROR; - path_len = strlen(git_dir); - strcpy(temp_path, git_dir); - - /* Does HEAD file already exist ? */ - strcpy(temp_path + path_len, GIT_HEAD_FILE); - - if (gitfo_exists(temp_path) == GIT_SUCCESS) - return repo_init_reinit(results); - - if (repo_init_createhead(temp_path) < GIT_SUCCESS) - return GIT_ERROR; - /* Creates the '/objects/info/' directory */ - strcpy(temp_path + path_len, GIT_OBJECTS_INFO_DIR); - if (gitfo_mkdir_recurs(temp_path, mode)) + git__joinpath(temp_path, git_dir, GIT_OBJECTS_INFO_DIR); + if (gitfo_mkdir_recurs(temp_path, mode) < GIT_SUCCESS) return GIT_ERROR; /* Creates the '/objects/pack/' directory */ - strcpy(temp_path + path_len, GIT_OBJECTS_PACK_DIR); + git__joinpath(temp_path, git_dir, GIT_OBJECTS_PACK_DIR); if (gitfo_mkdir(temp_path, mode)) return GIT_ERROR; /* Creates the '/refs/heads/' directory */ - strcpy(temp_path + path_len, GIT_REFS_HEADS_DIR); + git__joinpath(temp_path, git_dir, GIT_REFS_HEADS_DIR); if (gitfo_mkdir_recurs(temp_path, mode)) return GIT_ERROR; /* Creates the '/refs/tags/' directory */ - strcpy(temp_path + path_len, GIT_REFS_TAGS_DIR); + git__joinpath(temp_path, git_dir, GIT_REFS_TAGS_DIR); if (gitfo_mkdir(temp_path, mode)) return GIT_ERROR; @@ -593,24 +489,19 @@ static int repo_init_structure(repo_init *results) static int repo_init_find_dir(repo_init *results, const char* path) { char temp_path[GIT_PATH_MAX]; - int path_len; int error = GIT_SUCCESS; error = gitfo_prettify_dir_path(temp_path, path); if (error < GIT_SUCCESS) return error; - path_len = strlen(temp_path); - if (!results->is_bare) { - strcpy(temp_path + path_len - 1, GIT_DIR); - path_len = path_len + strlen(GIT_DIR) - 1; /* Skip the leading slash from the constant */ + git__joinpath(temp_path, temp_path, GIT_DIR); } - if (path_len >= GIT_PATH_MAX - MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH) - return GIT_ENOTAREPO; - results->path_repository = git__strdup(temp_path); + if (results->path_repository == NULL) + return GIT_ENOMEM; return GIT_SUCCESS; } @@ -629,11 +520,20 @@ int git_repository_init(git_repository **repo_out, const char *path, unsigned is if (error < GIT_SUCCESS) goto cleanup; + if (!repo_init_check_head_existence(results.path_repository)) + return repo_init_reinit(&results); + error = repo_init_structure(&results); if (error < GIT_SUCCESS) goto cleanup; - error = git_repository_open(repo_out, results.path_repository); + error = repository_open_internal(repo_out, results.path_repository, 1); + if (error < GIT_SUCCESS) + goto cleanup; + + assert((*repo_out)->is_bare == is_bare); + + error = repo_init_createhead(*repo_out); cleanup: free(results.path_repository); diff --git a/vendor/libgit2/src/repository.h b/vendor/libgit2/src/repository.h old mode 100755 new mode 100644 index 5bf041140..4af062e97 --- a/vendor/libgit2/src/repository.h +++ b/vendor/libgit2/src/repository.h @@ -10,6 +10,11 @@ #include "index.h" #include "refs.h" +#define DOT_GIT ".git" +#define GIT_DIR DOT_GIT "/" +#define GIT_OBJECTS_DIR "objects/" +#define GIT_INDEX_FILE "index" + typedef struct { git_rawobj raw; void *write_ptr; @@ -21,13 +26,16 @@ struct git_object { git_oid id; git_repository *repo; git_odb_source source; - int in_memory:1, modified:1; + unsigned short refcount; + short in_memory:1, modified:1; }; struct git_repository { git_odb *db; git_index *index; + git_hashtable *objects; + git_vector memory_objects; git_refcache references; @@ -42,10 +50,22 @@ struct git_repository { int git_object__source_open(git_object *object); void git_object__source_close(git_object *object); +/* fully free the object; internal method, do not + * export */ +void git_object__free(git_object *object); + int git__source_printf(git_odb_source *source, const char *format, ...); int git__source_write(git_odb_source *source, const void *bytes, size_t len); int git__parse_oid(git_oid *oid, char **buffer_out, const char *buffer_end, const char *header); int git__write_oid(git_odb_source *src, const char *header, const git_oid *oid); +#define GIT_OBJECT_INCREF(ob) git_object__incref((git_object *)(ob)) + +GIT_INLINE(void) git_object__incref(struct git_object *object) +{ + if (object) + object->refcount++; +} + #endif diff --git a/vendor/libgit2/src/revwalk.c b/vendor/libgit2/src/revwalk.c old mode 100755 new mode 100644 index 2237e333d..872cdbc43 --- a/vendor/libgit2/src/revwalk.c +++ b/vendor/libgit2/src/revwalk.c @@ -28,28 +28,23 @@ #include "revwalk.h" #include "hashtable.h" -uint32_t git_revwalk__commit_hash(const void *key) +uint32_t git_revwalk__commit_hash(const void *key, int hash_id) { uint32_t r; git_commit *commit; commit = (git_commit *)key; - memcpy(&r, commit->object.id.id, sizeof(r)); + memcpy(&r, commit->object.id.id + (hash_id * sizeof(uint32_t)), sizeof(r)); return r; } -int git_revwalk__commit_haskey(void *object, const void *key) +int git_revwalk__commit_keycmp(const void *key_a, const void *key_b) { - git_revwalk_commit *walk_commit; - git_commit *commit_object; - - walk_commit = (git_revwalk_commit *)object; - commit_object = (git_commit *)key; - - return (walk_commit->commit_object == commit_object); + git_commit *a = (git_commit *)key_a; + git_commit *b = (git_commit *)key_b; + return git_oid_cmp(&a->object.id, &b->object.id); } - int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) { git_revwalk *walk; @@ -62,7 +57,7 @@ int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) walk->commits = git_hashtable_alloc(64, git_revwalk__commit_hash, - git_revwalk__commit_haskey); + git_revwalk__commit_keycmp); if (walk->commits == NULL) { free(walk); @@ -119,6 +114,7 @@ static git_revwalk_commit *commit_to_walkcommit(git_revwalk *walk, git_commit *c memset(commit, 0x0, sizeof(git_revwalk_commit)); commit->commit_object = commit_object; + GIT_OBJECT_INCREF(commit_object); git_hashtable_insert(walk->commits, commit_object, commit); @@ -234,6 +230,7 @@ int git_revwalk_next(git_commit **commit, git_revwalk *walk) while ((next = walk->next(&walk->iterator)) != NULL) { if (!next->uninteresting) { *commit = next->commit_object; + GIT_OBJECT_INCREF(*commit); return GIT_SUCCESS; } } @@ -245,18 +242,16 @@ int git_revwalk_next(git_commit **commit, git_revwalk *walk) void git_revwalk_reset(git_revwalk *walk) { - git_hashtable_iterator it; + const void *_unused; git_revwalk_commit *commit; assert(walk); - git_hashtable_iterator_init(walk->commits, &it); - - while ((commit = (git_revwalk_commit *) - git_hashtable_iterator_next(&it)) != NULL) { + GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, { + git_object_close((git_object *)commit->commit_object); git_revwalk_list_clear(&commit->parents); free(commit); - } + }); git_hashtable_clear(walk->commits); git_revwalk_list_clear(&walk->iterator); @@ -329,6 +324,8 @@ git_revwalk_commit *git_revwalk_list_pop_back(git_revwalk_list *list) list->tail = list->tail->prev; if (list->tail == NULL) list->head = NULL; + else + list->tail->next = NULL; commit = node->walk_commit; free(node); @@ -350,6 +347,8 @@ git_revwalk_commit *git_revwalk_list_pop_front(git_revwalk_list *list) list->head = list->head->next; if (list->head == NULL) list->tail = NULL; + else + list->head->prev = NULL; commit = node->walk_commit; free(node); diff --git a/vendor/libgit2/src/revwalk.h b/vendor/libgit2/src/revwalk.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/signature.c b/vendor/libgit2/src/signature.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/signature.h b/vendor/libgit2/src/signature.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/t03-data.h b/vendor/libgit2/src/t03-data.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/tag.c b/vendor/libgit2/src/tag.c old mode 100755 new mode 100644 index 4c6cabf0b..01cc0dc8f --- a/vendor/libgit2/src/tag.c +++ b/vendor/libgit2/src/tag.c @@ -35,6 +35,7 @@ void git_tag__free(git_tag *tag) { git_signature_free(tag->tagger); + git_object_close(tag->target); free(tag->message); free(tag->tag_name); free(tag); @@ -48,6 +49,7 @@ const git_oid *git_tag_id(git_tag *c) const git_object *git_tag_target(git_tag *t) { assert(t); + GIT_OBJECT_INCREF(t->target); return t->target; } @@ -55,6 +57,9 @@ void git_tag_set_target(git_tag *tag, git_object *target) { assert(tag && target); + git_object_close(tag->target); + GIT_OBJECT_INCREF(target); + tag->object.modified = 1; tag->target = target; tag->type = git_object_type(target); @@ -66,14 +71,6 @@ git_otype git_tag_type(git_tag *t) return t->type; } -void git_tag_set_type(git_tag *tag, git_otype type) -{ - assert(tag); - - tag->object.modified = 1; - tag->type = type; -} - const char *git_tag_name(git_tag *t) { assert(t); @@ -164,7 +161,8 @@ static int parse_tag_buffer(git_tag *tag, char *buffer, const char *buffer_end) if (tag->type == GIT_OBJ_BAD) return GIT_EOBJCORRUPTED; - error = git_repository_lookup(&tag->target, tag->object.repo, &target_oid, tag->type); + git_object_close(tag->target); + error = git_object_lookup(&tag->target, tag->object.repo, &target_oid, tag->type); if (error < 0) return error; diff --git a/vendor/libgit2/src/tag.h b/vendor/libgit2/src/tag.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/thread-utils.c b/vendor/libgit2/src/thread-utils.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/thread-utils.h b/vendor/libgit2/src/thread-utils.h old mode 100755 new mode 100644 index 0395b97d1..0029e4bc1 --- a/vendor/libgit2/src/thread-utils.h +++ b/vendor/libgit2/src/thread-utils.h @@ -2,86 +2,106 @@ #define INCLUDE_thread_utils_h__ #if defined(GIT_HAS_PTHREAD) -typedef pthread_mutex_t git_lck; -# define GITLCK_INIT PTHREAD_MUTEX_INITIALIZER -# define gitlck_init(a) pthread_mutex_init(a, NULL) -# define gitlck_lock(a) pthread_mutex_lock(a) -# define gitlck_unlock(a) pthread_mutex_unlock(a) -# define gitlck_free(a) pthread_mutex_destroy(a) + typedef pthread_t git_thread; +# define git_thread_create(thread, attr, start_routine, arg) pthread_create(thread, attr, start_routine, arg) +# define git_thread_kill(thread) pthread_cancel(thread) +# define git_thread_exit(status) pthread_exit(status) +# define git_thread_join(id, status) pthread_join(id, status) -# if defined(GIT_HAS_ASM_ATOMIC) -# include -typedef atomic_t git_refcnt; -# define gitrc_init(a) atomic_set(a, 0) -# define gitrc_inc(a) atomic_inc_return(a) -# define gitrc_dec(a) atomic_dec_and_test(a) -# define gitrc_free(a) (void)0 + /* Pthreads Mutex */ + typedef pthread_mutex_t git_lck; +# define GITLCK_INIT PTHREAD_MUTEX_INITIALIZER +# define gitlck_init(a) pthread_mutex_init(a, NULL) +# define gitlck_lock(a) pthread_mutex_lock(a) +# define gitlck_unlock(a) pthread_mutex_unlock(a) +# define gitlck_free(a) pthread_mutex_destroy(a) -# else -typedef struct { git_lck lock; int counter; } git_refcnt; + /* Pthreads condition vars */ + typedef pthread_cond_t git_cnd; +# define GITCND_INIT PTHREAD_COND_INITIALIZER +# define gitcnd_init(c, a) pthread_cond_init(c, a) +# define gitcnd_free(c) pthread_cond_destroy(c) +# define gitcnd_wait(c, l) pthread_cond_wait(c, l) +# define gitcnd_signal(c) pthread_cond_signal(c) +# define gitcnd_broadcast(c) pthread_cond_broadcast(c) -/** Initialize to 0. No memory barrier is issued. */ -GIT_INLINE(void) gitrc_init(git_refcnt *p) -{ - gitlck_init(&p->lock); - p->counter = 0; -} +# if defined(GIT_HAS_ASM_ATOMIC) +# include + typedef atomic_t git_refcnt; +# define gitrc_init(a, v) atomic_set(a, v) +# define gitrc_inc(a) atomic_inc_return(a) +# define gitrc_dec(a) atomic_dec_and_test(a) +# define gitrc_free(a) (void)0 +# elif defined(GIT_WIN32) + typedef long git_refcnt; +# define gitrc_init(a, v) (*a = v) +# define gitrc_inc(a) (InterlockedIncrement(a)) +# define gitrc_dec(a) (!InterlockedDecrement(a)) +# define gitrc_free(a) (void)0 +# else + typedef struct { git_lck lock; int counter; } git_refcnt; -/** - * Increment. - * - * Atomically increments @p by 1. A memory barrier is also - * issued before and after the operation. - * - * @param p pointer of type git_refcnt - */ -GIT_INLINE(void) gitrc_inc(git_refcnt *p) -{ - gitlck_lock(&p->lock); - p->counter++; - gitlck_unlock(&p->lock); -} + /** Initialize to 0. No memory barrier is issued. */ + GIT_INLINE(void) gitrc_init(git_refcnt *p, int value) + { + gitlck_init(&p->lock); + p->counter = value; + } -/** - * Decrement and test. - * - * Atomically decrements @p by 1 and returns true if the - * result is 0, or false for all other cases. A memory - * barrier is also issued before and after the operation. - * - * @param p pointer of type git_refcnt - */ -GIT_INLINE(int) gitrc_dec(git_refcnt *p) -{ - int c; - gitlck_lock(&p->lock); - c = --p->counter; - gitlck_unlock(&p->lock); - return !c; -} + /** + * Increment. + * + * Atomically increments @p by 1. A memory barrier is also + * issued before and after the operation. + * + * @param p pointer of type git_refcnt + */ + GIT_INLINE(void) gitrc_inc(git_refcnt *p) + { + gitlck_lock(&p->lock); + p->counter++; + gitlck_unlock(&p->lock); + } -/** Free any resources associated with the counter. */ -# define gitrc_free(p) gitlck_free(&(p)->lock) + /** + * Decrement and test. + * + * Atomically decrements @p by 1 and returns true if the + * result is 0, or false for all other cases. A memory + * barrier is also issued before and after the operation. + * + * @param p pointer of type git_refcnt + */ + GIT_INLINE(int) gitrc_dec(git_refcnt *p) + { + int c; + gitlck_lock(&p->lock); + c = --p->counter; + gitlck_unlock(&p->lock); + return !c; + } -# endif + /** Free any resources associated with the counter. */ +# define gitrc_free(p) gitlck_free(&(p)->lock) +# endif #elif defined(GIT_THREADS) -# error GIT_THREADS but no git_lck implementation +# error GIT_THREADS but no git_lck implementation #else -typedef struct { int dummy; } git_lck; -# define GIT_MUTEX_INIT {} -# define gitlck_init(a) (void)0 -# define gitlck_lock(a) (void)0 -# define gitlck_unlock(a) (void)0 -# define gitlck_free(a) (void)0 - -typedef struct { int counter; } git_refcnt; -# define gitrc_init(a) ((a)->counter = 0) -# define gitrc_inc(a) ((a)->counter++) -# define gitrc_dec(a) (--(a)->counter == 0) -# define gitrc_free(a) (void)0 + /* no threads support */ + typedef struct { int dummy; } git_lck; +# define GIT_MUTEX_INIT {} +# define gitlck_init(a) (void)0 +# define gitlck_lock(a) (void)0 +# define gitlck_unlock(a) (void)0 +# define gitlck_free(a) (void)0 + typedef struct { int counter; } git_refcnt; +# define gitrc_init(a,v) ((a)->counter = v) +# define gitrc_inc(a) ((a)->counter++) +# define gitrc_dec(a) (--(a)->counter == 0) +# define gitrc_free(a) (void)0 #endif extern int git_online_cpus(void); diff --git a/vendor/libgit2/src/tree.c b/vendor/libgit2/src/tree.c old mode 100755 new mode 100644 index 5cef676ee..30938f258 --- a/vendor/libgit2/src/tree.c +++ b/vendor/libgit2/src/tree.c @@ -40,30 +40,12 @@ int entry_search_cmp(const void *key, const void *array_member) return strcmp(filename, entry->filename); } -static int cache_name_compare(const char *name1, int len1, int isdir1, - const char *name2, int len2, int isdir2) -{ - int len = len1 < len2 ? len1 : len2; - int cmp; - - cmp = memcmp(name1, name2, len); - if (cmp) - return cmp; - if (len1 < len2) - return ((!isdir1 && !isdir2) ? -1 : - (isdir1 ? '/' - name2[len1] : name2[len1] - '/')); - if (len1 > len2) - return ((!isdir1 && !isdir2) ? 1 : - (isdir2 ? name1[len2] - '/' : '/' - name1[len2])); - return 0; -} - int entry_sort_cmp(const void *a, const void *b) { const git_tree_entry *entry_a = *(const git_tree_entry **)(a); const git_tree_entry *entry_b = *(const git_tree_entry **)(b); - return cache_name_compare(entry_a->filename, strlen(entry_a->filename), + return gitfo_cmp_path(entry_a->filename, strlen(entry_a->filename), entry_a->attr & 040000, entry_b->filename, strlen(entry_b->filename), entry_b->attr & 040000); @@ -85,9 +67,7 @@ void git_tree_clear_entries(git_tree *tree) } git_vector_clear(&tree->entries); - tree->object.modified = 1; - tree->sorted = 1; } @@ -101,15 +81,11 @@ git_tree *git_tree__new(void) memset(tree, 0x0, sizeof(struct git_tree)); - if (git_vector_init(&tree->entries, - DEFAULT_TREE_SIZE, - entry_sort_cmp, - entry_search_cmp) < GIT_SUCCESS) { + if (git_vector_init(&tree->entries, DEFAULT_TREE_SIZE, entry_sort_cmp) < GIT_SUCCESS) { free(tree); return NULL; } - tree->sorted = 1; return tree; } @@ -171,7 +147,12 @@ const git_oid *git_tree_entry_id(git_tree_entry *entry) int git_tree_entry_2object(git_object **object_out, git_tree_entry *entry) { assert(entry && object_out); - return git_repository_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY); + return git_object_lookup(object_out, entry->owner->object.repo, &entry->oid, GIT_OBJ_ANY); +} + +static void sort_entries(git_tree *tree) +{ + git_vector_sort(&tree->entries); } git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) @@ -180,10 +161,9 @@ git_tree_entry *git_tree_entry_byname(git_tree *tree, const char *filename) assert(tree && filename); - if (!tree->sorted) - git_tree_sort_entries(tree); + sort_entries(tree); - idx = git_vector_search(&tree->entries, filename); + idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename); if (idx == GIT_ENOTFOUND) return NULL; @@ -194,8 +174,7 @@ git_tree_entry *git_tree_entry_byindex(git_tree *tree, int idx) { assert(tree); - if (!tree->sorted) - git_tree_sort_entries(tree); + sort_entries(tree); return git_vector_get(&tree->entries, (unsigned int)idx); } @@ -206,7 +185,7 @@ size_t git_tree_entrycount(git_tree *tree) return tree->entries.length; } -int git_tree_add_entry_unsorted(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes) +int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes) { git_tree_entry *entry; @@ -229,34 +208,16 @@ int git_tree_add_entry_unsorted(git_tree_entry **entry_out, git_tree *tree, cons *entry_out = entry; tree->object.modified = 1; - tree->sorted = 0; return GIT_SUCCESS; } -int git_tree_add_entry(git_tree_entry **entry_out, git_tree *tree, const git_oid *id, const char *filename, int attributes) -{ - int result = git_tree_add_entry_unsorted(entry_out, tree, id, filename, attributes); - if (result == GIT_SUCCESS) - git_tree_sort_entries(tree); - - return result; -} - -int git_tree_sort_entries(git_tree *tree) -{ - git_vector_sort(&tree->entries); - tree->sorted = 1; - return GIT_SUCCESS; -} - int git_tree_remove_entry_byindex(git_tree *tree, int idx) { git_tree_entry *remove_ptr; assert(tree); - if (!tree->sorted) - git_tree_sort_entries(tree); + sort_entries(tree); remove_ptr = git_vector_get(&tree->entries, (unsigned int)idx); if (remove_ptr == NULL) @@ -276,10 +237,9 @@ int git_tree_remove_entry_byname(git_tree *tree, const char *filename) assert(tree && filename); - if (!tree->sorted) - git_tree_sort_entries(tree); + sort_entries(tree); - idx = git_vector_search(&tree->entries, filename); + idx = git_vector_bsearch2(&tree->entries, entry_search_cmp, filename); if (idx == GIT_ENOTFOUND) return GIT_ENOTFOUND; @@ -296,8 +256,7 @@ int git_tree__writeback(git_tree *tree, git_odb_source *src) if (tree->entries.length == 0) return GIT_EMISSINGOBJDATA; - if (!tree->sorted) - git_tree_sort_entries(tree); + sort_entries(tree); for (i = 0; i < tree->entries.length; ++i) { git_tree_entry *entry; diff --git a/vendor/libgit2/src/tree.h b/vendor/libgit2/src/tree.h old mode 100755 new mode 100644 index 796c5b950..78500c471 --- a/vendor/libgit2/src/tree.h +++ b/vendor/libgit2/src/tree.h @@ -16,7 +16,6 @@ struct git_tree_entry { struct git_tree { git_object object; git_vector entries; - unsigned sorted:1; }; void git_tree__free(git_tree *tree); diff --git a/vendor/libgit2/src/unix/map.c b/vendor/libgit2/src/unix/map.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/util.c b/vendor/libgit2/src/util.c old mode 100755 new mode 100644 index 67b74eeba..2f1bd2220 --- a/vendor/libgit2/src/util.c +++ b/vendor/libgit2/src/util.c @@ -202,30 +202,34 @@ const char *git__topdir(const char *path) return &path[i + 1]; } -char *git__joinpath(const char *path_a, const char *path_b) +void git__joinpath_n(char *buffer_out, int count, ...) { - int len_a, len_b; - char *path_new; - - assert(path_a && path_b); + va_list ap; + int i; + char *buffer_start = buffer_out; - len_a = strlen(path_a); - len_b = strlen(path_b); + va_start(ap, count); + for (i = 0; i < count; ++i) { + const char *path; + int len; - path_new = git__malloc(len_a + len_b + 2); - if (path_new == NULL) - return NULL; + path = va_arg(ap, const char *); + if (i > 0 && *path == '/' && buffer_out > buffer_start && buffer_out[-1] == '/') + path++; - strcpy(path_new, path_a); + if (!*path) + continue; - if (len_a > 0 && len_b > 0 && path_new[len_a - 1] != '/') - path_new[len_a++] = '/'; + len = strlen(path); + memcpy(buffer_out, path, len); + buffer_out = buffer_out + len; - if (path_b[0] == '/') - path_b++; + if (i < count - 1 && buffer_out[-1] != '/') + *buffer_out++ = '/'; + } + va_end(ap); - strcpy(path_new + len_a, path_b); - return path_new; + *buffer_out = '\0'; } static char *strtok_raw(char *output, char *src, char *delimit, int keep) diff --git a/vendor/libgit2/src/util.h b/vendor/libgit2/src/util.h old mode 100755 new mode 100644 index 0f010929f..d5320e15b --- a/vendor/libgit2/src/util.h +++ b/vendor/libgit2/src/util.h @@ -62,9 +62,15 @@ extern const char *git__topdir(const char *path); * Join two paths together. Takes care of properly fixing the * middle slashes and everything * - * Returns a newly allocated string; must be free'd manually. + * The paths are joined together into buffer_out; this is expected + * to be an user allocated buffer of `GIT_PATH_MAX` size */ -extern char *git__joinpath(const char *path_a, const char *path_b); +extern void git__joinpath_n(char *buffer_out, int npath, ...); + +GIT_INLINE(void) git__joinpath(char *buffer_out, const char *path_a, const char *path_b) +{ + git__joinpath_n(buffer_out, 2, path_a, path_b); +} extern void git__hexdump(const char *buffer, size_t n); extern uint32_t git__hash(const void *key, int len, uint32_t seed); @@ -84,18 +90,6 @@ GIT_INLINE(int) git__is_sizet(git_off_t p) # define git__rotl(v, s) (uint32_t)(((uint32_t)(v) << (s)) | ((uint32_t)(v) >> (32 - (s)))) #endif -enum git_splitpath_flags -{ - GIT_SPL_PATH = 1, - GIT_SPL_FILE = 2, - GIT_SPL_EXT = 4, - GIT_SPL_PATH_FILE = GIT_SPL_PATH + GIT_SPL_FILE, - GIT_SPL_FILE_EXT = GIT_SPL_FILE + GIT_SPL_EXT, - GIT_SPL_EXT_NO_PERIOD = 8, -}; - - -extern char *git__splitpath(char *path, int flag); extern char *git__strtok(char *output, char *src, char *delimit); extern char *git__strtok_keep(char *output, char *src, char *delimit); diff --git a/vendor/libgit2/src/vector.c b/vendor/libgit2/src/vector.c old mode 100755 new mode 100644 index 325f34306..631364031 --- a/vendor/libgit2/src/vector.c +++ b/vendor/libgit2/src/vector.c @@ -28,25 +28,18 @@ #include "vector.h" static const double resize_factor = 1.75; -static const int minimum_size = 8; +static const size_t minimum_size = 8; static int resize_vector(git_vector *v) { - void **new_contents; - v->_alloc_size = ((unsigned int)(v->_alloc_size * resize_factor)) + 1; - if (v->_alloc_size == 0) + if (v->_alloc_size < minimum_size) v->_alloc_size = minimum_size; - new_contents = git__malloc(v->_alloc_size * sizeof(void *)); - if (new_contents == NULL) + v->contents = realloc(v->contents, v->_alloc_size * sizeof(void *)); + if (v->contents == NULL) return GIT_ENOMEM; - memcpy(new_contents, v->contents, v->length * sizeof(void *)); - - free(v->contents); - v->contents = new_contents; - return GIT_SUCCESS; } @@ -57,7 +50,7 @@ void git_vector_free(git_vector *v) free(v->contents); } -int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp, git_vector_srch srch) +int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp) { assert(v); @@ -68,9 +61,9 @@ int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp v->_alloc_size = initial_size; v->_cmp = cmp; - v->_srch = srch; v->length = 0; + v->sorted = 1; v->contents = git__malloc(v->_alloc_size * sizeof(void *)); if (v->contents == NULL) @@ -89,36 +82,71 @@ int git_vector_insert(git_vector *v, void *element) } v->contents[v->length++] = element; + v->sorted = 0; return GIT_SUCCESS; } -void *git_vector_get(git_vector *v, unsigned int position) -{ - assert(v); - return (position < v->length) ? v->contents[position] : NULL; -} - void git_vector_sort(git_vector *v) { assert(v); - if (v->_cmp != NULL) - qsort(v->contents, v->length, sizeof(void *), v->_cmp); + if (v->sorted || v->_cmp == NULL) + return; + + qsort(v->contents, v->length, sizeof(void *), v->_cmp); + v->sorted = 1; } -int git_vector_search(git_vector *v, const void *key) +int git_vector_bsearch2(git_vector *v, git_vector_cmp key_lookup, const void *key) { void **find; - if (v->_srch == NULL) + assert(v && key && key_lookup); + + /* need comparison function to sort the vector */ + if (v->_cmp == NULL) return GIT_ENOTFOUND; - find = bsearch(key, v->contents, v->length, sizeof(void *), v->_srch); - if (find == NULL) + git_vector_sort(v); + + find = bsearch(key, v->contents, v->length, sizeof(void *), key_lookup); + if (find != NULL) + return (int)(find - v->contents); + + return GIT_ENOTFOUND; +} + +int git_vector_search2(git_vector *v, git_vector_cmp key_lookup, const void *key) +{ + unsigned int i; + + assert(v && key && key_lookup); + + for (i = 0; i < v->length; ++i) { + if (key_lookup(key, v->contents[i]) == 0) + return i; + } + + return GIT_ENOTFOUND; +} + +static int strict_comparison(const void *a, const void *b) +{ + return a - b; +} + +int git_vector_search(git_vector *v, const void *entry) +{ + return git_vector_search2(v, v->_cmp ? v->_cmp : strict_comparison, entry); +} + +int git_vector_bsearch(git_vector *v, const void *key) +{ + if (v->_cmp == NULL) return GIT_ENOTFOUND; - return (int)(find - v->contents); + return git_vector_bsearch2(v, v->_cmp, key); } int git_vector_remove(git_vector *v, unsigned int idx) @@ -141,6 +169,7 @@ void git_vector_clear(git_vector *v) { assert(v); v->length = 0; + v->sorted = 1; } diff --git a/vendor/libgit2/src/vector.h b/vendor/libgit2/src/vector.h old mode 100755 new mode 100644 index 305927a72..256452ee5 --- a/vendor/libgit2/src/vector.h +++ b/vendor/libgit2/src/vector.h @@ -3,28 +3,32 @@ #include "git2/common.h" - typedef int (*git_vector_cmp)(const void *, const void *); -typedef int (*git_vector_srch)(const void *, const void *); typedef struct git_vector { unsigned int _alloc_size; git_vector_cmp _cmp; - git_vector_srch _srch; - void **contents; unsigned int length; + int sorted; } git_vector; - -int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp, git_vector_srch srch); +int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp); void git_vector_free(git_vector *v); void git_vector_clear(git_vector *v); -int git_vector_search(git_vector *v, const void *key); +int git_vector_search(git_vector *v, const void *entry); +int git_vector_search2(git_vector *v, git_vector_cmp cmp, const void *key); + +int git_vector_bsearch(git_vector *v, const void *entry); +int git_vector_bsearch2(git_vector *v, git_vector_cmp cmp, const void *key); + void git_vector_sort(git_vector *v); -void *git_vector_get(git_vector *v, unsigned int position); +GIT_INLINE(void *) git_vector_get(git_vector *v, unsigned int position) +{ + return (position < v->length) ? v->contents[position] : NULL; +} int git_vector_insert(git_vector *v, void *element); int git_vector_remove(git_vector *v, unsigned int idx); diff --git a/vendor/libgit2/src/win32/dir.c b/vendor/libgit2/src/win32/dir.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/win32/fileops.c b/vendor/libgit2/src/win32/fileops.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/src/win32/map.c b/vendor/libgit2/src/win32/map.c old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/.gitignore b/vendor/libgit2/tests/.gitignore old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/NAMING b/vendor/libgit2/tests/NAMING old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/big.index b/vendor/libgit2/tests/resources/big.index new file mode 100644 index 000000000..66932f14b Binary files /dev/null and b/vendor/libgit2/tests/resources/big.index differ diff --git a/vendor/libgit2/tests/resources/gitgit.index b/vendor/libgit2/tests/resources/gitgit.index old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/HEAD b/vendor/libgit2/tests/resources/testrepo.git/HEAD old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/head-tracker b/vendor/libgit2/tests/resources/testrepo.git/head-tracker old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/index b/vendor/libgit2/tests/resources/testrepo.git/index old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 b/vendor/libgit2/tests/resources/testrepo.git/objects/13/85f264afb75a56a5bec74243be9b367ba4ca08 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 b/vendor/libgit2/tests/resources/testrepo.git/objects/18/1037049a54a1eb5fab404658a3a250b44335d7 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd b/vendor/libgit2/tests/resources/testrepo.git/objects/18/10dff58d8a660512d4832e740f692884338ccd old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 b/vendor/libgit2/tests/resources/testrepo.git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 b/vendor/libgit2/tests/resources/testrepo.git/objects/4a/202b346bb0fb0db7eff3cffeb3c70babbd2045 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 b/vendor/libgit2/tests/resources/testrepo.git/objects/5b/5b025afb0b4c913b4c338a42934a3863bf3644 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a b/vendor/libgit2/tests/resources/testrepo.git/objects/75/057dd4114e74cca1d750d0aee1647c903cb60a old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/7b/4384978d2493e851f9cca7858815fac9b10980 b/vendor/libgit2/tests/resources/testrepo.git/objects/7b/4384978d2493e851f9cca7858815fac9b10980 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d b/vendor/libgit2/tests/resources/testrepo.git/objects/81/4889a078c031f61ed08ab5fa863aea9314344d old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 b/vendor/libgit2/tests/resources/testrepo.git/objects/84/96071c1b46c854b31185ea97743be6a8774479 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a b/vendor/libgit2/tests/resources/testrepo.git/objects/9f/d738e8f7967c078dceed8190330fc8648ee56a old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f b/vendor/libgit2/tests/resources/testrepo.git/objects/a4/a7dce85cf63874e984719f4fdd239f5145052f old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd b/vendor/libgit2/tests/resources/testrepo.git/objects/a7/1586c1dfe8a71c6cbf6c129f404c5642ff31bd old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 b/vendor/libgit2/tests/resources/testrepo.git/objects/a8/233120f6ad708f843d861ce2b7228ec4e3dec6 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/b2/5fa35b38051e4ae45d4222e795f9df2e43f1d1 b/vendor/libgit2/tests/resources/testrepo.git/objects/b2/5fa35b38051e4ae45d4222e795f9df2e43f1d1 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 b/vendor/libgit2/tests/resources/testrepo.git/objects/be/3563ae3f795b2b4353bcce3a527ad0a4f7f644 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd b/vendor/libgit2/tests/resources/testrepo.git/objects/c4/7800c7266a2be04c571c04d5a6614691ea99bd old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 b/vendor/libgit2/tests/resources/testrepo.git/objects/e6/9de29bb2d1d6434b8b29ae775ad8c2e48c5391 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 b/vendor/libgit2/tests/resources/testrepo.git/objects/f6/0079018b664e4e79329a7ef9559c8d9e0378d1 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 b/vendor/libgit2/tests/resources/testrepo.git/objects/fa/49b077972391ad58037050f2a75f74e3671e92 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 b/vendor/libgit2/tests/resources/testrepo.git/objects/fd/093bff70906175335656e6ce6ae05783708765 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.idx old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-a81e489679b7d3418f9ab594bda8ceb37dd4c695.pack old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.idx old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d7c6adf9f61318f041845b01440d09aa7a91e1b5.pack old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.idx old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.pack b/vendor/libgit2/tests/resources/testrepo.git/objects/pack/pack-d85f5d483273108c9d8dd0e4728ccf0b2982423a.pack old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/packed-refs b/vendor/libgit2/tests/resources/testrepo.git/packed-refs old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/heads/br2 b/vendor/libgit2/tests/resources/testrepo.git/refs/heads/br2 old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/heads/master b/vendor/libgit2/tests/resources/testrepo.git/refs/heads/master old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/heads/packed-test b/vendor/libgit2/tests/resources/testrepo.git/refs/heads/packed-test old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/heads/test b/vendor/libgit2/tests/resources/testrepo.git/refs/heads/test old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/tags/test b/vendor/libgit2/tests/resources/testrepo.git/refs/tags/test old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/resources/testrepo.git/refs/tags/very-simple b/vendor/libgit2/tests/resources/testrepo.git/refs/tags/very-simple old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/t00-core.c b/vendor/libgit2/tests/t00-core.c old mode 100755 new mode 100644 index f20aa9d76..1f6c06a95 --- a/vendor/libgit2/tests/t00-core.c +++ b/vendor/libgit2/tests/t00-core.c @@ -27,10 +27,10 @@ #include "vector.h" #include "fileops.h" -BEGIN_TEST("refcnt", init_inc2_dec2_free) +BEGIN_TEST(refcnt0, "increment refcount twice, decrement twice") git_refcnt p; - gitrc_init(&p); + gitrc_init(&p, 0); gitrc_inc(&p); gitrc_inc(&p); must_be_true(!gitrc_dec(&p)); @@ -38,7 +38,7 @@ BEGIN_TEST("refcnt", init_inc2_dec2_free) gitrc_free(&p); END_TEST -BEGIN_TEST("strutil", prefix_comparison) +BEGIN_TEST(string0, "compare prefixes") must_be_true(git__prefixcmp("", "") == 0); must_be_true(git__prefixcmp("a", "") == 0); must_be_true(git__prefixcmp("", "a") < 0); @@ -49,7 +49,7 @@ BEGIN_TEST("strutil", prefix_comparison) must_be_true(git__prefixcmp("ab", "aa") > 0); END_TEST -BEGIN_TEST("strutil", suffix_comparison) +BEGIN_TEST(string1, "compare suffixes") must_be_true(git__suffixcmp("", "") == 0); must_be_true(git__suffixcmp("a", "") == 0); must_be_true(git__suffixcmp("", "a") < 0); @@ -60,7 +60,31 @@ BEGIN_TEST("strutil", suffix_comparison) must_be_true(git__suffixcmp("zaz", "ac") > 0); END_TEST -BEGIN_TEST("strutil", dirname) + +BEGIN_TEST(vector0, "initial size of 1 would cause writing past array bounds") + git_vector x; + int i; + git_vector_init(&x, 1, NULL); + for (i = 0; i < 10; ++i) { + git_vector_insert(&x, (void*) 0xabc); + } + git_vector_free(&x); +END_TEST + +BEGIN_TEST(vector1, "don't read past array bounds on remove()") + git_vector x; + // make initial capacity exact for our insertions. + git_vector_init(&x, 3, NULL); + git_vector_insert(&x, (void*) 0xabc); + git_vector_insert(&x, (void*) 0xdef); + git_vector_insert(&x, (void*) 0x123); + + git_vector_remove(&x, 0); // used to read past array bounds. + git_vector_free(&x); +END_TEST + + +BEGIN_TEST(path0, "get the dirname of a path") char dir[64], *dir2; #define DIRNAME_TEST(A, B) { \ @@ -78,14 +102,18 @@ BEGIN_TEST("strutil", dirname) DIRNAME_TEST("/usr", "/"); DIRNAME_TEST("/usr/", "/"); DIRNAME_TEST("/usr/lib", "/usr"); + DIRNAME_TEST("/usr/lib/", "/usr"); + DIRNAME_TEST("/usr/lib//", "/usr"); DIRNAME_TEST("usr/lib", "usr"); + DIRNAME_TEST("usr/lib/", "usr"); + DIRNAME_TEST("usr/lib//", "usr"); DIRNAME_TEST(".git/", "."); #undef DIRNAME_TEST END_TEST -BEGIN_TEST("strutil", basename) +BEGIN_TEST(path1, "get the base name of a path") char base[64], *base2; #define BASENAME_TEST(A, B) { \ @@ -103,13 +131,14 @@ BEGIN_TEST("strutil", basename) BASENAME_TEST("/usr", "usr"); BASENAME_TEST("/usr/", "usr"); BASENAME_TEST("/usr/lib", "lib"); + BASENAME_TEST("/usr/lib//", "lib"); BASENAME_TEST("usr/lib", "lib"); #undef BASENAME_TEST END_TEST -BEGIN_TEST("strutil", topdir) +BEGIN_TEST(path2, "get the latest component in a path") const char *dir; #define TOPDIR_TEST(A, B) { \ @@ -133,32 +162,6 @@ BEGIN_TEST("strutil", topdir) #undef TOPDIR_TEST END_TEST -/* Initial size of 1 will cause writing past array bounds prior to fix */ -BEGIN_TEST("vector", initial_size_one) - git_vector x; - int i; - git_vector_init(&x, 1, NULL, NULL); - for (i = 0; i < 10; ++i) { - git_vector_insert(&x, (void*) 0xabc); - } - git_vector_free(&x); -END_TEST - -/* vector used to read past array bounds on remove() */ -BEGIN_TEST("vector", remove) - git_vector x; - // make initial capacity exact for our insertions. - git_vector_init(&x, 3, NULL, NULL); - git_vector_insert(&x, (void*) 0xabc); - git_vector_insert(&x, (void*) 0xdef); - git_vector_insert(&x, (void*) 0x123); - - git_vector_remove(&x, 0); // used to read past array bounds. - git_vector_free(&x); -END_TEST - - - typedef int (normalize_path)(char *, const char *); static int ensure_normalized(const char *input_path, const char *expected_path, normalize_path normalizer) @@ -189,7 +192,7 @@ static int ensure_file_path_normalized(const char *input_path, const char *expec return ensure_normalized(input_path, expected_path, gitfo_prettify_file_path); } -BEGIN_TEST("path", file_path_prettifying) +BEGIN_TEST(path3, "prettify and validate a path to a file") must_pass(ensure_file_path_normalized("a", "a")); must_pass(ensure_file_path_normalized("./testrepo.git", "testrepo.git")); must_pass(ensure_file_path_normalized("./.git", ".git")); @@ -269,7 +272,7 @@ BEGIN_TEST("path", file_path_prettifying) must_fail(ensure_file_path_normalized("/d1/.../d2", NULL)); END_TEST -BEGIN_TEST("path", dir_path_prettifying) +BEGIN_TEST(path4, "validate and prettify a path to a folder") must_pass(ensure_dir_path_normalized("./testrepo.git", "testrepo.git/")); must_pass(ensure_dir_path_normalized("./.git", ".git/")); must_pass(ensure_dir_path_normalized("./git.", "git./")); @@ -344,25 +347,17 @@ END_TEST static int ensure_joinpath(const char *path_a, const char *path_b, const char *expected_path) { - int error = GIT_SUCCESS; - char* joined_path; - - joined_path = git__joinpath(path_a, path_b); - if (joined_path == NULL) - return GIT_ERROR; - - if (strcmp(joined_path, expected_path)) - error = GIT_ERROR; - - free(joined_path); - - return error; + char joined_path[GIT_PATH_MAX]; + git__joinpath(joined_path, path_a, path_b); + return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR; } -BEGIN_TEST("path", joinpath) +BEGIN_TEST(path5, "properly join path components") must_pass(ensure_joinpath("", "", "")); must_pass(ensure_joinpath("", "a", "a")); - must_pass(ensure_joinpath("a", "", "a")); + must_pass(ensure_joinpath("", "/a", "/a")); + must_pass(ensure_joinpath("a", "", "a/")); + must_pass(ensure_joinpath("a", "/", "a/")); must_pass(ensure_joinpath("a", "b", "a/b")); must_pass(ensure_joinpath("/", "a", "/a")); must_pass(ensure_joinpath("/", "", "/")); @@ -372,6 +367,22 @@ BEGIN_TEST("path", joinpath) must_pass(ensure_joinpath("/a/", "/b/", "/a/b/")); END_TEST +static int ensure_joinpath_n(const char *path_a, const char *path_b, const char *path_c, const char *path_d, const char *expected_path) +{ + char joined_path[GIT_PATH_MAX]; + git__joinpath_n(joined_path, 4, path_a, path_b, path_c, path_d); + return strcmp(joined_path, expected_path) == 0 ? GIT_SUCCESS : GIT_ERROR; +} + +BEGIN_TEST(path6, "properly join path components for more than one path") + must_pass(ensure_joinpath_n("", "", "", "", "")); + must_pass(ensure_joinpath_n("", "a", "", "", "a/")); + must_pass(ensure_joinpath_n("a", "", "", "", "a/")); + must_pass(ensure_joinpath_n("", "", "", "a", "a")); + must_pass(ensure_joinpath_n("a", "b", "", "/c/d/", "a/b/c/d/")); + must_pass(ensure_joinpath_n("a", "b", "", "/c/d", "a/b/c/d")); +END_TEST + typedef struct name_data { int count; /* return count */ char *name; /* filename */ @@ -493,7 +504,7 @@ static walk_data dot = { dot_names }; -BEGIN_TEST("dirent", dot) +BEGIN_TEST(dirent0, "make sure that the '.' folder is not traversed") must_pass(setup(&dot)); @@ -518,7 +529,7 @@ static walk_data sub = { sub_names }; -BEGIN_TEST("dirent", sub) +BEGIN_TEST(dirent1, "traverse a subfolder") must_pass(setup(&sub)); @@ -537,7 +548,7 @@ static walk_data sub_slash = { sub_names }; -BEGIN_TEST("dirent", sub_slash) +BEGIN_TEST(dirent2, "traverse a slash-terminated subfolder") must_pass(setup(&sub_slash)); @@ -566,7 +577,7 @@ static int dont_call_me(void *GIT_UNUSED(state), char *GIT_UNUSED(path)) return GIT_ERROR; } -BEGIN_TEST("dirent", empty) +BEGIN_TEST(dirent3, "make sure that empty folders are not traversed") must_pass(setup(&empty)); @@ -599,7 +610,7 @@ static walk_data odd = { odd_names }; -BEGIN_TEST("dirent", odd) +BEGIN_TEST(dirent4, "make sure that strange looking filenames ('..c') are traversed") must_pass(setup(&odd)); @@ -614,30 +625,26 @@ BEGIN_TEST("dirent", odd) END_TEST -git_testsuite *libgit2_suite_core(void) -{ - git_testsuite *suite = git_testsuite_new("Core"); +BEGIN_SUITE(core) + ADD_TEST(refcnt0); - ADD_TEST(suite, "refcnt", init_inc2_dec2_free); + ADD_TEST(string0); + ADD_TEST(string1); - ADD_TEST(suite, "strutil", prefix_comparison); - ADD_TEST(suite, "strutil", suffix_comparison); - ADD_TEST(suite, "strutil", dirname); - ADD_TEST(suite, "strutil", basename); - ADD_TEST(suite, "strutil", topdir); + ADD_TEST(vector0); + ADD_TEST(vector1); - ADD_TEST(suite, "vector", initial_size_one); - ADD_TEST(suite, "vector", remove); + ADD_TEST(path0); + ADD_TEST(path1); + ADD_TEST(path2); + ADD_TEST(path3); + ADD_TEST(path4); + ADD_TEST(path5); + ADD_TEST(path6); - ADD_TEST(suite, "path", file_path_prettifying); - ADD_TEST(suite, "path", dir_path_prettifying); - ADD_TEST(suite, "path", joinpath); - - ADD_TEST(suite, "dirent", dot); - ADD_TEST(suite, "dirent", sub); - ADD_TEST(suite, "dirent", sub_slash); - ADD_TEST(suite, "dirent", empty); - ADD_TEST(suite, "dirent", odd); - - return suite; -} + ADD_TEST(dirent0); + ADD_TEST(dirent1); + ADD_TEST(dirent2); + ADD_TEST(dirent3); + ADD_TEST(dirent4); +END_SUITE diff --git a/vendor/libgit2/tests/t01-data.h b/vendor/libgit2/tests/t01-data.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/t01-rawobj.c b/vendor/libgit2/tests/t01-rawobj.c old mode 100755 new mode 100644 index 51a794214..cc4641589 --- a/vendor/libgit2/tests/t01-rawobj.c +++ b/vendor/libgit2/tests/t01-rawobj.c @@ -27,7 +27,7 @@ #include "hash.h" -BEGIN_TEST("oid", oid_szs) +BEGIN_TEST(oid0, "validate size of oid objects") git_oid out; must_be_true(20 == GIT_OID_RAWSZ); must_be_true(40 == GIT_OID_HEXSZ); @@ -35,12 +35,12 @@ BEGIN_TEST("oid", oid_szs) must_be_true(sizeof(out.id) == GIT_OID_RAWSZ); END_TEST -BEGIN_TEST("oid", empty_string) +BEGIN_TEST(oid1, "fail when parsing an empty string as oid") git_oid out; must_fail(git_oid_mkstr(&out, "")); END_TEST -BEGIN_TEST("oid", invalid_string_moo) +BEGIN_TEST(oid2, "fail when parsing an invalid string as oid") git_oid out; must_fail(git_oid_mkstr(&out, "moo")); END_TEST @@ -56,7 +56,7 @@ static int from_hex(unsigned int i) return -1; } -BEGIN_TEST("oid", invalid_string_all_chars) +BEGIN_TEST(oid3, "find all invalid characters when parsing an oid") git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -80,12 +80,12 @@ BEGIN_TEST("oid", invalid_string_all_chars) } END_TEST -BEGIN_TEST("oid", invalid_string_16a67770b7d8d72317c4b775213c23a8bd74f5ez) +BEGIN_TEST(oid4, "fail when parsing an invalid oid string") git_oid out; must_fail(git_oid_mkstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez")); END_TEST -BEGIN_TEST("oid", valid_string_16a67770b7d8d72317c4b775213c23a8bd74f5e0) +BEGIN_TEST(oid5, "succeed when parsing a valid oid string") git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -101,7 +101,7 @@ BEGIN_TEST("oid", valid_string_16a67770b7d8d72317c4b775213c23a8bd74f5e0) must_pass(memcmp(out.id, exp, sizeof(out.id))); END_TEST -BEGIN_TEST("oid", valid_raw) +BEGIN_TEST(oid6, "build a valid oid from raw bytes") git_oid out; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -114,7 +114,7 @@ BEGIN_TEST("oid", valid_raw) must_pass(memcmp(out.id, exp, sizeof(out.id))); END_TEST -BEGIN_TEST("oid", copy_oid) +BEGIN_TEST(oid7, "properly copy an oid to another") git_oid a, b; unsigned char exp[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -129,7 +129,7 @@ BEGIN_TEST("oid", copy_oid) must_pass(memcmp(a.id, exp, sizeof(a.id))); END_TEST -BEGIN_TEST("oid", cmp_oid_lt) +BEGIN_TEST(oid8, "compare two oids (lesser than)") git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -149,7 +149,7 @@ BEGIN_TEST("oid", cmp_oid_lt) must_be_true(git_oid_cmp(&a, &b) < 0); END_TEST -BEGIN_TEST("oid", cmp_oid_eq) +BEGIN_TEST(oid9, "compare two oids (equal)") git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -163,7 +163,7 @@ BEGIN_TEST("oid", cmp_oid_eq) must_be_true(git_oid_cmp(&a, &b) == 0); END_TEST -BEGIN_TEST("oid", cmp_oid_gt) +BEGIN_TEST(oid10, "compare two oids (greater than)") git_oid a, b; unsigned char a_in[] = { 0x16, 0xa6, 0x77, 0x70, 0xb7, @@ -183,7 +183,7 @@ BEGIN_TEST("oid", cmp_oid_gt) must_be_true(git_oid_cmp(&a, &b) > 0); END_TEST -BEGIN_TEST("oid", cmp_oid_fmt) +BEGIN_TEST(oid11, "compare formated oids") const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char out[GIT_OID_HEXSZ + 1]; @@ -200,7 +200,7 @@ BEGIN_TEST("oid", cmp_oid_fmt) must_pass(strcmp(exp, out)); END_TEST -BEGIN_TEST("oid", cmp_oid_allocfmt) +BEGIN_TEST(oid12, "compare oids (allocate + format)") const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char *out; @@ -213,7 +213,7 @@ BEGIN_TEST("oid", cmp_oid_allocfmt) free(out); END_TEST -BEGIN_TEST("oid", cmp_oid_pathfmt) +BEGIN_TEST(oid13, "compare oids (path format)") const char *exp1 = "16a0123456789abcdef4b775213c23a8bd74f5e0"; const char *exp2 = "16/a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; @@ -231,7 +231,7 @@ BEGIN_TEST("oid", cmp_oid_pathfmt) must_pass(strcmp(exp2, out)); END_TEST -BEGIN_TEST("oid", oid_to_string) +BEGIN_TEST(oid14, "convert raw oid to string") const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char out[GIT_OID_HEXSZ + 1]; @@ -275,7 +275,7 @@ BEGIN_TEST("oid", oid_to_string) must_pass(strcmp(exp, out)); END_TEST -BEGIN_TEST("oid", oid_to_string_big) +BEGIN_TEST(oid15, "convert raw oid to string (big)") const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0"; git_oid in; char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */ @@ -306,7 +306,7 @@ static char *hello_text = "hello world\n"; static char *bye_id = "ce08fe4884650f067bd5703b6a59a8b3b3c99a09"; static char *bye_text = "bye world\n"; -BEGIN_TEST("hash", hash_iuf) +BEGIN_TEST(hash0, "normal hash by blocks") git_hash_ctx *ctx; git_oid id1, id2; @@ -328,7 +328,7 @@ BEGIN_TEST("hash", hash_iuf) git_hash_free_ctx(ctx); END_TEST -BEGIN_TEST("hash", hash_buf) +BEGIN_TEST(hash1, "hash whole buffer in a single call") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, hello_id)); @@ -338,7 +338,7 @@ BEGIN_TEST("hash", hash_buf) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("hash", hash_vec) +BEGIN_TEST(hash2, "hash a vector") git_oid id1, id2; git_buf_vec vec[2]; @@ -354,7 +354,7 @@ BEGIN_TEST("hash", hash_vec) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objtype", type_to_string) +BEGIN_TEST(objtype0, "convert type to string") must_be_true(!strcmp(git_object_type2string(GIT_OBJ_BAD), "")); must_be_true(!strcmp(git_object_type2string(GIT_OBJ__EXT1), "")); must_be_true(!strcmp(git_object_type2string(GIT_OBJ_COMMIT), "commit")); @@ -370,7 +370,7 @@ BEGIN_TEST("objtype", type_to_string) must_be_true(!strcmp(git_object_type2string(1234), "")); END_TEST -BEGIN_TEST("objtype", string_to_type) +BEGIN_TEST(objtype1, "convert string to type") must_be_true(git_object_string2type(NULL) == GIT_OBJ_BAD); must_be_true(git_object_string2type("") == GIT_OBJ_BAD); must_be_true(git_object_string2type("commit") == GIT_OBJ_COMMIT); @@ -384,7 +384,7 @@ BEGIN_TEST("objtype", string_to_type) must_be_true(git_object_string2type("hohoho") == GIT_OBJ_BAD); END_TEST -BEGIN_TEST("objtype", loose_object) +BEGIN_TEST(objtype2, "check if an object type is loose") must_be_true(git_object_typeisloose(GIT_OBJ_BAD) == 0); must_be_true(git_object_typeisloose(GIT_OBJ__EXT1) == 0); must_be_true(git_object_typeisloose(GIT_OBJ_COMMIT) == 1); @@ -400,7 +400,7 @@ BEGIN_TEST("objtype", loose_object) must_be_true(git_object_typeisloose(1234) == 0); END_TEST -BEGIN_TEST("objhash", hash_junk) +BEGIN_TEST(objhash0, "hash junk data") git_oid id, id_zero; must_pass(git_oid_mkstr(&id_zero, zero_id)); @@ -431,7 +431,7 @@ BEGIN_TEST("objhash", hash_junk) must_fail(git_rawobj_hash(&id, &junk_obj)); END_TEST -BEGIN_TEST("objhash", hash_commit) +BEGIN_TEST(objhash1, "hash a commit object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, commit_id)); @@ -441,7 +441,7 @@ BEGIN_TEST("objhash", hash_commit) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_tree) +BEGIN_TEST(objhash2, "hash a tree object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, tree_id)); @@ -451,7 +451,7 @@ BEGIN_TEST("objhash", hash_tree) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_tag) +BEGIN_TEST(objhash3, "hash a tag object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, tag_id)); @@ -461,7 +461,7 @@ BEGIN_TEST("objhash", hash_tag) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_zero) +BEGIN_TEST(objhash4, "hash a zero-length object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, zero_id)); @@ -471,7 +471,7 @@ BEGIN_TEST("objhash", hash_zero) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_one) +BEGIN_TEST(objhash5, "hash an one-byte long object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, one_id)); @@ -481,7 +481,7 @@ BEGIN_TEST("objhash", hash_one) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_two) +BEGIN_TEST(objhash6, "hash a two-byte long object") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, two_id)); @@ -491,7 +491,7 @@ BEGIN_TEST("objhash", hash_two) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST -BEGIN_TEST("objhash", hash_some) +BEGIN_TEST(objhash7, "hash an object several bytes long") git_oid id1, id2; must_pass(git_oid_mkstr(&id1, some_id)); @@ -501,46 +501,39 @@ BEGIN_TEST("objhash", hash_some) must_be_true(git_oid_cmp(&id1, &id2) == 0); END_TEST - -git_testsuite *libgit2_suite_rawobjects(void) -{ - git_testsuite *suite = git_testsuite_new("Raw Objects"); - - ADD_TEST(suite, "hash", hash_iuf); - ADD_TEST(suite, "hash", hash_buf); - ADD_TEST(suite, "hash", hash_vec); - - ADD_TEST(suite, "oid", oid_szs); - ADD_TEST(suite, "oid", empty_string); - ADD_TEST(suite, "oid", invalid_string_moo); - ADD_TEST(suite, "oid", invalid_string_all_chars); - ADD_TEST(suite, "oid", invalid_string_16a67770b7d8d72317c4b775213c23a8bd74f5ez); - ADD_TEST(suite, "oid", valid_string_16a67770b7d8d72317c4b775213c23a8bd74f5e0); - ADD_TEST(suite, "oid", valid_raw); - ADD_TEST(suite, "oid", copy_oid); - ADD_TEST(suite, "oid", cmp_oid_lt); - ADD_TEST(suite, "oid", cmp_oid_eq); - ADD_TEST(suite, "oid", cmp_oid_gt); - ADD_TEST(suite, "oid", cmp_oid_fmt); - ADD_TEST(suite, "oid", cmp_oid_allocfmt); - ADD_TEST(suite, "oid", cmp_oid_pathfmt); - ADD_TEST(suite, "oid", oid_to_string); - ADD_TEST(suite, "oid", oid_to_string_big); - - ADD_TEST(suite, "objtype", type_to_string); - ADD_TEST(suite, "objtype", string_to_type); - ADD_TEST(suite, "objtype", loose_object); - - ADD_TEST(suite, "objhash", hash_junk); - ADD_TEST(suite, "objhash", hash_commit); - ADD_TEST(suite, "objhash", hash_tree); - ADD_TEST(suite, "objhash", hash_tag); - ADD_TEST(suite, "objhash", hash_zero); - ADD_TEST(suite, "objhash", hash_one); - ADD_TEST(suite, "objhash", hash_two); - ADD_TEST(suite, "objhash", hash_some); - - return suite; -} - +BEGIN_SUITE(rawobjects) + ADD_TEST(oid0); + ADD_TEST(oid1); + ADD_TEST(oid2); + ADD_TEST(oid3); + ADD_TEST(oid4); + ADD_TEST(oid5); + ADD_TEST(oid6); + ADD_TEST(oid7); + ADD_TEST(oid8); + ADD_TEST(oid9); + ADD_TEST(oid10); + ADD_TEST(oid11); + ADD_TEST(oid12); + ADD_TEST(oid13); + ADD_TEST(oid14); + ADD_TEST(oid15); + + ADD_TEST(hash0); + ADD_TEST(hash1); + ADD_TEST(hash2); + + ADD_TEST(objtype0); + ADD_TEST(objtype1); + ADD_TEST(objtype2); + + ADD_TEST(objhash0); + ADD_TEST(objhash1); + ADD_TEST(objhash2); + ADD_TEST(objhash3); + ADD_TEST(objhash4); + ADD_TEST(objhash5); + ADD_TEST(objhash6); + ADD_TEST(objhash7); +END_SUITE diff --git a/vendor/libgit2/tests/t02-data.h b/vendor/libgit2/tests/t02-data.h old mode 100755 new mode 100644 index 456be5002..705a2d7af --- a/vendor/libgit2/tests/t02-data.h +++ b/vendor/libgit2/tests/t02-data.h @@ -23,25 +23,6 @@ static object_data one = { }; -BEGIN_TEST("existsloose", exists_loose_one) - git_odb *db; - git_oid id, id2; - - must_pass(write_object_files(odb_dir, &one)); - must_pass(git_odb_open(&db, odb_dir)); - must_pass(git_oid_mkstr(&id, one.id)); - - must_be_true(git_odb_exists(db, &id)); - - /* Test for a non-existant object */ - must_pass(git_oid_mkstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa")); - must_be_true(0 == git_odb_exists(db, &id2)); - - git_odb_close(db); - must_pass(remove_object_files(odb_dir, &one)); -END_TEST - - /* commit == 3d7f8a6af076c8c3f20071a8935cdbe8228594d1 */ static unsigned char commit_bytes[] = { 0x78, 0x01, 0x85, 0x50, 0xc1, 0x6a, 0xc3, 0x30, diff --git a/vendor/libgit2/tests/t02-objread.c b/vendor/libgit2/tests/t02-objread.c old mode 100755 new mode 100644 index 1b2e2d56b..2a9d130c4 --- a/vendor/libgit2/tests/t02-objread.c +++ b/vendor/libgit2/tests/t02-objread.c @@ -28,7 +28,26 @@ #include "t02-data.h" #include "t02-oids.h" -BEGIN_TEST("readloose", read_loose_commit) + +BEGIN_TEST(existsloose0, "check if a loose object exists on the odb") + git_odb *db; + git_oid id, id2; + + must_pass(write_object_files(odb_dir, &one)); + must_pass(git_odb_open(&db, odb_dir)); + must_pass(git_oid_mkstr(&id, one.id)); + + must_be_true(git_odb_exists(db, &id)); + + /* Test for a non-existant object */ + must_pass(git_oid_mkstr(&id2, "8b137891791fe96927ad78e64b0aad7bded08baa")); + must_be_true(0 == git_odb_exists(db, &id2)); + + git_odb_close(db); + must_pass(remove_object_files(odb_dir, &one)); +END_TEST + +BEGIN_TEST(readloose0, "read a loose commit") git_odb *db; git_oid id; git_rawobj obj; @@ -45,7 +64,7 @@ BEGIN_TEST("readloose", read_loose_commit) must_pass(remove_object_files(odb_dir, &commit)); END_TEST -BEGIN_TEST("readloose", read_loose_tree) +BEGIN_TEST(readloose1, "read a loose tree") git_odb *db; git_oid id; git_rawobj obj; @@ -62,7 +81,7 @@ BEGIN_TEST("readloose", read_loose_tree) must_pass(remove_object_files(odb_dir, &tree)); END_TEST -BEGIN_TEST("readloose", read_loose_tag) +BEGIN_TEST(readloose2, "read a loose tag") git_odb *db; git_oid id; git_rawobj obj; @@ -79,7 +98,7 @@ BEGIN_TEST("readloose", read_loose_tag) must_pass(remove_object_files(odb_dir, &tag)); END_TEST -BEGIN_TEST("readloose", read_loose_zero) +BEGIN_TEST(readloose3, "read a loose zero-bytes object") git_odb *db; git_oid id; git_rawobj obj; @@ -96,7 +115,7 @@ BEGIN_TEST("readloose", read_loose_zero) must_pass(remove_object_files(odb_dir, &zero)); END_TEST -BEGIN_TEST("readloose", read_loose_one) +BEGIN_TEST(readloose4, "read a one-byte long loose object") git_odb *db; git_oid id; git_rawobj obj; @@ -113,7 +132,7 @@ BEGIN_TEST("readloose", read_loose_one) must_pass(remove_object_files(odb_dir, &one)); END_TEST -BEGIN_TEST("readloose", read_loose_two) +BEGIN_TEST(readloose5, "read a two-bytes long loose object") git_odb *db; git_oid id; git_rawobj obj; @@ -130,7 +149,7 @@ BEGIN_TEST("readloose", read_loose_two) must_pass(remove_object_files(odb_dir, &two)); END_TEST -BEGIN_TEST("readloose", read_loose_some) +BEGIN_TEST(readloose6, "read a loose object which is several bytes long") git_odb *db; git_oid id; git_rawobj obj; @@ -147,7 +166,7 @@ BEGIN_TEST("readloose", read_loose_some) must_pass(remove_object_files(odb_dir, &some)); END_TEST -BEGIN_TEST("readpack", readpacked_test) +BEGIN_TEST(readpack0, "read several packed objects") unsigned int i; git_odb *db; @@ -167,7 +186,7 @@ BEGIN_TEST("readpack", readpacked_test) git_odb_close(db); END_TEST -BEGIN_TEST("readheader", readheader_packed_test) +BEGIN_TEST(readheader0, "read only the header of several packed objects") unsigned int i; git_odb *db; @@ -191,7 +210,7 @@ BEGIN_TEST("readheader", readheader_packed_test) git_odb_close(db); END_TEST -BEGIN_TEST("readheader", readheader_loose_test) +BEGIN_TEST(readheader1, "read only the header of several loose objects") unsigned int i; git_odb *db; @@ -217,36 +236,29 @@ BEGIN_TEST("readheader", readheader_loose_test) git_odb_close(db); END_TEST -git_testsuite *libgit2_suite_objread(void) -{ - git_testsuite *suite = git_testsuite_new("Object Read"); - - ADD_TEST(suite, "existsloose", exists_loose_one); +BEGIN_SUITE(objread) + ADD_TEST(existsloose0); - ADD_TEST(suite, "readloose", read_loose_commit); - ADD_TEST(suite, "readloose", read_loose_tree); - ADD_TEST(suite, "readloose", read_loose_tag); - ADD_TEST(suite, "readloose", read_loose_zero); - ADD_TEST(suite, "readloose", read_loose_one); - ADD_TEST(suite, "readloose", read_loose_two); - ADD_TEST(suite, "readloose", read_loose_some); + ADD_TEST(readloose0); + ADD_TEST(readloose1); + ADD_TEST(readloose2); + ADD_TEST(readloose3); + ADD_TEST(readloose4); + ADD_TEST(readloose5); + ADD_TEST(readloose6); - /* TODO: import these (naming conflicts) */ /* - ADD_TEST(suite, "readloose", read_loose_commit_enc); - ADD_TEST(suite, "readloose", read_loose_tree_enc); - ADD_TEST(suite, "readloose", read_loose_tag_enc); - ADD_TEST(suite, "readloose", read_loose_zero_enc); - ADD_TEST(suite, "readloose", read_loose_one_enc); - ADD_TEST(suite, "readloose", read_loose_two_enc); - ADD_TEST(suite, "readloose", read_loose_some_enc); + ADD_TEST(readloose_enc0); + ADD_TEST(readloose_enc1); + ADD_TEST(readloose_enc2); + ADD_TEST(readloose_enc3); + ADD_TEST(readloose_enc4); + ADD_TEST(readloose_enc5); + ADD_TEST(readloose_enc6); */ - ADD_TEST(suite, "readpack", readpacked_test); - - ADD_TEST(suite, "readheader", readheader_packed_test); - ADD_TEST(suite, "readheader", readheader_loose_test); - + ADD_TEST(readpack0); - return suite; -} + ADD_TEST(readheader0); + ADD_TEST(readheader1); +END_SUITE diff --git a/vendor/libgit2/tests/t02-oids.h b/vendor/libgit2/tests/t02-oids.h old mode 100755 new mode 100644 diff --git a/vendor/libgit2/tests/t03-objwrite.c b/vendor/libgit2/tests/t03-objwrite.c old mode 100755 new mode 100644 index 0b9232534..10c6c7f1a --- a/vendor/libgit2/tests/t03-objwrite.c +++ b/vendor/libgit2/tests/t03-objwrite.c @@ -80,7 +80,7 @@ static int remove_object_files(object_data *d) return 0; } -BEGIN_TEST("write", write_commit) +BEGIN_TEST(write0, "write loose commit object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -101,7 +101,7 @@ BEGIN_TEST("write", write_commit) must_pass(remove_object_files(&commit)); END_TEST -BEGIN_TEST("write", write_tree) +BEGIN_TEST(write1, "write loose tree object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -122,7 +122,7 @@ BEGIN_TEST("write", write_tree) must_pass(remove_object_files(&tree)); END_TEST -BEGIN_TEST("write", write_tag) +BEGIN_TEST(write2, "write loose tag object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -143,7 +143,7 @@ BEGIN_TEST("write", write_tag) must_pass(remove_object_files(&tag)); END_TEST -BEGIN_TEST("write", write_zero) +BEGIN_TEST(write3, "write zero-length object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -164,7 +164,7 @@ BEGIN_TEST("write", write_zero) must_pass(remove_object_files(&zero)); END_TEST -BEGIN_TEST("write", write_one) +BEGIN_TEST(write4, "write one-byte long object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -185,7 +185,7 @@ BEGIN_TEST("write", write_one) must_pass(remove_object_files(&one)); END_TEST -BEGIN_TEST("write", write_two) +BEGIN_TEST(write5, "write two-byte long object") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -206,7 +206,7 @@ BEGIN_TEST("write", write_two) must_pass(remove_object_files(&two)); END_TEST -BEGIN_TEST("write", write_some) +BEGIN_TEST(write6, "write an object which is several bytes long") git_odb *db; git_oid id1, id2; git_rawobj obj; @@ -227,18 +227,12 @@ BEGIN_TEST("write", write_some) must_pass(remove_object_files(&some)); END_TEST -git_testsuite *libgit2_suite_objwrite(void) -{ - git_testsuite *suite = git_testsuite_new("Object Write"); - - ADD_TEST(suite, "write", write_commit); - ADD_TEST(suite, "write", write_tree); - ADD_TEST(suite, "write", write_tag); - ADD_TEST(suite, "write", write_zero); - ADD_TEST(suite, "write", write_one); - ADD_TEST(suite, "write", write_two); - ADD_TEST(suite, "write", write_some); - - return suite; -} - +BEGIN_SUITE(objwrite) + ADD_TEST(write0); + ADD_TEST(write1); + ADD_TEST(write2); + ADD_TEST(write3); + ADD_TEST(write4); + ADD_TEST(write5); + ADD_TEST(write6); +END_SUITE diff --git a/vendor/libgit2/tests/t04-commit.c b/vendor/libgit2/tests/t04-commit.c old mode 100755 new mode 100644 index 1e3b45c02..8e62759a8 --- a/vendor/libgit2/tests/t04-commit.c +++ b/vendor/libgit2/tests/t04-commit.c @@ -109,7 +109,7 @@ committer Vicent Marti 1273848544 +0200\n\ a simple commit which works\n", }; -BEGIN_TEST("parse", parse_oid_test) +BEGIN_TEST(parse0, "parse the OID line in a commit") git_oid oid; @@ -151,7 +151,7 @@ BEGIN_TEST("parse", parse_oid_test) END_TEST -BEGIN_TEST("parse", parse_sig_test) +BEGIN_TEST(parse1, "parse the signature line in a commit") #define TEST_SIGNATURE_PASS(_string, _header, _name, _email, _time, _offset) { \ char *ptr = _string; \ @@ -285,7 +285,7 @@ END_TEST /* External declaration for testing the buffer parsing method */ int commit_parse_buffer(git_commit *commit, void *data, size_t len, unsigned int parse_flags); -BEGIN_TEST("parse", parse_buffer_test) +BEGIN_TEST(parse2, "parse a whole commit buffer") const int broken_commit_count = sizeof(test_commits_broken) / sizeof(*test_commits_broken); const int working_commit_count = sizeof(test_commits_working) / sizeof(*test_commits_working); @@ -352,7 +352,7 @@ static const char *commit_ids[] = { "5b5b025afb0b4c913b4c338a42934a3863bf3644", /* 5 */ }; -BEGIN_TEST("details", query_details_test) +BEGIN_TEST(details0, "query the details on a parsed commit") const size_t commit_count = sizeof(commit_ids) / sizeof(const char *); unsigned int i; @@ -407,7 +407,7 @@ This is a commit created in memory and it will be written back to disk\n" static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; -BEGIN_TEST("write", writenew_test) +BEGIN_TEST(write0, "write a new commit object from memory to disk") git_repository *repo; git_commit *commit, *parent; git_tree *tree; @@ -474,7 +474,7 @@ BEGIN_TEST("write", writenew_test) git_repository_free(repo); END_TEST -BEGIN_TEST("write", writeback_test) +BEGIN_TEST(write1, "load a commit object, modify it and write it back") git_repository *repo; git_oid id; git_commit *commit, *parent; @@ -504,16 +504,11 @@ BEGIN_TEST("write", writeback_test) END_TEST -git_testsuite *libgit2_suite_commit(void) -{ - git_testsuite *suite = git_testsuite_new("Commit"); - - ADD_TEST(suite, "parse", parse_oid_test); - ADD_TEST(suite, "parse", parse_sig_test); - ADD_TEST(suite, "parse", parse_buffer_test); - ADD_TEST(suite, "details", query_details_test); - ADD_TEST(suite, "write", writenew_test); - ADD_TEST(suite, "write", writeback_test); - - return suite; -} +BEGIN_SUITE(commit) + ADD_TEST(parse0); + ADD_TEST(parse1); + ADD_TEST(parse2); + ADD_TEST(details0); + ADD_TEST(write0); + ADD_TEST(write1); +END_SUITE diff --git a/vendor/libgit2/tests/t05-revwalk.c b/vendor/libgit2/tests/t05-revwalk.c old mode 100755 new mode 100644 index 473ea3350..fd009fac1 --- a/vendor/libgit2/tests/t05-revwalk.c +++ b/vendor/libgit2/tests/t05-revwalk.c @@ -110,7 +110,7 @@ static int test_walk(git_revwalk *walk, git_commit *start_from, return GIT_ERROR; } -BEGIN_TEST("walk", simple_walk_test) +BEGIN_TEST(walk0, "do a simple walk on a repo with different sorting modes") git_oid id; git_repository *repo; git_revwalk *walk; @@ -145,7 +145,7 @@ BEGIN_TEST("walk", simple_walk_test) git_repository_free(repo); END_TEST -BEGIN_TEST("list", list_timesort_test) +BEGIN_TEST(list0, "check that a commit list is properly sorted by time") git_revwalk_list list; git_revwalk_listnode *n; @@ -210,12 +210,7 @@ BEGIN_TEST("list", list_timesort_test) END_TEST -git_testsuite *libgit2_suite_revwalk(void) -{ - git_testsuite *suite = git_testsuite_new("Revwalk"); - - ADD_TEST(suite, "walk", simple_walk_test); - ADD_TEST(suite, "list", list_timesort_test); - - return suite; -} +BEGIN_SUITE(revwalk) + ADD_TEST(walk0); + ADD_TEST(list0); +END_SUITE diff --git a/vendor/libgit2/tests/t06-index.c b/vendor/libgit2/tests/t06-index.c old mode 100755 new mode 100644 index f46dfb339..19b4da5c2 --- a/vendor/libgit2/tests/t06-index.c +++ b/vendor/libgit2/tests/t06-index.c @@ -45,7 +45,7 @@ struct test_entry TEST_ENTRIES[] = { {48, "src/revobject.h", 1448, 0x4C3F7FE2} }; -BEGIN_TEST("read", index_loadempty_test) +BEGIN_TEST(read0, "load an empty index") git_index *index; must_pass(git_index_open_bare(&index, "in-memory-index")); @@ -55,12 +55,12 @@ BEGIN_TEST("read", index_loadempty_test) must_be_true(index->on_disk == 0); must_be_true(git_index_entrycount(index) == 0); - must_be_true(index->sorted); + must_be_true(index->entries.sorted); git_index_free(index); END_TEST -BEGIN_TEST("read", index_load_test) +BEGIN_TEST(read1, "load a standard index (default test index)") git_index *index; unsigned int i; git_index_entry **entries; @@ -72,7 +72,7 @@ BEGIN_TEST("read", index_load_test) must_be_true(index->on_disk); must_be_true(git_index_entrycount(index) == TEST_INDEX_ENTRY_COUNT); - must_be_true(index->sorted); + must_be_true(index->entries.sorted); entries = (git_index_entry **)index->entries.contents; @@ -87,7 +87,7 @@ BEGIN_TEST("read", index_load_test) git_index_free(index); END_TEST -BEGIN_TEST("read", index2_load_test) +BEGIN_TEST(read2, "load a standard index (git.git index)") git_index *index; must_pass(git_index_open_bare(&index, TEST_INDEX2_PATH)); @@ -97,13 +97,13 @@ BEGIN_TEST("read", index2_load_test) must_be_true(index->on_disk); must_be_true(git_index_entrycount(index) == TEST_INDEX2_ENTRY_COUNT); - must_be_true(index->sorted); + must_be_true(index->entries.sorted); must_be_true(index->tree != NULL); git_index_free(index); END_TEST -BEGIN_TEST("read", index_find_test) +BEGIN_TEST(find0, "find an entry on an index") git_index *index; unsigned int i; @@ -118,7 +118,7 @@ BEGIN_TEST("read", index_find_test) git_index_free(index); END_TEST -BEGIN_TEST("read", index_findempty_test) +BEGIN_TEST(find1, "find an entry in an empty index") git_index *index; unsigned int i; @@ -132,91 +132,57 @@ BEGIN_TEST("read", index_findempty_test) git_index_free(index); END_TEST -BEGIN_TEST("write", index_write_test) +BEGIN_TEST(write0, "write an index back to disk") git_index *index; - git_filelock out_file; - must_pass(git_index_open_bare(&index, TEST_INDEX_PATH)); + must_pass(copy_file(TEST_INDEXBIG_PATH, "index_rewrite")); + + must_pass(git_index_open_bare(&index, "index_rewrite")); must_pass(git_index_read(index)); must_be_true(index->on_disk); - must_pass(git_filelock_init(&out_file, "index_rewrite")); - must_pass(git_filelock_lock(&out_file, 0)); - must_pass(git_index__write(index, &out_file)); - must_pass(git_filelock_commit(&out_file)); + must_pass(git_index_write(index)); + must_pass(cmp_files(TEST_INDEXBIG_PATH, "index_rewrite")); git_index_free(index); gitfo_unlink("index_rewrite"); END_TEST - -static void randomize_entries(git_index *index) -{ - unsigned int i, j; - git_index_entry *tmp; - git_index_entry **entries; - - entries = (git_index_entry **)index->entries.contents; - - srand((unsigned int)time(NULL)); - - for (i = 0; i < index->entries.length; ++i) { - j = rand() % index->entries.length; - - tmp = entries[j]; - entries[j] = entries[i]; - entries[i] = tmp; - } - - index->sorted = 0; -} - -BEGIN_TEST("sort", index_sort_test) - git_index *index; - unsigned int i; - git_index_entry **entries; - - must_pass(git_index_open_bare(&index, TEST_INDEX_PATH)); - must_pass(git_index_read(index)); - - randomize_entries(index); - - git_index__sort(index); - must_be_true(index->sorted); - - entries = (git_index_entry **)index->entries.contents; - - for (i = 1; i < index->entries.length; ++i) - must_be_true(strcmp(entries[i - 1]->path, entries[i]->path) < 0); - - git_index_free(index); +BEGIN_TEST(sort0, "sort the entires in an index") + /* + * TODO: This no longer applies: + * index sorting in Git uses some specific changes to the way + * directories are sorted. + * + * We need to specificially check for this by creating a new + * index, adding entries in random order and then + * checking for consistency + */ END_TEST -BEGIN_TEST("sort", index_sort_empty_test) + +BEGIN_TEST(sort1, "sort the entires in an empty index") git_index *index; must_pass(git_index_open_bare(&index, "fake-index")); - git_index__sort(index); - must_be_true(index->sorted); + /* FIXME: this test is slightly dumb */ + must_be_true(index->entries.sorted); git_index_free(index); END_TEST +BEGIN_SUITE(index) + ADD_TEST(read0); + ADD_TEST(read1); + ADD_TEST(read2); -git_testsuite *libgit2_suite_index(void) -{ - git_testsuite *suite = git_testsuite_new("Index"); + ADD_TEST(find0); + ADD_TEST(find1); - ADD_TEST(suite, "read", index_loadempty_test); - ADD_TEST(suite, "read", index_load_test); - ADD_TEST(suite, "read", index2_load_test); - ADD_TEST(suite, "read", index_find_test); - ADD_TEST(suite, "read", index_findempty_test); - ADD_TEST(suite, "write", index_write_test); - ADD_TEST(suite, "sort", index_sort_test); - ADD_TEST(suite, "sort", index_sort_empty_test); + ADD_TEST(write0); - return suite; -} + ADD_TEST(sort0); + ADD_TEST(sort1); +END_SUITE diff --git a/vendor/libgit2/tests/t07-hashtable.c b/vendor/libgit2/tests/t07-hashtable.c old mode 100755 new mode 100644 index a0f32194c..597136965 --- a/vendor/libgit2/tests/t07-hashtable.c +++ b/vendor/libgit2/tests/t07-hashtable.c @@ -34,32 +34,26 @@ typedef struct _aux_object { int visited; } table_item; -uint32_t hash_func(const void *key) +uint32_t hash_func(const void *key, int hash_id) { uint32_t r; git_oid *id; id = (git_oid *)key; - memcpy(&r, id->id, sizeof(r)); + memcpy(&r, id->id + (hash_id * sizeof(uint32_t)), sizeof(r)); return r; } -int hash_haskey(void *item, const void *key) +int hash_cmpkey(const void *a, const void *b) { - table_item *obj; - git_oid *oid; - - obj = (table_item *)item; - oid = (git_oid *)key; - - return (git_oid_cmp(oid, &obj->id) == 0); + return git_oid_cmp(a, b); } -BEGIN_TEST("table", table_create) +BEGIN_TEST(table0, "create a new hashtable") git_hashtable *table = NULL; - table = git_hashtable_alloc(55, hash_func, hash_haskey); + table = git_hashtable_alloc(55, hash_func, hash_cmpkey); must_be_true(table != NULL); must_be_true(table->size_mask + 1 == 64); @@ -67,7 +61,7 @@ BEGIN_TEST("table", table_create) END_TEST -BEGIN_TEST("table", table_populate) +BEGIN_TEST(table1, "fill the hashtable with random entries") const int objects_n = 32; int i; @@ -75,7 +69,7 @@ BEGIN_TEST("table", table_populate) table_item *objects; git_hashtable *table = NULL; - table = git_hashtable_alloc(objects_n * 2, hash_func, hash_haskey); + table = git_hashtable_alloc(objects_n * 2, hash_func, hash_cmpkey); must_be_true(table != NULL); objects = git__malloc(objects_n * sizeof(table_item)); @@ -115,7 +109,7 @@ BEGIN_TEST("table", table_populate) END_TEST -BEGIN_TEST("table", table_resize) +BEGIN_TEST(table2, "make sure the table resizes automatically") const int objects_n = 64; int i; @@ -123,7 +117,7 @@ BEGIN_TEST("table", table_resize) table_item *objects; git_hashtable *table = NULL; - table = git_hashtable_alloc(objects_n, hash_func, hash_haskey); + table = git_hashtable_alloc(objects_n, hash_func, hash_cmpkey); must_be_true(table != NULL); objects = git__malloc(objects_n * sizeof(table_item)); @@ -156,16 +150,16 @@ BEGIN_TEST("table", table_resize) END_TEST -BEGIN_TEST("tableit", table_iterator) +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; git_hashtable *table = NULL; - git_hashtable_iterator iterator; - table = git_hashtable_alloc(objects_n * 2, hash_func, hash_haskey); + table = git_hashtable_alloc(objects_n * 2, hash_func, hash_cmpkey); must_be_true(table != NULL); objects = git__malloc(objects_n * sizeof(table_item)); @@ -177,11 +171,9 @@ BEGIN_TEST("tableit", table_iterator) must_pass(git_hashtable_insert(table, &(objects[i].id), &(objects[i]))); } - git_hashtable_iterator_init(table, &iterator); - - /* iterate through all nodes, mark as visited */ - while ((ob = (table_item *)git_hashtable_iterator_next(&iterator)) != NULL) + GIT_HASHTABLE_FOREACH(table, _unused, ob, ob->visited = 1; + ); /* make sure all nodes have been visited */ for (i = 0; i < objects_n; ++i) @@ -189,18 +181,13 @@ BEGIN_TEST("tableit", table_iterator) git_hashtable_free(table); free(objects); - END_TEST -git_testsuite *libgit2_suite_hashtable(void) -{ - git_testsuite *suite = git_testsuite_new("Hashtable"); - - ADD_TEST(suite, "table", table_create); - ADD_TEST(suite, "table", table_populate); - ADD_TEST(suite, "table", table_resize); - ADD_TEST(suite, "tableit", table_iterator); +BEGIN_SUITE(hashtable) + ADD_TEST(table0); + ADD_TEST(table1); + ADD_TEST(table2); + ADD_TEST(tableit0); +END_SUITE - return suite; -} diff --git a/vendor/libgit2/tests/t08-tag.c b/vendor/libgit2/tests/t08-tag.c old mode 100755 new mode 100644 index 1b7c5fa2b..0afdf719d --- a/vendor/libgit2/tests/t08-tag.c +++ b/vendor/libgit2/tests/t08-tag.c @@ -31,7 +31,7 @@ static const char *tag1_id = "b25fa35b38051e4ae45d4222e795f9df2e43f1d1"; static const char *tag2_id = "7b4384978d2493e851f9cca7858815fac9b10980"; static const char *tagged_commit = "e90810b8df3e80c413d903f631643c716887138d"; -BEGIN_TEST("readtag", readtag) +BEGIN_TEST(read0, "read and parse a tag from the repository") git_repository *repo; git_tag *tag1, *tag2; git_commit *commit; @@ -61,7 +61,7 @@ BEGIN_TEST("readtag", readtag) git_repository_free(repo); END_TEST -BEGIN_TEST("write", tag_writeback_test) +BEGIN_TEST(write0, "write back a tag to the repository") git_oid id; git_repository *repo; git_tag *tag; @@ -81,12 +81,7 @@ BEGIN_TEST("write", tag_writeback_test) END_TEST -git_testsuite *libgit2_suite_tag(void) -{ - git_testsuite *suite = git_testsuite_new("Tag"); - - ADD_TEST(suite, "readtag", readtag); - ADD_TEST(suite, "write", tag_writeback_test); - - return suite; -} +BEGIN_SUITE(tag) + ADD_TEST(read0); + ADD_TEST(write0); +END_SUITE diff --git a/vendor/libgit2/tests/t09-tree.c b/vendor/libgit2/tests/t09-tree.c old mode 100755 new mode 100644 index 8c0b5b024..6bc2a84bd --- a/vendor/libgit2/tests/t09-tree.c +++ b/vendor/libgit2/tests/t09-tree.c @@ -29,7 +29,7 @@ static const char *tree_oid = "1810dff58d8a660512d4832e740f692884338ccd"; -BEGIN_TEST("readtree", tree_entry_access_test) +BEGIN_TEST(read0, "acces randomly the entries on a loaded tree") git_oid id; git_repository *repo; git_tree *tree; @@ -51,7 +51,7 @@ BEGIN_TEST("readtree", tree_entry_access_test) git_repository_free(repo); END_TEST -BEGIN_TEST("readtree", tree_read_test) +BEGIN_TEST(read1, "read a tree from the repository") git_oid id; git_repository *repo; git_tree *tree; @@ -76,7 +76,7 @@ BEGIN_TEST("readtree", tree_read_test) git_repository_free(repo); END_TEST -BEGIN_TEST("modify", tree_in_memory_add_test) +BEGIN_TEST(write0, "add a new entry to a tree and write it back to disk") const unsigned int entry_count = 128; git_repository *repo; @@ -101,12 +101,10 @@ BEGIN_TEST("modify", tree_in_memory_add_test) must_pass(git_object_write((git_object *)tree)); must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tree)); - git_object_free((git_object *)tree); - git_repository_free(repo); END_TEST -BEGIN_TEST("modify", tree_add_entry_test) +BEGIN_TEST(write1, "add several entries in-memory and validate that they exist; write back to disk") git_oid id; git_repository *repo; git_tree *tree; @@ -152,19 +150,14 @@ BEGIN_TEST("modify", tree_add_entry_test) */ must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tree)); - git_object_free((git_object *)tree); git_repository_free(repo); END_TEST -git_testsuite *libgit2_suite_tree(void) -{ - git_testsuite *suite = git_testsuite_new("Tree"); - - ADD_TEST(suite, "readtree", tree_entry_access_test); - ADD_TEST(suite, "readtree", tree_read_test); - ADD_TEST(suite, "modify", tree_in_memory_add_test); - ADD_TEST(suite, "modify", tree_add_entry_test); +BEGIN_SUITE(tree) + ADD_TEST(read0); + ADD_TEST(read1); + ADD_TEST(write0); + ADD_TEST(write1); +END_SUITE - return suite; -} diff --git a/vendor/libgit2/tests/t10-refs.c b/vendor/libgit2/tests/t10-refs.c old mode 100755 new mode 100644 index 9e38d2739..abe364133 --- a/vendor/libgit2/tests/t10-refs.c +++ b/vendor/libgit2/tests/t10-refs.c @@ -25,46 +25,45 @@ #include "test_lib.h" #include "test_helpers.h" -#include "refs.h" +#include "repository.h" static const char *loose_tag_ref_name = "refs/tags/test"; static const char *non_existing_tag_ref_name = "refs/tags/i-do-not-exist"; -BEGIN_TEST("readtag", loose_tag_reference_looking_up) +BEGIN_TEST(readtag0, "lookup a loose tag reference") git_repository *repo; git_reference *reference; git_object *object; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, loose_tag_ref_name)); - must_be_true(reference->type == GIT_REF_OID); - must_be_true(reference->packed == 0); + must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); + must_be_true(reference->type & GIT_REF_OID); + must_be_true((reference->type & GIT_REF_PACKED) == 0); must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); - must_pass(git_repository_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); + must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_TAG); git_repository_free(repo); END_TEST -BEGIN_TEST("readtag", non_existing_tag_reference_looking_up) +BEGIN_TEST(readtag1, "lookup a loose tag reference that doesn't exist") git_repository *repo; git_reference *reference; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_fail(git_repository_lookup_ref(&reference, repo, non_existing_tag_ref_name)); + must_fail(git_reference_lookup(&reference, repo, non_existing_tag_ref_name)); git_repository_free(repo); END_TEST -static const char *head_ref_name = "HEAD"; static const char *head_tracker_sym_ref_name = "head-tracker"; static const char *current_head_target = "refs/heads/master"; static const char *current_master_tip = "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"; -BEGIN_TEST("readsymref", symbolic_reference_looking_up) +BEGIN_TEST(readsym0, "lookup a symbolic reference") git_repository *repo; git_reference *reference, *resolved_ref; git_object *object; @@ -72,15 +71,15 @@ BEGIN_TEST("readsymref", symbolic_reference_looking_up) must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, head_ref_name)); - must_be_true(reference->type == GIT_REF_SYMBOLIC); - must_be_true(reference->packed == 0); - must_be_true(strcmp(reference->name, head_ref_name) == 0); + must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE)); + must_be_true(reference->type & GIT_REF_SYMBOLIC); + must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(strcmp(reference->name, GIT_HEAD_FILE) == 0); must_pass(git_reference_resolve(&resolved_ref, reference)); must_be_true(resolved_ref->type == GIT_REF_OID); - must_pass(git_repository_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); + must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); @@ -90,7 +89,7 @@ BEGIN_TEST("readsymref", symbolic_reference_looking_up) git_repository_free(repo); END_TEST -BEGIN_TEST("readsymref", nested_symbolic_reference_looking_up) +BEGIN_TEST(readsym1, "lookup a nested symbolic reference") git_repository *repo; git_reference *reference, *resolved_ref; git_object *object; @@ -98,56 +97,56 @@ BEGIN_TEST("readsymref", nested_symbolic_reference_looking_up) must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, head_tracker_sym_ref_name)); - must_be_true(reference->type == GIT_REF_SYMBOLIC); - must_be_true(reference->packed == 0); - must_be_true(strcmp(reference->name, head_tracker_sym_ref_name) == 0); - - must_pass(git_reference_resolve(&resolved_ref, reference)); - must_be_true(resolved_ref->type == GIT_REF_OID); - - must_pass(git_repository_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); - must_be_true(object != NULL); - must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); - - git_oid_mkstr(&id, current_master_tip); + must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name)); + must_be_true(reference->type & GIT_REF_SYMBOLIC); + must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(strcmp(reference->name, head_tracker_sym_ref_name) == 0); + + must_pass(git_reference_resolve(&resolved_ref, reference)); + must_be_true(resolved_ref->type == GIT_REF_OID); + + must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY)); + must_be_true(object != NULL); + must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); + + git_oid_mkstr(&id, current_master_tip); must_be_true(git_oid_cmp(&id, git_object_id(object)) == 0); git_repository_free(repo); END_TEST -BEGIN_TEST("readsymref", looking_up_head_then_master) +BEGIN_TEST(readsym2, "lookup the HEAD and resolve the master branch") git_repository *repo; git_reference *reference, *resolved_ref, *comp_base_ref; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, head_tracker_sym_ref_name)); - must_pass(git_reference_resolve(&resolved_ref, reference)); - comp_base_ref = resolved_ref; - - must_pass(git_repository_lookup_ref(&reference, repo, head_ref_name)); - must_pass(git_reference_resolve(&resolved_ref, reference)); - must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); - - must_pass(git_repository_lookup_ref(&reference, repo, current_head_target)); + must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name)); + must_pass(git_reference_resolve(&resolved_ref, reference)); + comp_base_ref = resolved_ref; + + must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE)); + must_pass(git_reference_resolve(&resolved_ref, reference)); + must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); + + must_pass(git_reference_lookup(&reference, repo, current_head_target)); must_pass(git_reference_resolve(&resolved_ref, reference)); - must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); + must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref))); git_repository_free(repo); END_TEST -BEGIN_TEST("readsymref", looking_up_master_then_head) +BEGIN_TEST(readsym3, "lookup the master branch and then the HEAD") git_repository *repo; git_reference *reference, *master_ref, *resolved_ref; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&master_ref, repo, current_head_target)); - must_pass(git_repository_lookup_ref(&reference, repo, head_ref_name)); + must_pass(git_reference_lookup(&master_ref, repo, current_head_target)); + must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE)); must_pass(git_reference_resolve(&resolved_ref, reference)); - must_pass(git_oid_cmp(git_reference_oid(master_ref), git_reference_oid(resolved_ref))); + must_pass(git_oid_cmp(git_reference_oid(master_ref), git_reference_oid(resolved_ref))); git_repository_free(repo); END_TEST @@ -155,51 +154,591 @@ END_TEST static const char *packed_head_name = "refs/heads/packed"; static const char *packed_test_head_name = "refs/heads/packed-test"; -BEGIN_TEST("readpackedref", packed_reference_looking_up) +BEGIN_TEST(readpacked0, "lookup a packed reference") git_repository *repo; git_reference *reference; git_object *object; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, packed_head_name)); - must_be_true(reference->type == GIT_REF_OID); - must_be_true(reference->packed == 1); + must_pass(git_reference_lookup(&reference, repo, packed_head_name)); + must_be_true(reference->type & GIT_REF_OID); + must_be_true((reference->type & GIT_REF_PACKED) != 0); must_be_true(strcmp(reference->name, packed_head_name) == 0); - must_pass(git_repository_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); + must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY)); must_be_true(object != NULL); must_be_true(git_object_type(object) == GIT_OBJ_COMMIT); git_repository_free(repo); END_TEST -BEGIN_TEST("readpackedref", packed_exists_but_more_recent_loose_reference_is_retrieved) +BEGIN_TEST(readpacked1, "assure that a loose reference is looked up before a packed reference") git_repository *repo; git_reference *reference; must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); - must_pass(git_repository_lookup_ref(&reference, repo, packed_head_name)); - must_pass(git_repository_lookup_ref(&reference, repo, packed_test_head_name)); - must_be_true(reference->type == GIT_REF_OID); - must_be_true(reference->packed == 0); + must_pass(git_reference_lookup(&reference, repo, packed_head_name)); + must_pass(git_reference_lookup(&reference, repo, packed_test_head_name)); + must_be_true(reference->type & GIT_REF_OID); + must_be_true((reference->type & GIT_REF_PACKED) == 0); must_be_true(strcmp(reference->name, packed_test_head_name) == 0); git_repository_free(repo); END_TEST -git_testsuite *libgit2_suite_refs(void) +BEGIN_TEST(create0, "create a new symbolic reference") + git_reference *new_reference, *looked_up_ref, *resolved_ref; + git_repository *repo; + git_oid id; + char ref_path[GIT_PATH_MAX]; + + const char *new_head_tracker = "another-head-tracker"; + + git_oid_mkstr(&id, current_master_tip); + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + /* Retrieve the physical path to the symbolic ref for further cleaning */ + git__joinpath(ref_path, repo->path_repository, new_head_tracker); + + /* Create and write the new symbolic reference */ + must_pass(git_reference_create_symbolic(&new_reference, repo, new_head_tracker, current_head_target)); + + /* Ensure the reference can be looked-up... */ + must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker)); + must_be_true(looked_up_ref->type & GIT_REF_SYMBOLIC); + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0); + + /* ...peeled.. */ + must_pass(git_reference_resolve(&resolved_ref, looked_up_ref)); + must_be_true(resolved_ref->type == GIT_REF_OID); + + /* ...and that it points to the current master tip */ + must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0); + + git_repository_free(repo); + + /* Similar test with a fresh new repository */ + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + must_pass(git_reference_lookup(&looked_up_ref, repo, 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 */ +END_TEST + +BEGIN_TEST(create1, "create a deep symbolic reference") + git_reference *new_reference, *looked_up_ref, *resolved_ref; + git_repository *repo; + git_oid id; + char ref_path[GIT_PATH_MAX]; + + const char *new_head_tracker = "deep/rooted/tracker"; + + git_oid_mkstr(&id, current_master_tip); + + must_pass(git_repository_open(&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)); + must_pass(git_reference_lookup(&looked_up_ref, repo, 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 */ +END_TEST + +BEGIN_TEST(create2, "create a new OID reference") + git_reference *new_reference, *looked_up_ref; + git_repository *repo; + git_oid id; + char ref_path[GIT_PATH_MAX]; + + const char *new_head = "refs/heads/new-head"; + + git_oid_mkstr(&id, current_master_tip); + + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + /* Retrieve the physical path to the symbolic ref for further cleaning */ + git__joinpath(ref_path, repo->path_repository, new_head); + + /* Create and write the new object id reference */ + must_pass(git_reference_create_oid(&new_reference, repo, new_head, &id)); + + /* Ensure the reference can be looked-up... */ + must_pass(git_reference_lookup(&looked_up_ref, repo, new_head)); + must_be_true(looked_up_ref->type & GIT_REF_OID); + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true(strcmp(looked_up_ref->name, new_head) == 0); + + /* ...and that it points to the current master tip */ + must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); + + git_repository_free(repo); + + /* Similar test with a fresh new repository */ + must_pass(git_repository_open(&repo, REPOSITORY_FOLDER)); + + must_pass(git_reference_lookup(&looked_up_ref, repo, new_head)); + must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0); + + git_repository_free(repo); + + must_pass(gitfo_unlink(ref_path)); /* TODO: replace with git_reference_delete() when available */ +END_TEST + +BEGIN_TEST(pack0, "create a packfile for an empty folder") + git_repository *repo; + char temp_path[GIT_PATH_MAX]; + const int mode = 0755; /* or 0777 ? */ + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + git__joinpath_n(temp_path, 3, repo->path_repository, GIT_REFS_HEADS_DIR, "empty_dir"); + must_pass(gitfo_mkdir_recurs(temp_path, mode)); + + must_pass(git_reference_packall(repo)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(pack1, "create a packfile from all the loose rn a repo") + git_repository *repo; + git_reference *reference; + char temp_path[GIT_PATH_MAX]; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Ensure a known loose ref can be looked up */ + must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); + must_be_true((reference->type & GIT_REF_PACKED) == 0); + must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); + + must_pass(git_reference_packall(repo)); + + /* Ensure the packed-refs file exists */ + git__joinpath(temp_path, repo->path_repository, GIT_PACKEDREFS_FILE); + must_pass(gitfo_exists(temp_path)); + + /* Ensure the known ref can still be looked up but is now packed */ + must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name)); + must_be_true((reference->type & GIT_REF_PACKED) != 0); + must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0); + + /* Ensure the known ref has been removed from the loose folder structure */ + git__joinpath(temp_path, repo->path_repository, loose_tag_ref_name); + must_pass(!gitfo_exists(temp_path)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(rename0, "rename a loose reference") + git_reference *looked_up_ref, *another_looked_up_ref; + git_repository *repo; + char temp_path[GIT_PATH_MAX]; + const char *new_name = "refs/tags/Nemo/knows/refs.kung-fu"; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Ensure the ref doesn't exist on the file system */ + git__joinpath(temp_path, repo->path_repository, new_name); + must_pass(!gitfo_exists(temp_path)); + + /* Retrieval of the reference to rename */ + must_pass(git_reference_lookup(&looked_up_ref, repo, loose_tag_ref_name)); + + /* ... which is indeed loose */ + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* Now that the reference is renamed... */ + must_pass(git_reference_rename(looked_up_ref, new_name)); + must_be_true(!strcmp(looked_up_ref->name, new_name)); + + /* ...It can't be looked-up with the old name... */ + must_fail(git_reference_lookup(&another_looked_up_ref, repo, loose_tag_ref_name)); + + /* ...but the new name works ok... */ + must_pass(git_reference_lookup(&another_looked_up_ref, repo, new_name)); + must_be_true(!strcmp(another_looked_up_ref->name, new_name)); + + /* .. the ref is still loose... */ + must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* ...and the ref can be found in the file system */ + git__joinpath(temp_path, repo->path_repository, new_name); + must_pass(gitfo_exists(temp_path)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(rename1, "rename a packed reference (should make it loose)") + git_reference *looked_up_ref, *another_looked_up_ref; + git_repository *repo; + char temp_path[GIT_PATH_MAX]; + const char *brand_new_name = "refs/heads/brand_new_name"; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Ensure the ref doesn't exist on the file system */ + git__joinpath(temp_path, repo->path_repository, packed_head_name); + must_pass(!gitfo_exists(temp_path)); + + /* The reference can however be looked-up... */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); + + /* .. and it's packed */ + must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0); + + /* Now that the reference is renamed... */ + must_pass(git_reference_rename(looked_up_ref, brand_new_name)); + must_be_true(!strcmp(looked_up_ref->name, brand_new_name)); + + /* ...It can't be looked-up with the old name... */ + must_fail(git_reference_lookup(&another_looked_up_ref, repo, packed_head_name)); + + /* ...but the new name works ok... */ + must_pass(git_reference_lookup(&another_looked_up_ref, repo, brand_new_name)); + must_be_true(!strcmp(another_looked_up_ref->name, brand_new_name)); + + /* .. the ref is no longer packed... */ + must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* ...and the ref now happily lives in the file system */ + git__joinpath(temp_path, repo->path_repository, brand_new_name); + must_pass(gitfo_exists(temp_path)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference which happens to be in both loose and pack state") + git_reference *looked_up_ref, *another_looked_up_ref; + git_repository *repo; + char temp_path[GIT_PATH_MAX]; + const char *brand_new_name = "refs/heads/brand_new_name"; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Ensure the other reference exists on the file system */ + git__joinpath(temp_path, repo->path_repository, packed_test_head_name); + must_pass(gitfo_exists(temp_path)); + + /* Lookup the other reference */ + must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); + + /* Ensure it's loose */ + must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* Lookup the reference to rename */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); + + /* Ensure it's packed */ + must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0); + + /* Now that the reference is renamed... */ + must_pass(git_reference_rename(looked_up_ref, brand_new_name)); + + /* Lookup the other reference */ + must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); + + /* Ensure it's loose */ + must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* Ensure the other ref still exists on the file system */ + must_pass(gitfo_exists(temp_path)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(rename3, "can not 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_fail(git_reference_rename(looked_up_ref, packed_test_head_name)); + + /* Failure to rename it hasn't corrupted its state */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name)); + must_be_true(!strcmp(looked_up_ref->name, packed_head_name)); + + close_temp_repo(repo); +END_TEST + +BEGIN_TEST(rename4, "can not rename a reference with an invalid name") + git_reference *looked_up_ref; + git_repository *repo; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* An existing oid reference... */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name)); + + /* Can not be renamed with an invalid name. */ + must_fail(git_reference_rename(looked_up_ref, "Hello! I'm a very invalid name.")); + + /* Can not be renamed outside of the refs hierarchy. */ + must_fail(git_reference_rename(looked_up_ref, "i-will-sudo-you")); + + /* Failure to rename it hasn't corrupted its state */ + 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; + char temp_path[GIT_PATH_MAX]; + + must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER)); + + /* Ensure the loose reference exists on the file system */ + git__joinpath(temp_path, repo->path_repository, packed_test_head_name); + must_pass(gitfo_exists(temp_path)); + + /* Lookup the reference */ + must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name)); + + /* Ensure it's the loose version that has been found */ + must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0); + + /* Now that the reference is deleted... */ + must_pass(git_reference_delete(looked_up_ref)); + + /* Looking up the reference once again should not retrieve it */ + must_fail(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name)); + + /* Ensure the loose reference doesn't exist any longer on the file system */ + must_pass(!gitfo_exists(temp_path)); + + close_temp_repo(repo); +END_TEST + +static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname) { - git_testsuite *suite = git_testsuite_new("References"); - - ADD_TEST(suite, "readtag", loose_tag_reference_looking_up); - ADD_TEST(suite, "readtag", non_existing_tag_reference_looking_up); - ADD_TEST(suite, "readsymref", symbolic_reference_looking_up); - ADD_TEST(suite, "readsymref", nested_symbolic_reference_looking_up); - ADD_TEST(suite, "readsymref", looking_up_head_then_master); - ADD_TEST(suite, "readsymref", looking_up_master_then_head); - ADD_TEST(suite, "readpackedref", packed_reference_looking_up); - ADD_TEST(suite, "readpackedref", packed_exists_but_more_recent_loose_reference_is_retrieved); - - return suite; + int error = GIT_SUCCESS; + char buffer_out[GIT_PATH_MAX]; + + if (is_oid_ref) + error = git_reference__normalize_name_oid(buffer_out, input_refname); + else + error = git_reference__normalize_name(buffer_out, input_refname); + + if (error < GIT_SUCCESS) + return error; + + if (expected_refname == NULL) + return error; + + if (strcmp(buffer_out, expected_refname)) + error = GIT_ERROR; + + return error; } + +#define OID_REF 1 +#define SYM_REF 0 + +BEGIN_TEST(normalize0, "normalize a direct (OID) reference name") + must_fail(ensure_refname_normalized(OID_REF, "a", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "", NULL)); + 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/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")); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/foo?bar", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads\foo", NULL)); + must_pass(ensure_refname_normalized(OID_REF, "refs/heads/v@ation", "refs/heads/v@ation")); + must_pass(ensure_refname_normalized(OID_REF, "refs///heads///a", "refs/heads/a")); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/.a/b", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/foo/../bar", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/foo..bar", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/./foo", NULL)); + must_fail(ensure_refname_normalized(OID_REF, "refs/heads/v@{ation", NULL)); +END_TEST + +BEGIN_TEST(normalize1, "normalize a symbolic reference name") + must_pass(ensure_refname_normalized(SYM_REF, "a", "a")); + must_pass(ensure_refname_normalized(SYM_REF, "a/b", "a/b")); + must_pass(ensure_refname_normalized(SYM_REF, "refs///heads///a", "refs/heads/a")); + must_fail(ensure_refname_normalized(SYM_REF, "", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "heads\foo", NULL)); +END_TEST + +/* Ported from JGit, BSD licence. + * See https://github.com/spearce/JGit/commit/e4bf8f6957bbb29362575d641d1e77a02d906739 */ +BEGIN_TEST(normalize2, "tests borrowed from JGit") + +/* EmptyString */ + must_fail(ensure_refname_normalized(SYM_REF, "", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "/", NULL)); + +/* MustHaveTwoComponents */ + must_fail(ensure_refname_normalized(OID_REF, "master", NULL)); + must_pass(ensure_refname_normalized(SYM_REF, "heads/master", "heads/master")); + +/* ValidHead */ + + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/master", "refs/heads/master")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/pu", "refs/heads/pu")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/z", "refs/heads/z")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/FoO", "refs/heads/FoO")); + +/* ValidTag */ + must_pass(ensure_refname_normalized(SYM_REF, "refs/tags/v1.0", "refs/tags/v1.0")); + +/* NoLockSuffix */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master.lock", NULL)); + +/* NoDirectorySuffix */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master/", NULL)); + +/* NoSpace */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/i haz space", NULL)); + +/* NoAsciiControlCharacters */ + { + char c; + char buffer[MAX_GITDIR_TREE_STRUCTURE_PATH_LENGTH]; + for (c = '\1'; c < ' '; c++) { + strncpy(buffer, "refs/heads/mast", 15); + strncpy(buffer + 15, (const char *)&c, 1); + strncpy(buffer + 16, "er", 2); + buffer[18 - 1] = '\0'; + must_fail(ensure_refname_normalized(SYM_REF, buffer, NULL)); + } + } + +/* NoBareDot */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/.", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/..", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/./master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/../master", NULL)); + +/* NoLeadingOrTrailingDot */ + must_fail(ensure_refname_normalized(SYM_REF, ".", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/.bar", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/..bar", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/bar.", NULL)); + +/* ContainsDot */ + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/m.a.s.t.e.r", "refs/heads/m.a.s.t.e.r")); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master..pu", NULL)); + +/* NoMagicRefCharacters */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master^", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/^master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "^refs/heads/master", NULL)); + + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master~", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/~master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "~refs/heads/master", NULL)); + + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master:", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/:master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, ":refs/heads/master", NULL)); + +/* ShellGlob */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master?", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/?master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "?refs/heads/master", NULL)); + + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master[", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/[master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "[refs/heads/master", NULL)); + + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master*", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/*master", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "*refs/heads/master", NULL)); + +/* ValidSpecialCharacters */ + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/!", "refs/heads/!")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/\"", "refs/heads/\"")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/#", "refs/heads/#")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/$", "refs/heads/$")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/%", "refs/heads/%")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/&", "refs/heads/&")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/'", "refs/heads/'")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/(", "refs/heads/(")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/)", "refs/heads/)")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/+", "refs/heads/+")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/,", "refs/heads/,")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/-", "refs/heads/-")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/;", "refs/heads/;")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/<", "refs/heads/<")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/=", "refs/heads/=")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/>", "refs/heads/>")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/@", "refs/heads/@")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/]", "refs/heads/]")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/_", "refs/heads/_")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/`", "refs/heads/`")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/{", "refs/heads/{")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/|", "refs/heads/|")); + must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/}", "refs/heads/}")); + + // This is valid on UNIX, but not on Windows + // hence we make in invalid due to non-portability + // + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/\\", NULL)); + +/* UnicodeNames */ + /* + * Currently this fails. + * must_pass(ensure_refname_normalized(SYM_REF, "refs/heads/\u00e5ngstr\u00f6m", "refs/heads/\u00e5ngstr\u00f6m")); + */ + +/* RefLogQueryIsValidRef */ + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master@{1}", NULL)); + must_fail(ensure_refname_normalized(SYM_REF, "refs/heads/master@{1.hour.ago}", NULL)); +END_TEST + + +BEGIN_SUITE(refs) + ADD_TEST(readtag0); + ADD_TEST(readtag1); + + ADD_TEST(readsym0); + ADD_TEST(readsym1); + ADD_TEST(readsym2); + ADD_TEST(readsym3); + + ADD_TEST(readpacked0); + ADD_TEST(readpacked1); + + ADD_TEST(create0); + ADD_TEST(create1); + ADD_TEST(create2); + + ADD_TEST(normalize0); + ADD_TEST(normalize1); + ADD_TEST(normalize2); + + ADD_TEST(pack0); + ADD_TEST(pack1); + + ADD_TEST(rename0); + ADD_TEST(rename1); + ADD_TEST(rename2); + ADD_TEST(rename3); + ADD_TEST(rename4); + + ADD_TEST(delete0); +END_SUITE diff --git a/vendor/libgit2/tests/t11-sqlite.c b/vendor/libgit2/tests/t11-sqlite.c old mode 100755 new mode 100644 index bc75f5668..9e9d1b786 --- a/vendor/libgit2/tests/t11-sqlite.c +++ b/vendor/libgit2/tests/t11-sqlite.c @@ -51,7 +51,7 @@ static git_odb *open_sqlite_odb(void) if (git_odb_backend_sqlite(&sqlite, ":memory") < GIT_SUCCESS) return NULL; - if (git_odb_add_backend(odb, sqlite) < GIT_SUCCESS) + if (git_odb_add_backend(odb, sqlite, 0) < GIT_SUCCESS) return NULL; return odb; @@ -75,49 +75,43 @@ static git_odb *open_sqlite_odb(void) git_odb_close(db); \ } -BEGIN_TEST("sqlite", sql_write_commit) +BEGIN_TEST(sqlite0, "write a commit, read it back (sqlite backend)") TEST_WRITE(commit); END_TEST -BEGIN_TEST("sqlite", sql_write_tree) +BEGIN_TEST(sqlite1, "write a tree, read it back (sqlite backend)") TEST_WRITE(tree); END_TEST -BEGIN_TEST("sqlite", sql_write_tag) +BEGIN_TEST(sqlite2, "write a tag, read it back (sqlite backend)") TEST_WRITE(tag); END_TEST -BEGIN_TEST("sqlite", sql_write_zero) +BEGIN_TEST(sqlite3, "write a zero-byte entry, read it back (sqlite backend)") TEST_WRITE(zero); END_TEST -BEGIN_TEST("sqlite", sql_write_one) +BEGIN_TEST(sqlite4, "write a one-byte entry, read it back (sqlite backend)") TEST_WRITE(one); END_TEST -BEGIN_TEST("sqlite", sql_write_two) +BEGIN_TEST(sqlite5, "write a two-byte entry, read it back (sqlite backend)") TEST_WRITE(two); END_TEST -BEGIN_TEST("sqlite", sql_write_some) +BEGIN_TEST(sqlite6, "write some bytes in an entry, read it back (sqlite backend)") TEST_WRITE(some); END_TEST -git_testsuite *libgit2_suite_sqlite(void) -{ - git_testsuite *suite = git_testsuite_new("SQLite Backend"); - +BEGIN_SUITE(sqlite) #ifdef GIT2_SQLITE_BACKEND - ADD_TEST(suite, "sqlite", sql_write_commit); - ADD_TEST(suite, "sqlite", sql_write_tree); - ADD_TEST(suite, "sqlite", sql_write_tag); - ADD_TEST(suite, "sqlite", sql_write_zero); - ADD_TEST(suite, "sqlite", sql_write_one); - ADD_TEST(suite, "sqlite", sql_write_two); - ADD_TEST(suite, "sqlite", sql_write_some); + ADD_TEST(sqlite0); + ADD_TEST(sqlite1); + ADD_TEST(sqlite2); + ADD_TEST(sqlite3); + ADD_TEST(sqlite4); + ADD_TEST(sqlite5); + ADD_TEST(sqlite6); #endif - - return suite; -} - +END_SUITE diff --git a/vendor/libgit2/tests/t12-repo.c b/vendor/libgit2/tests/t12-repo.c new file mode 100644 index 000000000..644669c8e --- /dev/null +++ b/vendor/libgit2/tests/t12-repo.c @@ -0,0 +1,163 @@ +/* + * 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 "test_helpers.h" + +#include "odb.h" +#include "git2/odb_backend.h" +#include "repository.h" + +typedef struct { + git_odb_backend base; + int position; +} fake_backend; + +git_odb_backend *new_backend(int position) +{ + fake_backend *b; + + b = git__malloc(sizeof(fake_backend)); + if (b == NULL) + return NULL; + + memset(b, 0x0, sizeof(fake_backend)); + b->position = position; + return (git_odb_backend *)b; +} + +int test_backend_sorting(git_odb *odb) +{ + unsigned int i; + + for (i = 0; i < odb->backends.length; ++i) { + fake_backend *internal = *((fake_backend **)git_vector_get(&odb->backends, i)); + + if (internal == NULL) + return GIT_ERROR; + + if (internal->position != (int)i) + return GIT_ERROR; + } + + return GIT_SUCCESS; +} + +BEGIN_TEST(odb0, "assure that ODB backends are properly sorted") + git_odb *odb; + must_pass(git_odb_new(&odb)); + must_pass(git_odb_add_backend(odb, new_backend(0), 5)); + must_pass(git_odb_add_backend(odb, new_backend(2), 3)); + must_pass(git_odb_add_backend(odb, new_backend(1), 4)); + must_pass(git_odb_add_backend(odb, new_backend(3), 1)); + must_pass(test_backend_sorting(odb)); + git_odb_close(odb); +END_TEST + +BEGIN_TEST(odb1, "assure that alternate backends are properly sorted") + git_odb *odb; + must_pass(git_odb_new(&odb)); + must_pass(git_odb_add_backend(odb, new_backend(0), 5)); + must_pass(git_odb_add_backend(odb, new_backend(2), 3)); + must_pass(git_odb_add_backend(odb, new_backend(1), 4)); + must_pass(git_odb_add_backend(odb, new_backend(3), 1)); + must_pass(git_odb_add_alternate(odb, new_backend(4), 5)); + must_pass(git_odb_add_alternate(odb, new_backend(6), 3)); + must_pass(git_odb_add_alternate(odb, new_backend(5), 4)); + must_pass(git_odb_add_alternate(odb, new_backend(7), 1)); + must_pass(test_backend_sorting(odb)); + git_odb_close(odb); +END_TEST + + +#define STANDARD_REPOSITORY 0 +#define BARE_REPOSITORY 1 + +static int ensure_repository_init( + const char *working_directory, + int repository_kind, + const char *expected_path_index, + const char *expected_path_repository, + const char *expected_working_directory) +{ + char path_odb[GIT_PATH_MAX]; + git_repository *repo; + + if (gitfo_isdir(working_directory) == GIT_SUCCESS) + return GIT_ERROR; + + git__joinpath(path_odb, expected_path_repository, GIT_OBJECTS_DIR); + + if (git_repository_init(&repo, working_directory, repository_kind) < GIT_SUCCESS) + return GIT_ERROR; + + if (repo->path_workdir != NULL || expected_working_directory != NULL) { + if (strcmp(repo->path_workdir, expected_working_directory) != 0) + return GIT_ERROR; + } + + if (strcmp(repo->path_odb, path_odb) != 0) + return GIT_ERROR; + + if (strcmp(repo->path_repository, expected_path_repository) != 0) + return GIT_ERROR; + + if (repo->path_index != NULL || expected_path_index != NULL) { + if (strcmp(repo->path_index, expected_path_index) != 0) + return GIT_ERROR; + } + + git_repository_free(repo); + rmdir_recurs(working_directory); + + return GIT_SUCCESS; +} + +BEGIN_TEST(init0, "initialize a standard repo") + char path_index[GIT_PATH_MAX], path_repository[GIT_PATH_MAX]; + + git__joinpath(path_repository, TEMP_REPO_FOLDER, GIT_DIR); + git__joinpath(path_index, path_repository, GIT_INDEX_FILE); + + ensure_repository_init(TEMP_REPO_FOLDER, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER); + ensure_repository_init(TEMP_REPO_FOLDER_NS, STANDARD_REPOSITORY, path_index, path_repository, TEMP_REPO_FOLDER); +END_TEST + +BEGIN_TEST(init1, "initialize a bare repo") + char path_repository[GIT_PATH_MAX]; + + git__joinpath(path_repository, TEMP_REPO_FOLDER, ""); + + ensure_repository_init(TEMP_REPO_FOLDER, BARE_REPOSITORY, NULL, path_repository, NULL); + ensure_repository_init(TEMP_REPO_FOLDER_NS, BARE_REPOSITORY, NULL, path_repository, NULL); +END_TEST + + +BEGIN_SUITE(repository) + ADD_TEST(odb0); + ADD_TEST(odb1); + ADD_TEST(init0); + ADD_TEST(init1); +END_SUITE + diff --git a/vendor/libgit2/tests/test_helpers.c b/vendor/libgit2/tests/test_helpers.c old mode 100755 new mode 100644 index 5fd9a565a..588461135 --- a/vendor/libgit2/tests/test_helpers.c +++ b/vendor/libgit2/tests/test_helpers.c @@ -131,3 +131,133 @@ int cmp_objects(git_rawobj *o, object_data *d) return -1; return 0; } + +int copy_file(const char *src, const char *dst) +{ + gitfo_buf source_buf; + git_file dst_fd; + int error = GIT_ERROR; + + if (gitfo_read_file(&source_buf, src) < GIT_SUCCESS) + return GIT_ENOTFOUND; + + dst_fd = gitfo_creat(dst, 0644); + if (dst_fd < 0) + goto cleanup; + + error = gitfo_write(dst_fd, source_buf.data, source_buf.len); + +cleanup: + gitfo_free_buf(&source_buf); + gitfo_close(dst_fd); + + return error; +} + +int cmp_files(const char *a, const char *b) +{ + gitfo_buf buf_a, buf_b; + int error = GIT_ERROR; + + if (gitfo_read_file(&buf_a, a) < GIT_SUCCESS) + return GIT_ERROR; + + if (gitfo_read_file(&buf_b, b) < GIT_SUCCESS) { + gitfo_free_buf(&buf_a); + return GIT_ERROR; + } + + if (buf_a.len == buf_b.len && !memcmp(buf_a.data, buf_b.data, buf_a.len)) + error = GIT_SUCCESS; + + gitfo_free_buf(&buf_a); + gitfo_free_buf(&buf_b); + + return error; +} + +static int remove_filesystem_element_recurs(void *GIT_UNUSED(nil), char *path) +{ + int error = GIT_SUCCESS; + + GIT_UNUSED_ARG(nil); + + error = gitfo_isdir(path); + if (error == GIT_SUCCESS) { + size_t root_size = strlen(path); + + error = gitfo_dirent(path, GIT_PATH_MAX, remove_filesystem_element_recurs, NULL); + if (error < GIT_SUCCESS) + return error; + + path[root_size] = 0; + return rmdir(path); + } + + return gitfo_unlink(path); +} + +int rmdir_recurs(const char *directory_path) +{ + char buffer[GIT_PATH_MAX]; + strcpy(buffer, directory_path); + return remove_filesystem_element_recurs(NULL, buffer); +} + +typedef struct { + size_t src_len, dst_len; + char *dst; +} copydir_data; + +static int copy_filesystem_element_recurs(void *_data, char *source) +{ + const int mode = 0755; /* or 0777 ? */ + copydir_data *data = (copydir_data *)_data; + + data->dst[data->dst_len] = 0; + git__joinpath(data->dst, data->dst, source + data->src_len); + + if (gitfo_isdir(source) == GIT_SUCCESS) { + if (gitfo_mkdir(data->dst, mode) < GIT_SUCCESS) + return GIT_EOSERR; + + return gitfo_dirent(source, GIT_PATH_MAX, copy_filesystem_element_recurs, _data); + } + + return copy_file(source, data->dst); +} + +int copydir_recurs(const char *source_directory_path, const char *destination_directory_path) +{ + char source_buffer[GIT_PATH_MAX]; + char dest_buffer[GIT_PATH_MAX]; + copydir_data data; + + /* Source has to exist, Destination hast to _not_ exist */ + if (gitfo_isdir(source_directory_path) || !gitfo_isdir(destination_directory_path)) + return GIT_EINVALIDPATH; + + git__joinpath(source_buffer, source_directory_path, ""); + data.src_len = strlen(source_buffer); + + git__joinpath(dest_buffer, destination_directory_path, ""); + data.dst = dest_buffer; + data.dst_len = strlen(dest_buffer); + + return copy_filesystem_element_recurs(&data, source_buffer); +} + +int open_temp_repo(git_repository **repo, const char *path) +{ + int error; + if ((error = copydir_recurs(path, TEMP_REPO_FOLDER)) < GIT_SUCCESS) + return error; + + return git_repository_open(repo, TEMP_REPO_FOLDER); +} + +void close_temp_repo(git_repository *repo) +{ + git_repository_free(repo); + rmdir_recurs(TEMP_REPO_FOLDER); +} diff --git a/vendor/libgit2/tests/test_helpers.h b/vendor/libgit2/tests/test_helpers.h old mode 100755 new mode 100644 index 7551fffee..78538d51c --- a/vendor/libgit2/tests/test_helpers.h +++ b/vendor/libgit2/tests/test_helpers.h @@ -29,10 +29,16 @@ #include "test_lib.h" #include -#define ODB_FOLDER (TEST_RESOURCES "/testrepo.git/objects/") -#define REPOSITORY_FOLDER (TEST_RESOURCES "/testrepo.git/") -#define TEST_INDEX_PATH (TEST_RESOURCES "/testrepo.git/index") -#define TEST_INDEX2_PATH (TEST_RESOURCES "/gitgit.index") +#define TEST_REPOSITORY_NAME "testrepo.git" +#define REPOSITORY_FOLDER TEST_RESOURCES "/" TEST_REPOSITORY_NAME "/" +#define ODB_FOLDER (REPOSITORY_FOLDER "objects/") +#define TEST_INDEX_PATH (REPOSITORY_FOLDER "index") +#define TEST_INDEX2_PATH (TEST_RESOURCES "/gitgit.index") +#define TEST_INDEXBIG_PATH (TEST_RESOURCES "/big.index") + +#define TEMP_FOLDER "./" +#define TEMP_REPO_FOLDER TEMP_FOLDER TEST_REPOSITORY_NAME "/" +#define TEMP_REPO_FOLDER_NS TEMP_FOLDER TEST_REPOSITORY_NAME typedef struct object_data { unsigned char *bytes; /* (compressed) bytes stored in object store */ @@ -55,5 +61,13 @@ extern int cmp_objects(git_rawobj *o, object_data *d); extern int remove_loose_object(const char *odb_dir, git_object *object); +extern int cmp_files(const char *a, const char *b); +extern int copy_file(const char *source, const char *dest); +extern int rmdir_recurs(const char *directory_path); +extern int copydir_recurs(const char *source_directory_path, const char *destination_directory_path); + +extern int open_temp_repo(git_repository **repo, const char *path); +extern void close_temp_repo(git_repository *repo); + #endif /* INCLUDE_test_helpers_h__ */ diff --git a/vendor/libgit2/tests/test_lib.c b/vendor/libgit2/tests/test_lib.c index eb13cd8f6..c9c6141c6 100755 --- a/vendor/libgit2/tests/test_lib.c +++ b/vendor/libgit2/tests/test_lib.c @@ -12,10 +12,12 @@ struct git_test { char *name; + char *message; + char *failed_pos; + char *description; + git_testfunc function; - int failed; - int ran; - const char *message; + unsigned failed:1, ran:1; jmp_buf *jump; }; @@ -25,25 +27,18 @@ struct git_testsuite { git_test *list[GIT_MAX_TEST_CASES]; }; -static void test_init(git_test *t, const char *name, git_testfunc function) -{ - t->name = strdup(name); - t->failed = 0; - t->ran = 0; - t->message = NULL; - t->function = function; - t->jump = NULL; -} - static void test_free(git_test *t) { if (t) { free(t->name); + free(t->description); + free(t->failed_pos); + free(t->message); free(t); } } -void test_run(git_test *tc) +static void test_run(git_test *tc) { jmp_buf buf; tc->jump = &buf; @@ -56,11 +51,26 @@ void test_run(git_test *tc) tc->jump = 0; } -git_test *git_test_new(const char *name, git_testfunc function) +static git_test *create_test(git_testfunc function) { - git_test *tc = DO_ALLOC(git_test); - test_init(tc, name, function); - return tc; + git_test *t = DO_ALLOC(git_test); + + t->name = NULL; + t->failed = 0; + t->ran = 0; + t->description = NULL; + t->message = NULL; + t->failed_pos = NULL; + t->function = function; + t->jump = NULL; + + return t; +} + +void git_test__init(git_test *t, const char *name, const char *description) +{ + t->name = strdup(name); + t->description = strdup(description); } @@ -72,10 +82,11 @@ static void fail_test(git_test *tc, const char *file, int line, const char *mess { char buf[1024]; - snprintf(buf, 1024, "%s @ %s:%d", message, file, line); + snprintf(buf, 1024, "%s:%d", file, line); tc->failed = 1; - tc->message = strdup(buf); + tc->message = strdup(message); + tc->failed_pos = strdup(buf); if (tc->jump != 0) longjmp(*(tc->jump), 0); @@ -111,7 +122,7 @@ git_testsuite *git_testsuite_new(const char *name) return ts; } -void git_testsuite_free(git_testsuite *ts) +static void free_suite(git_testsuite *ts) { unsigned int n; @@ -122,20 +133,12 @@ void git_testsuite_free(git_testsuite *ts) free(ts); } -void git_testsuite_add(git_testsuite *ts, git_test *tc) +void git_testsuite_add(git_testsuite *ts, git_testfunc test) { assert(ts->count < GIT_MAX_TEST_CASES); - ts->list[ts->count++] = tc; + ts->list[ts->count++] = create_test(test); } -void git_testsuite_addsuite(git_testsuite *ts, git_testsuite *ts2) -{ - int i; - for (i = 0 ; i < ts2->count ; ++i) - git_testsuite_add(ts, ts2->list[i]); -} - - static void print_details(git_testsuite *ts) { int i; @@ -151,7 +154,8 @@ static void print_details(git_testsuite *ts) git_test *tc = ts->list[i]; if (tc->failed) { failCount++; - printf(" %d) %s: %s\n", failCount, tc->name, tc->message); + printf(" %d) \"%s\" [test %s @ %s]\n\t%s\n", + failCount, tc->description, tc->name, tc->failed_pos, tc->message); } } } @@ -159,7 +163,7 @@ static void print_details(git_testsuite *ts) int git_testsuite_run(git_testsuite *ts) { - int i; + int i, fail_count; printf("Suite \"%s\": ", ts->name); @@ -175,7 +179,9 @@ int git_testsuite_run(git_testsuite *ts) } printf("\n "); print_details(ts); + fail_count = ts->fail_count; - return ts->fail_count; + free_suite(ts); + return fail_count; } diff --git a/vendor/libgit2/tests/test_lib.h b/vendor/libgit2/tests/test_lib.h index ae384ba4d..d0b62c8d4 100755 --- a/vendor/libgit2/tests/test_lib.h +++ b/vendor/libgit2/tests/test_lib.h @@ -9,13 +9,23 @@ #include "common.h" #include -#define ADD_TEST(SUITE, MODULE, TEST) \ - git_testsuite_add(SUITE, git_test_new(MODULE "::" #TEST, &_gittest__##TEST)) - -#define BEGIN_TEST(MODULE, TEST) \ - void _gittest__##TEST(git_test *_gittest) \ - { \ - assert(_gittest);\ +#define DECLARE_SUITE(SNAME) extern git_testsuite *libgit2_suite_##SNAME(void) +#define SUITE_NAME(SNAME) libgit2_suite_##SNAME + +#define BEGIN_SUITE(SNAME) \ + git_testsuite *libgit2_suite_##SNAME(void) {\ + git_testsuite *_gitsuite = git_testsuite_new(#SNAME); + +#define ADD_TEST(TNAME) \ + git_testsuite_add(_gitsuite, _gittest__##TNAME); + +#define END_SUITE \ + return _gitsuite;\ + } + +#define BEGIN_TEST(TNAME, DESC) \ + static void _gittest__##TNAME(git_test *_gittest) { \ + git_test__init(_gittest, #TNAME, DESC); \ {\ #define END_TEST }} @@ -23,21 +33,18 @@ typedef struct git_test git_test; typedef struct git_testsuite git_testsuite; typedef void (*git_testfunc)(git_test *); +typedef git_testsuite *(*libgit2_suite)(void); +void git_test__init(git_test *t, const char *name, const char *description); void git_test__fail(git_test *tc, const char *file, int line, const char *message); void git_test__assert(git_test *tc, const char *file, int line, const char *message, int condition); -#define must_pass(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Method failed, " #expr, (expr) == 0) -#define must_fail(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Expected method to fail, " #expr, (expr) < 0) -#define must_be_true(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Expected " #expr, !!(expr)) +#define must_pass(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Method failed: " #expr, (expr) == 0) +#define must_fail(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Expected method to fail: " #expr, (expr) < 0) +#define must_be_true(expr) git_test__assert(_gittest, __FILE__, __LINE__, "Expression is not true: " #expr, !!(expr)) git_testsuite *git_testsuite_new(const char *name); -git_test *git_test_new(const char *name, git_testfunc function); - -void git_testsuite_free(git_testsuite *ts); - -void git_testsuite_add(git_testsuite *ts, git_test *tc); -void git_testsuite_addsuite(git_testsuite* ts, git_testsuite *ts2); +void git_testsuite_add(git_testsuite *ts, git_testfunc test); int git_testsuite_run(git_testsuite *ts); #endif diff --git a/vendor/libgit2/tests/test_main.c b/vendor/libgit2/tests/test_main.c old mode 100755 new mode 100644 index 191cd39a4..9308b8d45 --- a/vendor/libgit2/tests/test_main.c +++ b/vendor/libgit2/tests/test_main.c @@ -29,79 +29,49 @@ #include "test_lib.h" #include "test_helpers.h" -extern git_testsuite *libgit2_suite_core(void); -extern git_testsuite *libgit2_suite_rawobjects(void); -extern git_testsuite *libgit2_suite_objread(void); -extern git_testsuite *libgit2_suite_objwrite(void); -extern git_testsuite *libgit2_suite_commit(void); -extern git_testsuite *libgit2_suite_revwalk(void); -extern git_testsuite *libgit2_suite_index(void); -extern git_testsuite *libgit2_suite_hashtable(void); -extern git_testsuite *libgit2_suite_tag(void); -extern git_testsuite *libgit2_suite_tree(void); -extern git_testsuite *libgit2_suite_refs(void); -extern git_testsuite *libgit2_suite_sqlite(void); - -typedef git_testsuite *(*libgit2_suite)(void); +DECLARE_SUITE(core); +DECLARE_SUITE(rawobjects); +DECLARE_SUITE(objread); +DECLARE_SUITE(objwrite); +DECLARE_SUITE(commit); +DECLARE_SUITE(revwalk); +DECLARE_SUITE(index); +DECLARE_SUITE(hashtable); +DECLARE_SUITE(tag); +DECLARE_SUITE(tree); +DECLARE_SUITE(refs); +DECLARE_SUITE(sqlite); +DECLARE_SUITE(repository); static libgit2_suite suite_methods[]= { - libgit2_suite_core, - libgit2_suite_rawobjects, - libgit2_suite_objread, - libgit2_suite_objwrite, - libgit2_suite_commit, - libgit2_suite_revwalk, - libgit2_suite_index, - libgit2_suite_hashtable, - libgit2_suite_tag, - libgit2_suite_tree, - libgit2_suite_refs, - libgit2_suite_sqlite, + SUITE_NAME(core), + SUITE_NAME(rawobjects), + SUITE_NAME(objread), + SUITE_NAME(objwrite), + SUITE_NAME(commit), + SUITE_NAME(revwalk), + SUITE_NAME(index), + SUITE_NAME(hashtable), + SUITE_NAME(tag), + SUITE_NAME(tree), + SUITE_NAME(refs), + SUITE_NAME(sqlite), + SUITE_NAME(repository), }; #define GIT_SUITE_COUNT (ARRAY_SIZE(suite_methods)) - -git_testsuite **libgit2_get_suites() -{ - git_testsuite **suites; - unsigned int i; - - suites = git__malloc(GIT_SUITE_COUNT * sizeof(void *)); - if (suites == NULL) - return NULL; - - for (i = 0; i < GIT_SUITE_COUNT; ++i) - suites[i] = suite_methods[i](); - - return suites; -} - -void libgit2_free_suites(git_testsuite **suites) -{ - unsigned int i; - - for (i = 0; i < GIT_SUITE_COUNT; ++i) - git_testsuite_free(suites[i]); - - free(suites); -} - int main(int GIT_UNUSED(argc), char *GIT_UNUSED(argv[])) { unsigned int i, failures; - git_testsuite **suites; GIT_UNUSED_ARG(argc); GIT_UNUSED_ARG(argv); - suites = libgit2_get_suites(); failures = 0; for (i = 0; i < GIT_SUITE_COUNT; ++i) - failures += git_testsuite_run(suites[i]); - - libgit2_free_suites(suites); + failures += git_testsuite_run(suite_methods[i]()); return failures ? -1 : 0; } diff --git a/vendor/libgit2/tests/tests.supp b/vendor/libgit2/tests/tests.supp old mode 100755 new mode 100644 diff --git a/vendor/libgit2/wscript b/vendor/libgit2/wscript old mode 100755 new mode 100644 index 85e38dfdc..aeb17a9f4 --- a/vendor/libgit2/wscript +++ b/vendor/libgit2/wscript @@ -29,6 +29,8 @@ PPC optimized version (ppc) or the SHA1 functions from OpenSSL (openssl)") help='Force a specific MSVC++ version (7.1, 8.0, 9.0, 10.0), if more than one is installed') opt.add_option('--arch', action='store', default='x86', help='Select target architecture (ia64, x64, x86, x86_amd64, x86_ia64)') + opt.add_option('--without-sqlite', action='store_false', default=True, + dest='use_sqlite', help='Disable sqlite support') def configure(conf): @@ -67,11 +69,12 @@ def configure(conf): conf.check_cc(lib=zlib_name, uselib_store='z', install_path=None) # check for sqlite3 - if conf.check_cc(lib='sqlite3', uselib_store='sqlite3', install_path=None, mandatory=False): + if conf.options.use_sqlite and conf.check_cc( + lib='sqlite3', uselib_store='sqlite3', install_path=None, mandatory=False): conf.env.DEFINES += ['GIT2_SQLITE_BACKEND'] if conf.options.sha1 not in ['openssl', 'ppc', 'builtin']: - ctx.fatal('Invalid SHA1 option') + conf.fatal('Invalid SHA1 option') # check for libcrypto (openssl) if we are using its SHA1 functions if conf.options.sha1 == 'openssl': @@ -129,7 +132,7 @@ def build_library(bld, build_type): sources = directory.ant_glob('src/*.c') # Find the version of the library, from our header file - version = get_libgit2_version(directory.find_node("src/git2.h").abspath()) + version = get_libgit2_version(directory.find_node("include/git2.h").abspath()) # Compile platform-dependant code # E.g. src/unix/*.c @@ -150,7 +153,7 @@ def build_library(bld, build_type): BUILD[build_type]( source=sources, target='git2', - includes='src', + includes=['src', 'include'], install_path='${LIBDIR}', use=ALL_LIBS, vnum=version, @@ -165,8 +168,8 @@ def build_library(bld, build_type): ) # Install headers - bld.install_files('${PREFIX}/include', directory.find_node('src/git2.h')) - bld.install_files('${PREFIX}/include/git2', directory.ant_glob('src/git2/*.h')) + bld.install_files('${PREFIX}/include', directory.find_node('include/git2.h')) + bld.install_files('${PREFIX}/include/git2', directory.ant_glob('include/git2/*.h')) # On Unix systems, let them know about installation if bld.env.PLATFORM == 'unix' and bld.cmd == 'install-shared': @@ -188,7 +191,7 @@ def build_test(bld): bld.program( source=sources, target='libgit2_test', - includes=['src', 'tests'], + includes=['src', 'tests', 'include'], defines=['TEST_RESOURCES="%s"' % resources_path], use=['git2'] + ALL_LIBS ) diff --git a/wscript b/wscript index c5dbfa148..a6079f57a 100755 --- a/wscript +++ b/wscript @@ -4,7 +4,7 @@ import os from os import system from os.path import exists, abspath -VERSION = '0.0.1' +VERSION = '0.0.2' APPNAME = 'nodegit' srcdir = '.' blddir = 'build' @@ -36,6 +36,6 @@ def build(bld): main = bld.new_task_gen('cxx', 'shlib', 'node_addon') main.target = 'nodegit' - main.source = 'src/base.cc src/sig.cc src/blob.cc src/error.cc src/object.cc src/reference.cc src/repo.cc src/commit.cc src/oid.cc src/revwalk.cc src/tree.cc' + main.source = 'src/base.cc src/sig.cc src/blob.cc src/error.cc src/object.cc src/reference.cc src/repo.cc src/commit.cc src/oid.cc src/revwalk.cc src/tree.cc src/tree_entry.cc' main.rpath = abspath('vendor/libgit2/build/shared') main.uselib = 'GIT2'