Merge remote-tracking branch 'carlos/reference-update'

This commit is contained in:
J. David Ibáñez
2014-09-05 17:11:32 +02:00
8 changed files with 126 additions and 169 deletions

View File

@@ -17,16 +17,18 @@ Example::
The Reference type
====================
.. autoclass:: pygit2.Reference
.. autoattribute:: pygit2.Reference.name
.. autoattribute:: pygit2.Reference.shorthand
.. autoattribute:: pygit2.Reference.target
.. autoattribute:: pygit2.Reference.type
.. automethod:: pygit2.Reference.set_target
.. automethod:: pygit2.Reference.delete
.. automethod:: pygit2.Reference.rename
.. automethod:: pygit2.Reference.resolve
.. automethod:: pygit2.Reference.log
.. automethod:: pygit2.Reference.log_append
Example::

View File

@@ -30,6 +30,13 @@ typedef struct git_strarray {
typedef int64_t git_off_t;
typedef int64_t git_time_t;
typedef enum {
GIT_REF_INVALID = 0,
GIT_REF_OID = 1,
GIT_REF_SYMBOLIC = 2,
GIT_REF_LISTALL = 3,
} git_ref_t;
typedef enum {
GIT_OK = 0,
GIT_ERROR = -1,
@@ -462,6 +469,9 @@ int git_repository_init_ext(
const char *repo_path,
git_repository_init_options *opts);
int git_repository_set_head(git_repository *repo, const char *refname, const git_signature *signature, const char *log_message);
int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish, const git_signature *signature, const char *log_message);
/*
* git_index
*/

View File

@@ -275,7 +275,57 @@ class Repository(_Repository):
oid = reference.resolve().target
treeish = self[oid]
self.checkout_tree(treeish, **kwargs)
self.head = refname
head = self.lookup_reference('HEAD')
if head.type == C.GIT_REF_SYMBOLIC:
from_ = self.head.shorthand
else:
from_ = head.target.hex
try:
signature = self.default_signature
except:
signature = None
reflog_text = "checkout: moving from %s to %s" % (from_, reference)
self.set_head(refname, signature, reflog_text)
#
# Setting HEAD
#
def set_head(self, target, signature=None, message=None):
"""Set HEAD to point to the given target
Arguments:
target
The new target for HEAD. Can be a string or Oid (to detach)
signature
Signature to use for the reflog. If not provided, the repository's
default will be used
message
Message to use for the reflog
"""
sig_ptr = ffi.new('git_signature **')
if signature:
ffi.buffer(sig_ptr)[:] = signature._pointer[:]
message_ptr = ffi.NULL
if message_ptr:
message_ptr = to_bytes(message)
if isinstance(target, Oid):
oid = ffi.new('git_oid *')
ffi.buffer(oid)[:] = target.raw[:]
err = C.git_repository_set_head_detached(self._repo, oid, sig_ptr[0], message_ptr)
check_error(err)
return
# if it's a string, then it's a reference name
err = C.git_repository_set_head(self._repo, to_bytes(target), sig_ptr[0], message_ptr)
check_error(err)
#
# Diff

View File

@@ -205,10 +205,7 @@ Reference_resolve(Reference *self, PyObject *args)
PyDoc_STRVAR(Reference_target__doc__,
"The reference target: If direct the value will be an Oid object, if it\n"
"is symbolic it will be an string with the full name of the target\n"
"reference.\n"
"\n"
"The target is writable. Setting the Reference's target to another Oid\n"
"object will direct the reference to that Oid instead.");
"reference.\n");
PyObject *
Reference_target__get__(Reference *self)
@@ -230,48 +227,80 @@ Reference_target__get__(Reference *self)
return to_path(c_name);
}
int
Reference_target__set__(Reference *self, PyObject *py_target)
PyDoc_STRVAR(Reference_set_target__doc__,
"set_target(target, [signature, message])\n"
"\n"
"Set the target of this reference.\n"
"\n"
"Update the reference using the given signature and message.\n"
"These will be used to fill the reflog entry which will be created\n"
"as a result of this update\n"
"\n"
"Arguments:\n"
"\n"
"target\n"
" The new target for this reference\n"
"signature\n"
" The signature to use for the reflog. If left out, the repository's\n"
" default identity will be used.\n"
"message\n"
" Message to use for the reflog.\n");
PyObject *
Reference_set_target(Reference *self, PyObject *args, PyObject *kwds)
{
git_oid oid;
char *c_name;
int err;
git_reference *new_ref;
const git_signature *sig = NULL;
PyObject *py_target = NULL;
Signature *py_signature = NULL;
const char *message = NULL;
char *keywords[] = {"target", "signature", "message", NULL};
CHECK_REFERENCE_INT(self);
CHECK_REFERENCE(self);
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O!s", keywords,
&py_target, &SignatureType, &py_signature, &message))
return NULL;
if (py_signature)
sig = py_signature->signature;
/* Case 1: Direct */
if (GIT_REF_OID == git_reference_type(self->reference)) {
err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid);
if (err < 0)
return err;
goto error;
err = git_reference_set_target(&new_ref, self->reference, &oid, NULL, NULL);
err = git_reference_set_target(&new_ref, self->reference, &oid, sig, message);
if (err < 0)
goto error;
git_reference_free(self->reference);
self->reference = new_ref;
return 0;
Py_RETURN_NONE;
}
/* Case 2: Symbolic */
c_name = py_path_to_c_str(py_target);
if (c_name == NULL)
return -1;
return NULL;
err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, NULL, NULL);
err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, sig, message);
free(c_name);
if (err < 0)
goto error;
git_reference_free(self->reference);
self->reference = new_ref;
return 0;
Py_RETURN_NONE;
error:
Error_set(err);
return -1;
return NULL;
}
@@ -335,72 +364,6 @@ Reference_log(Reference *self)
return (PyObject*)iter;
}
PyDoc_STRVAR(Reference_log_append__doc__,
"log_append(oid, committer, message[, encoding])\n"
"\n"
"Append a reflog entry to the reference. If the oid is None then keep\n"
"the current reference's oid. The message parameter may be None.");
PyObject *
Reference_log_append(Reference *self, PyObject *args)
{
git_signature *committer;
const char *message = NULL;
git_reflog *reflog;
git_oid oid;
const git_oid *ref_oid;
int err;
PyObject *py_oid = NULL;
Signature *py_committer;
PyObject *py_message = NULL;
char *encoding = NULL;
git_repository *repo;
CHECK_REFERENCE(self);
/* Input parameters */
if (!PyArg_ParseTuple(args, "OO!O|s", &py_oid,
&SignatureType, &py_committer,
&py_message, &encoding))
return NULL;
if (py_oid == Py_None)
ref_oid = git_reference_target(self->reference);
else {
err = py_oid_to_git_oid_expand(self->repo->repo, py_oid, &oid);
if (err < 0)
return NULL;
ref_oid = &oid;
}
if (py_message != Py_None) {
message = py_str_to_c_str(py_message, encoding);
if (message == NULL)
return NULL;
}
/* Go */
repo = git_reference_owner(self->reference);
err = git_reflog_read(&reflog, repo, git_reference_name(self->reference));
if (err < 0) {
free((void *)message);
return NULL;
}
committer = (git_signature *)py_committer->signature;
err = git_reflog_append(reflog, ref_oid, committer, message);
if (!err)
err = git_reflog_write(reflog);
git_reflog_free(reflog);
free((void *)message);
if (err < 0)
return NULL;
Py_RETURN_NONE;
}
PyDoc_STRVAR(Reference_get_object__doc__,
"get_object() -> object\n"
"\n"
@@ -514,15 +477,15 @@ PyMethodDef Reference_methods[] = {
METHOD(Reference, rename, METH_O),
METHOD(Reference, resolve, METH_NOARGS),
METHOD(Reference, log, METH_NOARGS),
METHOD(Reference, log_append, METH_VARARGS),
METHOD(Reference, get_object, METH_NOARGS),
METHOD(Reference, set_target, METH_VARARGS | METH_KEYWORDS),
{NULL}
};
PyGetSetDef Reference_getseters[] = {
GETTER(Reference, name),
GETTER(Reference, shorthand),
GETSET(Reference, target),
GETTER(Reference, target),
GETTER(Reference, type),
{NULL}
};

View File

@@ -177,38 +177,6 @@ Repository_head__get__(Repository *self)
return wrap_reference(head, self);
}
int
Repository_head__set__(Repository *self, PyObject *py_val)
{
int err;
if (PyObject_TypeCheck(py_val, &OidType)) {
git_oid oid;
py_oid_to_git_oid(py_val, &oid);
err = git_repository_set_head_detached(self->repo, &oid, NULL, NULL);
if (err < 0) {
Error_set(err);
return -1;
}
} else {
const char *refname;
PyObject *trefname;
refname = py_str_borrow_c_str(&trefname, py_val, NULL);
if (refname == NULL)
return -1;
err = git_repository_set_head(self->repo, refname, NULL, NULL);
Py_DECREF(trefname);
if (err < 0) {
Error_set_str(err, refname);
return -1;
}
}
return 0;
}
PyDoc_STRVAR(Repository_head_is_detached__doc__,
"A repository's HEAD is detached when it points directly to a commit\n"
"instead of a branch.");
@@ -1447,7 +1415,7 @@ PyMethodDef Repository_methods[] = {
PyGetSetDef Repository_getseters[] = {
GETTER(Repository, path),
GETSET(Repository, head),
GETTER(Repository, head),
GETTER(Repository, head_is_detached),
GETTER(Repository, head_is_unborn),
GETTER(Repository, is_empty),

View File

@@ -1,44 +0,0 @@
# -*- coding: UTF-8 -*-
#
# Copyright 2010-2014 The pygit2 contributors
#
# 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.
"""Tests for reference log."""
from __future__ import absolute_import
from __future__ import unicode_literals
from pygit2 import Signature
from . import utils
class ReflogTest(utils.RepoTestCase):
def test_log_append(self):
repo = self.repo
master = repo.lookup_reference("refs/heads/master")
signature = Signature('xtao', 'xutao@douban.com')
master.log_append(None, signature, 'reflog')
self.assertTrue('reflog' in [entry.message for entry in master.log()])

View File

@@ -31,7 +31,7 @@ from __future__ import absolute_import
from __future__ import unicode_literals
import unittest
from pygit2 import GitError, GIT_REF_OID, GIT_REF_SYMBOLIC
from pygit2 import GitError, GIT_REF_OID, GIT_REF_SYMBOLIC, Signature
from . import utils
@@ -77,13 +77,13 @@ class ReferencesTest(utils.RepoTestCase):
def test_reference_set_sha(self):
NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533'
reference = self.repo.lookup_reference('refs/heads/master')
reference.target = NEW_COMMIT
reference.set_target(NEW_COMMIT)
self.assertEqual(reference.target.hex, NEW_COMMIT)
def test_reference_set_sha_prefix(self):
NEW_COMMIT = '5ebeeebb320790caf276b9fc8b24546d63316533'
reference = self.repo.lookup_reference('refs/heads/master')
reference.target = NEW_COMMIT[0:6]
reference.set_target(NEW_COMMIT[0:6])
self.assertEqual(reference.target.hex, NEW_COMMIT)
@@ -100,7 +100,7 @@ class ReferencesTest(utils.RepoTestCase):
def test_set_target(self):
reference = self.repo.lookup_reference('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
reference.target = 'refs/heads/i18n'
reference.set_target('refs/heads/i18n')
self.assertEqual(reference.target, 'refs/heads/i18n')
def test_get_shorthand(self):
@@ -109,6 +109,16 @@ class ReferencesTest(utils.RepoTestCase):
reference = self.repo.create_reference('refs/remotes/origin/master', LAST_COMMIT)
self.assertEqual(reference.shorthand, 'origin/master')
def test_set_target_with_message(self):
reference = self.repo.lookup_reference('HEAD')
self.assertEqual(reference.target, 'refs/heads/master')
sig = Signature('foo', 'bar')
msg = 'Hello log'
reference.set_target('refs/heads/i18n', signature=sig, message=msg)
self.assertEqual(reference.target, 'refs/heads/i18n')
self.assertEqual(list(reference.log())[0].message, msg)
self.assertEqualSignature(list(reference.log())[0].committer, sig)
def test_delete(self):
repo = self.repo
@@ -124,8 +134,6 @@ class ReferencesTest(utils.RepoTestCase):
self.assertRaises(GitError, getattr, reference, 'name')
self.assertRaises(GitError, getattr, reference, 'type')
self.assertRaises(GitError, getattr, reference, 'target')
self.assertRaises(GitError, setattr, reference, 'target', LAST_COMMIT)
self.assertRaises(GitError, setattr, reference, 'target', "a/b/c")
self.assertRaises(GitError, reference.delete)
self.assertRaises(GitError, reference.resolve)
self.assertRaises(GitError, reference.rename, "refs/tags/version2")

View File

@@ -76,10 +76,10 @@ class RepositoryTest(utils.BareRepoTestCase):
def test_set_head(self):
# Test setting a detatched HEAD.
self.repo.head = Oid(hex=PARENT_SHA)
self.repo.set_head(Oid(hex=PARENT_SHA))
self.assertEqual(self.repo.head.target.hex, PARENT_SHA)
# And test setting a normal HEAD.
self.repo.head = "refs/heads/master"
self.repo.set_head("refs/heads/master")
self.assertEqual(self.repo.head.name, "refs/heads/master")
self.assertEqual(self.repo.head.target.hex, HEAD_SHA)