Files
deb-python-pygit2/src/repository.c
Hervé Cauwelier 61c330f57d split create_blob_fromfile into fromworkdir and fromdisk to match libgit2
Both create loose blobs but fromworkdir assert the file is inside the working directory.
2013-05-01 13:05:30 +02:00

1293 lines
34 KiB
C

/*
* Copyright 2010-2013 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.
*/
#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "error.h"
#include "types.h"
#include "reference.h"
#include "utils.h"
#include "object.h"
#include "oid.h"
#include "note.h"
#include "repository.h"
#include "remote.h"
extern PyObject *GitError;
extern PyTypeObject IndexType;
extern PyTypeObject WalkerType;
extern PyTypeObject SignatureType;
extern PyTypeObject TreeType;
extern PyTypeObject TreeBuilderType;
extern PyTypeObject ConfigType;
extern PyTypeObject DiffType;
extern PyTypeObject RemoteType;
extern PyTypeObject ReferenceType;
extern PyTypeObject NoteType;
extern PyTypeObject NoteIterType;
git_otype
int_to_loose_object_type(int type_id)
{
switch((git_otype)type_id) {
case GIT_OBJ_COMMIT: return GIT_OBJ_COMMIT;
case GIT_OBJ_TREE: return GIT_OBJ_TREE;
case GIT_OBJ_BLOB: return GIT_OBJ_BLOB;
case GIT_OBJ_TAG: return GIT_OBJ_TAG;
default: return GIT_OBJ_BAD;
}
}
PyObject *
lookup_object(Repository *repo, const git_oid *oid, git_otype type)
{
int err;
git_object *obj;
err = git_object_lookup_prefix(&obj, repo->repo, oid, GIT_OID_HEXSZ,
type);
if (err < 0)
return Error_set_oid(err, oid, GIT_OID_HEXSZ);
return wrap_object(obj, repo);
}
int
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
{
char *path;
int err;
if (kwds) {
PyErr_SetString(PyExc_TypeError,
"Repository takes no keyword arguments");
return -1;
}
if (!PyArg_ParseTuple(args, "s", &path))
return -1;
err = git_repository_open(&self->repo, path);
if (err < 0) {
Error_set_str(err, path);
return -1;
}
self->config = NULL;
self->index = NULL;
return 0;
}
void
Repository_dealloc(Repository *self)
{
PyObject_GC_UnTrack(self);
Py_CLEAR(self->index);
Py_CLEAR(self->config);
git_repository_free(self->repo);
PyObject_GC_Del(self);
}
int
Repository_traverse(Repository *self, visitproc visit, void *arg)
{
Py_VISIT(self->index);
return 0;
}
int
Repository_clear(Repository *self)
{
Py_CLEAR(self->index);
return 0;
}
static int
Repository_build_as_iter(const git_oid *oid, void *accum)
{
int err;
PyObject *oid_str = git_oid_to_py_str(oid);
err = PyList_Append((PyObject*)accum, oid_str);
Py_DECREF(oid_str);
return err;
}
PyObject *
Repository_as_iter(Repository *self)
{
git_odb *odb;
int err;
PyObject *accum = PyList_New(0);
err = git_repository_odb(&odb, self->repo);
if (err < 0)
return Error_set(err);
err = git_odb_foreach(odb, Repository_build_as_iter, (void*)accum);
git_odb_free(odb);
if (err == GIT_EUSER) {
return NULL;
} else if (err < 0) {
return Error_set(err);
}
return PyObject_GetIter(accum);
}
PyDoc_STRVAR(Repository_head__doc__,
"Current head reference of the repository.");
PyObject *
Repository_head__get__(Repository *self)
{
git_reference *head;
const git_oid *oid;
PyObject *pyobj;
int err;
err = git_repository_head(&head, self->repo);
if (err < 0) {
if (err == GIT_ENOTFOUND)
PyErr_SetString(GitError, "head reference does not exist");
else
Error_set(err);
return NULL;
}
return wrap_reference(head);
}
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.");
PyObject *
Repository_head_is_detached__get__(Repository *self)
{
if (git_repository_head_detached(self->repo) > 0)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PyDoc_STRVAR(Repository_head_is_orphaned__doc__,
"An orphan branch is one named from HEAD but which doesn't exist in the\n"
"refs namespace, because it doesn't have any commit to point to.");
PyObject *
Repository_head_is_orphaned__get__(Repository *self)
{
if (git_repository_head_orphan(self->repo) > 0)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PyDoc_STRVAR(Repository_is_empty__doc__,
"Check if a repository is empty.");
PyObject *
Repository_is_empty__get__(Repository *self)
{
if (git_repository_is_empty(self->repo) > 0)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PyDoc_STRVAR(Repository_is_bare__doc__,
"Check if a repository is a bare repository.");
PyObject *
Repository_is_bare__get__(Repository *self)
{
if (git_repository_is_bare(self->repo) > 0)
Py_RETURN_TRUE;
Py_RETURN_FALSE;
}
PyDoc_STRVAR(Repository_git_object_lookup_prefix__doc__,
"git_object_lookup_prefix(oid) -> Object\n"
"\n"
"Returns the Git object with the given oid.");
PyObject *
Repository_git_object_lookup_prefix(Repository *self, PyObject *key)
{
int err, len;
git_oid oid;
git_object *obj;
len = py_str_to_git_oid(key, &oid);
if (len < 0)
return NULL;
err = git_object_lookup_prefix(&obj, self->repo, &oid,
(unsigned int)len, GIT_OBJ_ANY);
if (err == 0)
return wrap_object(obj, self);
if (err == GIT_ENOTFOUND)
Py_RETURN_NONE;
return Error_set_oid(err, &oid, len);
}
PyDoc_STRVAR(Repository_revparse_single__doc__,
"revparse_single(revision) -> Object\n"
"\n"
"Find an object, as specified by a revision string. See\n"
"`man gitrevisions`, or the documentation for `git rev-parse` for\n"
"information on the syntax accepted.");
PyObject *
Repository_revparse_single(Repository *self, PyObject *py_spec)
{
git_object *c_obj;
char *c_spec;
int err;
/* 1- Get the C revision spec */
c_spec = py_str_to_c_str(py_spec, NULL);
if (c_spec == NULL)
return NULL;
/* 2- Lookup */
err = git_revparse_single(&c_obj, self->repo, c_spec);
if (err < 0) {
PyObject *err_obj = Error_set_str(err, c_spec);
free(c_spec);
return err_obj;
}
free(c_spec);
return wrap_object(c_obj, self);
}
git_odb_object *
Repository_read_raw(git_repository *repo, const git_oid *oid, size_t len)
{
git_odb *odb;
git_odb_object *obj;
int err;
err = git_repository_odb(&odb, repo);
if (err < 0) {
Error_set(err);
return NULL;
}
err = git_odb_read_prefix(&obj, odb, oid, (unsigned int)len);
git_odb_free(odb);
if (err < 0) {
Error_set_oid(err, oid, len);
return NULL;
}
return obj;
}
PyDoc_STRVAR(Repository_read__doc__,
"read(oid) -> type, data, size\n"
"\n"
"Read raw object data from the repository.");
PyObject *
Repository_read(Repository *self, PyObject *py_hex)
{
git_oid oid;
git_odb_object *obj;
int len;
PyObject* tuple;
len = py_str_to_git_oid(py_hex, &oid);
if (len < 0)
return NULL;
obj = Repository_read_raw(self->repo, &oid, len);
if (obj == NULL)
return NULL;
tuple = Py_BuildValue(
#if PY_MAJOR_VERSION == 2
"(ns#)",
#else
"(ny#)",
#endif
git_odb_object_type(obj),
git_odb_object_data(obj),
git_odb_object_size(obj));
git_odb_object_free(obj);
return tuple;
}
PyDoc_STRVAR(Repository_write__doc__,
"write(type, data) -> oid\n"
"\n"
"Write raw object data into the repository. First arg is the object type,\n"
"the second one a buffer with data. Return the object id (sha) of of the\n"
"created object.");
PyObject *
Repository_write(Repository *self, PyObject *args)
{
int err;
git_oid oid;
git_odb *odb;
git_odb_stream* stream;
int type_id;
const char* buffer;
Py_ssize_t buflen;
git_otype type;
if (!PyArg_ParseTuple(args, "Is#", &type_id, &buffer, &buflen))
return NULL;
type = int_to_loose_object_type(type_id);
if (type == GIT_OBJ_BAD)
return PyErr_Format(PyExc_ValueError, "%d", type_id);
err = git_repository_odb(&odb, self->repo);
if (err < 0)
return Error_set(err);
err = git_odb_open_wstream(&stream, odb, buflen, type);
git_odb_free(odb);
if (err < 0)
return Error_set(err);
stream->write(stream, buffer, buflen);
err = stream->finalize_write(&oid, stream);
stream->free(stream);
return git_oid_to_python(oid.id);
}
PyDoc_STRVAR(Repository_index__doc__, "Index file.");
PyObject *
Repository_index__get__(Repository *self, void *closure)
{
int err;
git_index *index;
Index *py_index;
assert(self->repo);
if (self->index == NULL) {
err = git_repository_index(&index, self->repo);
if (err < 0)
return Error_set(err);
py_index = PyObject_GC_New(Index, &IndexType);
if (!py_index) {
git_index_free(index);
return NULL;
}
Py_INCREF(self);
py_index->repo = self;
py_index->index = index;
PyObject_GC_Track(py_index);
self->index = (PyObject*)py_index;
}
Py_INCREF(self->index);
return self->index;
}
PyDoc_STRVAR(Repository_path__doc__,
"The normalized path to the git repository.");
PyObject *
Repository_path__get__(Repository *self, void *closure)
{
return to_path(git_repository_path(self->repo));
}
PyDoc_STRVAR(Repository_workdir__doc__,
"The normalized path to the working directory of the repository. If the\n"
"repository is bare, None will be returned.");
PyObject *
Repository_workdir__get__(Repository *self, void *closure)
{
const char *c_path;
c_path = git_repository_workdir(self->repo);
if (c_path == NULL)
Py_RETURN_NONE;
return to_path(c_path);
}
PyDoc_STRVAR(Repository_config__doc__,
"Get the configuration file for this repository.\n"
"\n"
"If a configuration file has not been set, the default config set for the\n"
"repository will be returned, including global and system configurations\n"
"(if they are available).");
PyObject *
Repository_config__get__(Repository *self)
{
int err;
git_config *config;
Config *py_config;
assert(self->repo);
if (self->config == NULL) {
err = git_repository_config(&config, self->repo);
if (err < 0)
return Error_set(err);
py_config = PyObject_New(Config, &ConfigType);
if (py_config == NULL) {
git_config_free(config);
return NULL;
}
py_config->config = config;
self->config = (PyObject*)py_config;
} else {
Py_INCREF(self->config);
}
return self->config;
}
PyDoc_STRVAR(Repository_walk__doc__,
"walk(oid, sort_mode) -> iterator\n"
"\n"
"Generator that traverses the history starting from the given commit.");
PyObject *
Repository_walk(Repository *self, PyObject *args)
{
PyObject *value;
unsigned int sort;
int err;
git_oid oid;
git_revwalk *walk;
Walker *py_walker;
if (!PyArg_ParseTuple(args, "OI", &value, &sort))
return NULL;
err = git_revwalk_new(&walk, self->repo);
if (err < 0)
return Error_set(err);
/* Sort */
git_revwalk_sorting(walk, sort);
/* Push */
if (value != Py_None) {
err = py_str_to_git_oid_expand(self->repo, value, &oid);
if (err < 0) {
git_revwalk_free(walk);
return Error_set(err);
}
err = git_revwalk_push(walk, &oid);
if (err < 0) {
git_revwalk_free(walk);
return Error_set(err);
}
}
py_walker = PyObject_New(Walker, &WalkerType);
if (!py_walker) {
git_revwalk_free(walk);
return NULL;
}
Py_INCREF(self);
py_walker->repo = self;
py_walker->walk = walk;
return (PyObject*)py_walker;
}
PyDoc_STRVAR(Repository_create_blob__doc__,
"create_blob(data) -> bytes\n"
"\n"
"Create a new blob from memory.");
PyObject *
Repository_create_blob(Repository *self, PyObject *args)
{
git_oid oid;
const char *raw;
Py_ssize_t size;
int err;
if (!PyArg_ParseTuple(args, "s#", &raw, &size))
return NULL;
err = git_blob_create_frombuffer(&oid, self->repo, (const void*)raw, size);
if (err < 0)
return Error_set(err);
return git_oid_to_python(oid.id);
}
PyDoc_STRVAR(Repository_create_blob_fromworkdir__doc__,
"create_blob_fromworkdir(path) -> bytes\n"
"\n"
"Create a new blob from a file within the working directory.");
PyObject *
Repository_create_blob_fromworkdir(Repository *self, PyObject *args)
{
git_oid oid;
const char* path;
int err;
if (!PyArg_ParseTuple(args, "s", &path))
return NULL;
err = git_blob_create_fromworkdir(&oid, self->repo, path);
if (err < 0)
return Error_set(err);
return git_oid_to_python(oid.id);
}
PyDoc_STRVAR(Repository_create_blob_fromdisk__doc__,
"create_blob_fromdisk(path) -> bytes\n"
"\n"
"Create a new blob from file.");
PyObject *
Repository_create_blob_fromdisk(Repository *self, PyObject *args)
{
git_oid oid;
const char* path;
int err;
if (!PyArg_ParseTuple(args, "s", &path))
return NULL;
err = git_blob_create_fromdisk(&oid, self->repo, path);
if (err < 0)
return Error_set(err);
return git_oid_to_python(oid.id);
}
PyDoc_STRVAR(Repository_create_commit__doc__,
"create_commit(reference, author, committer, message, tree, parents[, encoding]) -> bytes\n"
"\n"
"Create a new commit object, return its SHA.");
PyObject *
Repository_create_commit(Repository *self, PyObject *args)
{
Signature *py_author, *py_committer;
PyObject *py_oid, *py_message, *py_parents, *py_parent;
PyObject *py_result = NULL;
char *message = NULL;
char *update_ref = NULL;
char *encoding = NULL;
git_oid oid;
git_tree *tree = NULL;
int parent_count;
git_commit **parents = NULL;
int err = 0, i = 0, len;
if (!PyArg_ParseTuple(args, "zO!O!OOO!|s",
&update_ref,
&SignatureType, &py_author,
&SignatureType, &py_committer,
&py_message,
&py_oid,
&PyList_Type, &py_parents,
&encoding))
return NULL;
len = py_str_to_git_oid(py_oid, &oid);
if (len < 0)
goto out;
message = py_str_to_c_str(py_message, encoding);
if (message == NULL)
goto out;
err = git_tree_lookup_prefix(&tree, self->repo, &oid, (unsigned int)len);
if (err < 0) {
Error_set(err);
goto out;
}
parent_count = (int)PyList_Size(py_parents);
parents = malloc(parent_count * sizeof(git_commit*));
if (parents == NULL) {
PyErr_SetNone(PyExc_MemoryError);
goto out;
}
for (; i < parent_count; i++) {
py_parent = PyList_GET_ITEM(py_parents, i);
len = py_str_to_git_oid(py_parent, &oid);
if (len < 0)
goto out;
if (git_commit_lookup_prefix(&parents[i], self->repo, &oid,
(unsigned int)len))
goto out;
}
err = git_commit_create(&oid, self->repo, update_ref,
py_author->signature, py_committer->signature,
encoding, message, tree, parent_count,
(const git_commit**)parents);
if (err < 0) {
Error_set(err);
goto out;
}
py_result = git_oid_to_python(oid.id);
out:
free(message);
git_tree_free(tree);
while (i > 0) {
i--;
git_commit_free(parents[i]);
}
free(parents);
return py_result;
}
PyDoc_STRVAR(Repository_create_tag__doc__,
"create_tag(name, oid, type, tagger, message) -> bytes\n"
"\n"
"Create a new tag object, return its SHA.");
PyObject *
Repository_create_tag(Repository *self, PyObject *args)
{
PyObject *py_oid;
Signature *py_tagger;
char *tag_name, *message;
git_oid oid;
git_object *target = NULL;
int err, target_type, len;
if (!PyArg_ParseTuple(args, "sOiO!s",
&tag_name,
&py_oid,
&target_type,
&SignatureType, &py_tagger,
&message))
return NULL;
len = py_str_to_git_oid(py_oid, &oid);
if (len < 0)
return NULL;
err = git_object_lookup_prefix(&target, self->repo, &oid,
(unsigned int)len, target_type);
err = err < 0 ? err : git_tag_create(&oid, self->repo, tag_name, target,
py_tagger->signature, message, 0);
git_object_free(target);
if (err < 0)
return Error_set_oid(err, &oid, len);
return git_oid_to_python(oid.id);
}
PyDoc_STRVAR(Repository_listall_references__doc__,
"listall_references([flags]) -> (str, ...)\n"
"\n"
"Return a tuple with all the references in the repository.");
PyObject *
Repository_listall_references(Repository *self, PyObject *args)
{
unsigned list_flags=GIT_REF_LISTALL;
git_strarray c_result;
PyObject *py_result, *py_string;
unsigned index;
int err;
/* 1- Get list_flags */
if (!PyArg_ParseTuple(args, "|I", &list_flags))
return NULL;
/* 2- Get the C result */
err = git_reference_list(&c_result, self->repo, list_flags);
if (err < 0)
return Error_set(err);
/* 3- Create a new PyTuple */
py_result = PyTuple_New(c_result.count);
if (py_result == NULL)
goto out;
/* 4- Fill it */
for (index=0; index < c_result.count; index++) {
py_string = to_path((c_result.strings)[index]);
if (py_string == NULL) {
Py_CLEAR(py_result);
goto out;
}
PyTuple_SET_ITEM(py_result, index, py_string);
}
out:
git_strarray_free(&c_result);
return py_result;
}
PyDoc_STRVAR(Repository_lookup_reference__doc__,
"lookup_reference(name) -> Reference\n"
"\n"
"Lookup a reference by its name in a repository.");
PyObject *
Repository_lookup_reference(Repository *self, PyObject *py_name)
{
git_reference *c_reference;
char *c_name;
int err;
/* 1- Get the C name */
c_name = py_path_to_c_str(py_name);
if (c_name == NULL)
return NULL;
/* 2- Lookup */
err = git_reference_lookup(&c_reference, self->repo, c_name);
if (err < 0) {
PyObject *err_obj = Error_set_str(err, c_name);
free(c_name);
return err_obj;
}
free(c_name);
/* 3- Make an instance of Reference and return it */
return wrap_reference(c_reference);
}
PyDoc_STRVAR(Repository_git_reference_create__doc__,
"git_reference_create(name, target, force) -> Reference\n"
"\n"
"Create a new reference \"name\" which points to an object.\n"
"\n"
"Arguments:\n"
"\n"
"force\n"
" If True references will be overridden, otherwise (the default) an\n"
" exception is raised.\n"
"\n"
"Examples::\n"
"\n"
" repo.git_reference_create('refs/heads/foo', repo.head.hex, False)");
PyObject *
Repository_git_reference_create(Repository *self, PyObject *args,
PyObject *kw)
{
PyObject *py_obj;
git_reference *c_reference;
char *c_name;
git_oid oid;
int err, force;
if (!PyArg_ParseTuple(args, "sOi", &c_name, &py_obj, &force))
return NULL;
err = py_str_to_git_oid_expand(self->repo, py_obj, &oid);
if (err < 0)
return Error_set(err);
err = git_reference_create(&c_reference, self->repo, c_name, &oid, force);
if (err < 0)
return Error_set(err);
return wrap_reference(c_reference);
}
PyDoc_STRVAR(Repository_git_reference_symbolic_create__doc__,
"git_reference_symbolic_create(name, source, force) -> Reference\n"
"\n"
"Create a new reference \"name\" which points to another reference.\n"
"\n"
"Arguments:\n"
"\n"
"force\n"
" If True references will be overridden, otherwise (the default) an\n"
" exception is raised.\n"
"\n"
"Examples::\n"
"\n"
" repo.git_reference_symbolic_create('refs/tags/foo', 'refs/heads/master', False)");
PyObject *
Repository_git_reference_symbolic_create(Repository *self, PyObject *args,
PyObject *kw)
{
git_reference *c_reference;
char *c_name, *c_target;
int err, force;
if (!PyArg_ParseTuple(args, "ssi", &c_name, &c_target, &force))
return NULL;
err = git_reference_symbolic_create(&c_reference, self->repo, c_name,
c_target, force);
if (err < 0)
return Error_set(err);
return wrap_reference(c_reference);
}
PyDoc_STRVAR(Repository_status__doc__,
"status() -> {str: int}\n"
"\n"
"Reads the status of the repository and returns a dictionary with file\n"
"paths as keys and status flags as values. See pygit2.GIT_STATUS_*.");
int
read_status_cb(const char *path, unsigned int status_flags, void *payload)
{
/* This is the callback that will be called in git_status_foreach. It
* will be called for every path.*/
PyObject *flags;
int err;
flags = PyLong_FromLong((long) status_flags);
err = PyDict_SetItemString(payload, path, flags);
Py_CLEAR(flags);
if (err < 0)
return GIT_ERROR;
return GIT_OK;
}
PyObject *
Repository_status(Repository *self, PyObject *args)
{
PyObject *payload_dict;
payload_dict = PyDict_New();
git_status_foreach(self->repo, read_status_cb, payload_dict);
return payload_dict;
}
PyDoc_STRVAR(Repository_status_file__doc__,
"status_file(path) -> int\n"
"\n"
"Returns the status of the given file path.");
PyObject *
Repository_status_file(Repository *self, PyObject *value)
{
char *path;
unsigned int status;
int err;
path = py_path_to_c_str(value);
if (!path)
return NULL;
err = git_status_file(&status, self->repo, path);
if (err < 0) {
PyObject *err_obj = Error_set_str(err, path);
free(path);
return err_obj;
}
return PyLong_FromLong(status);
}
PyDoc_STRVAR(Repository_TreeBuilder__doc__,
"TreeBuilder([tree]) -> TreeBuilder\n"
"\n"
"Create a TreeBuilder object for this repository.");
PyObject *
Repository_TreeBuilder(Repository *self, PyObject *args)
{
TreeBuilder *builder;
git_treebuilder *bld;
PyObject *py_src = NULL;
git_oid oid;
git_tree *tree = NULL;
git_tree *must_free = NULL;
int err;
if (!PyArg_ParseTuple(args, "|O", &py_src))
return NULL;
if (py_src) {
if (PyObject_TypeCheck(py_src, &TreeType)) {
Tree *py_tree = (Tree *)py_src;
if (py_tree->repo->repo != self->repo) {
/* return Error_set(GIT_EINVALIDARGS); */
return Error_set(GIT_ERROR);
}
tree = py_tree->tree;
} else {
err = py_str_to_git_oid_expand(self->repo, py_src, &oid);
if (err < 0)
return NULL;
err = git_tree_lookup(&tree, self->repo, &oid);
if (err < 0)
return Error_set(err);
must_free = tree;
}
}
err = git_treebuilder_create(&bld, tree);
if (must_free != NULL)
git_tree_free(must_free);
if (err < 0)
return Error_set(err);
builder = PyObject_New(TreeBuilder, &TreeBuilderType);
if (builder) {
builder->repo = self;
builder->bld = bld;
Py_INCREF(self);
}
return (PyObject*)builder;
}
PyDoc_STRVAR(Repository_create_remote__doc__,
"create_remote(name, url) -> Remote\n"
"\n"
"Creates a new remote.");
PyObject *
Repository_create_remote(Repository *self, PyObject *args)
{
Remote *py_remote;
git_remote *remote;
char *name = NULL, *url = NULL;
int err;
if (!PyArg_ParseTuple(args, "ss", &name, &url))
return NULL;
err = git_remote_create(&remote, self->repo, name, url);
if (err < 0)
return Error_set(err);
py_remote = PyObject_New(Remote, &RemoteType);
Py_INCREF(self);
py_remote->repo = self;
py_remote->remote = remote;
return (PyObject*) py_remote;
}
PyDoc_STRVAR(Repository_remotes__doc__, "Returns all configured remotes.");
PyObject *
Repository_remotes__get__(Repository *self)
{
git_strarray remotes;
PyObject* py_list = NULL, *py_args = NULL;
Remote *py_remote;
size_t i;
git_remote_list(&remotes, self->repo);
py_list = PyList_New(remotes.count);
for (i=0; i < remotes.count; ++i) {
py_remote = PyObject_New(Remote, &RemoteType);
py_args = Py_BuildValue("Os", self, remotes.strings[i]);
Remote_init(py_remote, py_args, NULL);
PyList_SetItem(py_list, i, (PyObject*) py_remote);
}
git_strarray_free(&remotes);
return (PyObject*) py_list;
}
PyDoc_STRVAR(Repository_checkout__doc__,
"checkout([strategy:int, reference:Reference])\n"
"\n"
"Checks out a tree by a given reference and modifies the HEAD pointer\n"
"Standard checkout strategy is pygit2.GIT_CHECKOUT_SAFE_CREATE\n"
"If no reference is given, checkout will use HEAD instead.");
PyObject *
Repository_checkout(Repository *self, PyObject *args, PyObject *kw)
{
git_checkout_opts opts = GIT_CHECKOUT_OPTS_INIT;
unsigned int strategy = GIT_CHECKOUT_SAFE_CREATE;
Reference* ref = NULL;
git_object* object;
const git_oid* id;
int err, head = 0;
static char *kwlist[] = {"strategy", "reference", "head", NULL};
if (!PyArg_ParseTupleAndKeywords(args, kw, "|IO!i", kwlist,
&strategy, &ReferenceType, &ref, &head))
return NULL;
if (ref != NULL) { /* checkout from treeish */
id = git_reference_target(ref->reference);
err = git_object_lookup(&object, self->repo, id, GIT_OBJ_COMMIT);
if (err == GIT_OK) {
opts.checkout_strategy = strategy;
err = git_checkout_tree(self->repo, object, &opts);
if (err == GIT_OK) {
err = git_repository_set_head(self->repo,
git_reference_name(ref->reference));
}
git_object_free(object);
}
} else { /* checkout from head / index */
opts.checkout_strategy = strategy;
err = (!head) ? git_checkout_index(self->repo, NULL, &opts) :
git_checkout_head(self->repo, &opts);
}
if (err < 0)
return Error_set(err);
Py_RETURN_NONE;
}
PyDoc_STRVAR(Repository_notes__doc__, "");
PyObject *
Repository_notes(Repository *self, PyObject* args)
{
NoteIter *iter = NULL;
char *ref = "refs/notes/commits";
int err = GIT_ERROR;
if (!PyArg_ParseTuple(args, "|s", &ref))
return NULL;
iter = PyObject_New(NoteIter, &NoteIterType);
if (iter != NULL) {
iter->repo = self;
iter->ref = ref;
err = git_note_iterator_new(&iter->iter, self->repo, iter->ref);
if (err == GIT_OK) {
Py_INCREF(self);
return (PyObject*)iter;
}
}
return Error_set(err);
}
PyDoc_STRVAR(Repository_create_note__doc__,
"create_note(message, author, committer, annotated_id [,ref, force]) -> ID\n"
"\n"
"Create a new note for an object, return its SHA-ID."
"If no ref is given 'refs/notes/commits' will be used.");
PyObject *
Repository_create_note(Repository *self, PyObject* args)
{
git_oid note_id, annotated_id;
char *annotated = NULL, *message = NULL, *ref = "refs/notes/commits";
int err = GIT_ERROR;
unsigned int force = 0;
Signature *py_author, *py_committer;
if (!PyArg_ParseTuple(args, "sO!O!s|si",
&message,
&SignatureType, &py_author,
&SignatureType, &py_committer,
&annotated, &ref, &force))
return NULL;
err = git_oid_fromstr(&annotated_id, annotated);
if (err < 0)
return Error_set(err);
err = git_note_create(&note_id, self->repo, py_author->signature,
py_committer->signature, ref,
&annotated_id, message, force);
if (err < 0)
return Error_set(err);
return git_oid_to_python(note_id.id);
}
PyDoc_STRVAR(Repository_lookup_note__doc__,
"lookup_note(annotated_id [, ref]) -> Note\n"
"\n"
"Lookup a note for an annotated object in a repository.");
PyObject *
Repository_lookup_note(Repository *self, PyObject* args)
{
git_oid annotated_id;
char* annotated = NULL, *ref = "refs/notes/commits";
int err;
if (!PyArg_ParseTuple(args, "s|s", &annotated, &ref))
return NULL;
err = git_oid_fromstr(&annotated_id, annotated);
if (err < 0)
return Error_set(err);
return (PyObject*) wrap_note(self, &annotated_id, ref);
}
PyMethodDef Repository_methods[] = {
METHOD(Repository, create_blob, METH_VARARGS),
METHOD(Repository, create_blob_fromworkdir, METH_VARARGS),
METHOD(Repository, create_blob_fromdisk, METH_VARARGS),
METHOD(Repository, create_commit, METH_VARARGS),
METHOD(Repository, create_tag, METH_VARARGS),
METHOD(Repository, TreeBuilder, METH_VARARGS),
METHOD(Repository, walk, METH_VARARGS),
METHOD(Repository, read, METH_O),
METHOD(Repository, write, METH_VARARGS),
METHOD(Repository, git_reference_create, METH_VARARGS),
METHOD(Repository, git_reference_symbolic_create, METH_VARARGS),
METHOD(Repository, listall_references, METH_VARARGS),
METHOD(Repository, lookup_reference, METH_O),
METHOD(Repository, revparse_single, METH_O),
METHOD(Repository, status, METH_NOARGS),
METHOD(Repository, status_file, METH_O),
METHOD(Repository, create_remote, METH_VARARGS),
METHOD(Repository, checkout, METH_VARARGS|METH_KEYWORDS),
METHOD(Repository, notes, METH_VARARGS),
METHOD(Repository, create_note, METH_VARARGS),
METHOD(Repository, lookup_note, METH_VARARGS),
METHOD(Repository, git_object_lookup_prefix, METH_O),
{NULL}
};
PyGetSetDef Repository_getseters[] = {
GETTER(Repository, index),
GETTER(Repository, path),
GETTER(Repository, head),
GETTER(Repository, head_is_detached),
GETTER(Repository, head_is_orphaned),
GETTER(Repository, is_empty),
GETTER(Repository, is_bare),
GETTER(Repository, config),
GETTER(Repository, workdir),
GETTER(Repository, remotes),
{NULL}
};
PyDoc_STRVAR(Repository__doc__,
"Repository(path) -> Repository\n"
"\n"
"Git repository.");
PyTypeObject RepositoryType = {
PyVarObject_HEAD_INIT(NULL, 0)
"_pygit2.Repository", /* tp_name */
sizeof(Repository), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)Repository_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT |
Py_TPFLAGS_BASETYPE |
Py_TPFLAGS_HAVE_GC, /* tp_flags */
Repository__doc__, /* tp_doc */
(traverseproc)Repository_traverse, /* tp_traverse */
(inquiry)Repository_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
(getiterfunc)Repository_as_iter, /* tp_iter */
0, /* tp_iternext */
Repository_methods, /* tp_methods */
0, /* tp_members */
Repository_getseters, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
(initproc)Repository_init, /* tp_init */
0, /* tp_alloc */
0, /* tp_new */
};