Skip to content

Commit

Permalink
revwalk: fix #34 problem.
Browse files Browse the repository at this point in the history
* Git2\Revwalk::rewind completely broken (ignores any hided commits, didn't push, hide correctly)
  • Loading branch information
chobie committed Sep 9, 2012
1 parent 8aa140f commit 5531c47
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 28 deletions.
8 changes: 8 additions & 0 deletions php_git2.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,19 @@ typedef struct{
git_reference *reference;
} php_git2_reference;

typedef struct php_git2_vector{
size_t _alloc_size;
size_t length;
void **contents;
} php_git2_vector;

typedef struct{
zend_object zo;
git_revwalk *walker;
git_oid *current;
php_git2_vector vector;
git_repository *repository;
int dirty;
} php_git2_walker;

typedef struct{
Expand Down
22 changes: 22 additions & 0 deletions tests/008-02-walker_itrate.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@ foreach ($walker as $oid => $commit) {
printf("oid: %s\n", $oid);
printf("message: %s\n", $commit->getMessage());
}

echo "==== rewind ====\n\n";

foreach ($walker as $oid => $commit) {
printf("oid: %s\n", $oid);
printf("message: %s\n", $commit->getMessage());
}

--EXPECT--
oid: 6e20138dc38f9f626107f1cd3ef0f9838c43defe
message: added section 1 contents
Expand All @@ -23,5 +31,19 @@ message: added section 1
oid: 7fce1026cb624448e5a8cf8752bd5e19d8f2cb1f
message: modified README

oid: ffc6c773865c1342db9cd5df5777fc91ddeb8a4d
message: initial commit

==== rewind ====

oid: 6e20138dc38f9f626107f1cd3ef0f9838c43defe
message: added section 1 contents

oid: 9bb8c853c9ea27609a6bdc48b78cd26a320daf7d
message: added section 1

oid: 7fce1026cb624448e5a8cf8752bd5e19d8f2cb1f
message: modified README

oid: ffc6c773865c1342db9cd5df5777fc91ddeb8a4d
message: initial commit
185 changes: 157 additions & 28 deletions walker.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,76 @@
#include "php_git2.h"
#include <spl/spl_array.h>
#include <zend_interfaces.h>

PHPAPI zend_class_entry *git2_walker_class_entry;

static const double resize_factor = 1.75;
static const unsigned int minimum_size = 8;

typedef struct{
git_oid oid;
unsigned int interested;
} php_git2_revwalk_element;

int php_git2_vector_init(php_git2_vector *v, size_t initial_size)
{
assert(v);
memset(v, 0x0, sizeof(php_git2_vector));

if (initial_size == 0) {
initial_size = minimum_size;
}

v->_alloc_size = initial_size;
v->length = 0;

v->contents = emalloc(v->_alloc_size * sizeof(void *));
}

static int php_git2_resize_vector(php_git2_vector *v)
{
v->_alloc_size = ((unsigned int)(v->_alloc_size * resize_factor)) + 1;
if (v->_alloc_size < minimum_size)
v->_alloc_size = minimum_size;

v->contents = erealloc(v->contents, v->_alloc_size * sizeof(void *));

return 0;
}

int php_git2_vector_insert(php_git2_vector *v, void *element)
{
assert(v);

if (v->length >= v->_alloc_size && php_git2_resize_vector(v) < 0) {
return -1;
}

v->contents[v->length++] = element;
return 0;
}

void php_git2_vector_clear(php_git2_vector *v)
{
assert(v);
v->length = 0;
}

void php_git2_vector_free(php_git2_vector *v)
{
assert(v);

efree(v->contents);
v->contents = NULL;

v->length = 0;
v->_alloc_size = 0;
}


static void php_git2_walker_free_storage(php_git2_walker *object TSRMLS_DC)
{
int i = 0;
if (object->walker != NULL) {
git_revwalk_free(object->walker);
object->walker = NULL;
Expand All @@ -39,6 +104,11 @@ static void php_git2_walker_free_storage(php_git2_walker *object TSRMLS_DC)
object->current = NULL;
}

for (i = 0; i < object->vector.length; i++) {
efree(object->vector.contents[i]);
}
php_git2_vector_free(&object->vector);

/* the repository will be free'd by Git2\Repository */
object->repository = NULL;

Expand All @@ -51,8 +121,11 @@ zend_object_value php_git2_walker_new(zend_class_entry *ce TSRMLS_DC)
zend_object_value retval;

PHP_GIT2_STD_CREATE_OBJECT(php_git2_walker);
object->dirty = 0;

object->current = emalloc(sizeof(git_oid));
php_git2_vector_init(&object->vector, 8);

return retval;
}

Expand Down Expand Up @@ -93,8 +166,9 @@ PHP_METHOD(git2_walker, __construct)
error = git_revwalk_new(&m_walker->walker, m_repository->repository);

if (error != GIT_OK) {
/* @todo error handling */
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "can't create a Git2\\Walker instance.");
}

m_walker->repository = m_repository->repository;
}
/* }}} */
Expand Down Expand Up @@ -124,8 +198,8 @@ PHP_METHOD(git2_walker, push)
{
php_git2_walker *m_walker;
char *sha;
int sha_len = 0;
git_oid oid;
int sha_len = 0, error = 0;
php_git2_revwalk_element *elm;

/* @todo: also supports Git2\Commit object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
Expand All @@ -134,11 +208,17 @@ PHP_METHOD(git2_walker, push)
}

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
elm = emalloc(sizeof(php_git2_revwalk_element));
elm->interested = 1;

git_oid_fromstrn(&oid, sha, sha_len);
git_revwalk_reset(m_walker->walker);
git_revwalk_push(m_walker->walker, &oid);
memcpy(m_walker->current, &oid, sizeof(git_oid));
git_oid_fromstrn(&elm->oid, sha, sha_len);
error = git_revwalk_push(m_walker->walker, &elm->oid);

if (error != GIT_OK) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Git2\\Walker::push failed.");
}

php_git2_vector_insert(&m_walker->vector, elm);
}
/* }}} */

Expand All @@ -149,8 +229,9 @@ PHP_METHOD(git2_walker, hide)
{
php_git2_walker *m_walker;
char *sha;
int sha_len = 0;
int sha_len = 0, error = 0;
git_oid oid;
php_git2_revwalk_element *elm;

/* @todo: also supports Git2\Commit object */
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
Expand All @@ -159,8 +240,16 @@ PHP_METHOD(git2_walker, hide)
}

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
git_oid_fromstrn(&oid, sha, sha_len);
git_revwalk_hide(m_walker->walker, &oid);
elm = emalloc(sizeof(php_git2_revwalk_element));
elm->interested = 0;

git_oid_fromstrn(&elm->oid, sha, sha_len);
error = git_revwalk_hide(m_walker->walker, &elm->oid);

if (error != GIT_OK) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Git2\\Walker::push failed.");
}
php_git2_vector_insert(&m_walker->vector, elm);
}
/* }}} */

Expand All @@ -171,9 +260,18 @@ PHP_METHOD(git2_walker, hide)
PHP_METHOD(git2_walker, reset)
{
php_git2_walker *m_walker;
int i = 0;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
git_revwalk_reset(m_walker->walker);
m_walker->dirty = 0;

for (i = 0; i < m_walker->vector.length; i++) {
php_git2_revwalk_element *elm = m_walker->vector.contents[i];
efree(elm);
}

php_git2_vector_clear(&m_walker->vector);
}
/* }}} */

Expand All @@ -191,9 +289,10 @@ PHP_METHOD(git2_walker, current)
int error = 0;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
error = git_object_lookup(&object, m_walker->repository, m_walker->current, GIT_OBJ_COMMIT);

error = git_object_lookup(&object, m_walker->repository, m_walker->current, GIT_OBJ_COMMIT);
result = php_git2_object_new(m_walker->repository, object TSRMLS_CC);
RETVAL_ZVAL(result,0,1);
RETVAL_ZVAL(result, 0, 1);
}

/*
Expand All @@ -203,22 +302,26 @@ PHP_METHOD(git2_walker, key)
{
char out[GIT_OID_HEXSZ] = {0};
php_git2_walker *m_walker;
int error = 0;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
git_oid_fmt(out, m_walker->current);
RETURN_STRINGL(out,GIT_OID_HEXSZ,1);

RETURN_STRINGL(out, GIT_OID_HEXSZ, 1);
}

/*
{{{ proto: Git2\Walker::valid()
{{{ proto: Git2\Walker::next()
*/
PHP_METHOD(git2_walker, next)
{
php_git2_walker *m_walker;
int error = 0;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
error = git_revwalk_next(m_walker->current, m_walker->walker);
m_walker->dirty = 1;

if (error != GIT_OK) {
efree(m_walker->current);
m_walker->current = NULL;
Expand All @@ -231,16 +334,42 @@ PHP_METHOD(git2_walker, next)
PHP_METHOD(git2_walker, rewind)
{
php_git2_walker *m_walker;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());
git_revwalk_reset(m_walker->walker);
if (m_walker->current == NULL) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC,
"does not specify interested hash before calling Git2\\Walker::rewind.");
RETURN_FALSE;
int i = 0, error = 0;
m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());

if (m_walker->dirty) {
git_revwalk_reset(m_walker->walker);

for (i = 0; i < m_walker->vector.length; i++) {
php_git2_revwalk_element *elm = m_walker->vector.contents[i];

if (elm->interested) {
error = git_revwalk_push(m_walker->walker, &elm->oid);
} else {
error = git_revwalk_hide(m_walker->walker, &elm->oid);
}

if (error != GIT_OK) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Git2\\Walker::rewind failed. probably you pushed or hided invalied oid.");
}
}

if (m_walker->current == NULL) {
m_walker->current = emalloc(sizeof(git_oid));
}

assert(m_walker->current);
error = git_revwalk_next(m_walker->current, m_walker->walker);
m_walker->dirty = 1;
} else {
error = git_revwalk_next(m_walker->current, m_walker->walker);
m_walker->dirty = 1;

if (error != GIT_OK) {
zend_throw_exception_ex(spl_ce_RuntimeException, 0 TSRMLS_CC, "Git2\\Walker::rewind failed. probably you pushed or hided invalied oid.");
}
}
git_revwalk_push(m_walker->walker, m_walker->current);
git_revwalk_next(m_walker->current, m_walker->walker);

}

/*
Expand All @@ -249,8 +378,8 @@ PHP_METHOD(git2_walker, rewind)
PHP_METHOD(git2_walker, valid)
{
php_git2_walker *m_walker;

m_walker = PHP_GIT2_GET_OBJECT(php_git2_walker, getThis());

if (m_walker->current != NULL) {
RETURN_TRUE;
} else {
Expand Down

0 comments on commit 5531c47

Please sign in to comment.