Start implementing remotes with CFFI
This moves enough code into python with CFFI to pass the test_remotes unit tests. There is no credentials support yet. There is a small change in the return value of Remote.fetch() in that we now return a TransferProgress object instead of extracting a few values into a dictionary.
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ pygit2/__pycache__
|
|||||||
*.egg-info
|
*.egg-info
|
||||||
*.swp
|
*.swp
|
||||||
docs/_build
|
docs/_build
|
||||||
|
__pycache__
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ from .repository import Repository
|
|||||||
from .version import __version__
|
from .version import __version__
|
||||||
from .settings import Settings
|
from .settings import Settings
|
||||||
from .credentials import *
|
from .credentials import *
|
||||||
|
from .remote import Remote
|
||||||
|
|
||||||
def init_repository(path, bare=False):
|
def init_repository(path, bare=False):
|
||||||
"""
|
"""
|
||||||
|
|||||||
127
pygit2/decl.h
Normal file
127
pygit2/decl.h
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
typedef ... git_repository;
|
||||||
|
typedef ... git_remote;
|
||||||
|
typedef ... git_refspec;
|
||||||
|
typedef ... git_push;
|
||||||
|
typedef ... git_cred;
|
||||||
|
typedef ... git_oid;
|
||||||
|
|
||||||
|
typedef struct git_strarray {
|
||||||
|
char **strings;
|
||||||
|
size_t count;
|
||||||
|
} git_strarray;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GIT_OK = 0,
|
||||||
|
GIT_ERROR = -1,
|
||||||
|
GIT_ENOTFOUND = -3,
|
||||||
|
GIT_EEXISTS = -4,
|
||||||
|
GIT_EAMBIGUOUS = -5,
|
||||||
|
GIT_EBUFS = -6,
|
||||||
|
GIT_EUSER = -7,
|
||||||
|
GIT_EBAREREPO = -8,
|
||||||
|
GIT_EUNBORNBRANCH = -9,
|
||||||
|
GIT_EUNMERGED = -10,
|
||||||
|
GIT_ENONFASTFORWARD = -11,
|
||||||
|
GIT_EINVALIDSPEC = -12,
|
||||||
|
GIT_EMERGECONFLICT = -13,
|
||||||
|
GIT_ELOCKED = -14,
|
||||||
|
|
||||||
|
GIT_PASSTHROUGH = -30,
|
||||||
|
GIT_ITEROVER = -31,
|
||||||
|
} git_error_code;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *message;
|
||||||
|
int klass;
|
||||||
|
} git_error;
|
||||||
|
|
||||||
|
const git_error * giterr_last(void);
|
||||||
|
|
||||||
|
void git_strarray_free(git_strarray *array);
|
||||||
|
|
||||||
|
typedef struct git_transfer_progress {
|
||||||
|
unsigned int total_objects;
|
||||||
|
unsigned int indexed_objects;
|
||||||
|
unsigned int received_objects;
|
||||||
|
unsigned int local_objects;
|
||||||
|
unsigned int total_deltas;
|
||||||
|
unsigned int indexed_deltas;
|
||||||
|
size_t received_bytes;
|
||||||
|
} git_transfer_progress;
|
||||||
|
|
||||||
|
typedef enum git_remote_completion_type {
|
||||||
|
GIT_REMOTE_COMPLETION_DOWNLOAD,
|
||||||
|
GIT_REMOTE_COMPLETION_INDEXING,
|
||||||
|
GIT_REMOTE_COMPLETION_ERROR,
|
||||||
|
} git_remote_completion_type;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GIT_DIRECTION_FETCH = 0,
|
||||||
|
GIT_DIRECTION_PUSH = 1
|
||||||
|
} git_direction;
|
||||||
|
|
||||||
|
typedef struct git_remote_callbacks {
|
||||||
|
unsigned int version;
|
||||||
|
int (*progress)(const char *str, int len, void *data);
|
||||||
|
int (*completion)(git_remote_completion_type type, void *data);
|
||||||
|
int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data);
|
||||||
|
int (*transfer_progress)(const git_transfer_progress *stats, void *data);
|
||||||
|
int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
|
||||||
|
void *payload;
|
||||||
|
} git_remote_callbacks ;
|
||||||
|
|
||||||
|
int git_remote_list(git_strarray *out, git_repository *repo);
|
||||||
|
int git_remote_load(git_remote **out, git_repository *repo, const char *name);
|
||||||
|
int git_remote_create(git_remote **out,
|
||||||
|
git_repository *repo,
|
||||||
|
const char *name,
|
||||||
|
const char *url);
|
||||||
|
const char * git_remote_name(const git_remote *remote);
|
||||||
|
typedef int (*git_remote_rename_problem_cb)(const char *problematic_refspec, void *payload);
|
||||||
|
int git_remote_rename(git_remote *remote,
|
||||||
|
const char *new_name,
|
||||||
|
git_remote_rename_problem_cb callback,
|
||||||
|
void *payload);
|
||||||
|
const char * git_remote_url(const git_remote *remote);
|
||||||
|
int git_remote_set_url(git_remote *remote, const char* url);
|
||||||
|
const char * git_remote_pushurl(const git_remote *remote);
|
||||||
|
int git_remote_set_pushurl(git_remote *remote, const char* url);
|
||||||
|
int git_remote_fetch(git_remote *remote);
|
||||||
|
const git_transfer_progress * git_remote_stats(git_remote *remote);
|
||||||
|
int git_remote_add_push(git_remote *remote, const char *refspec);
|
||||||
|
int git_remote_add_fetch(git_remote *remote, const char *refspec);
|
||||||
|
int git_remote_save(const git_remote *remote);
|
||||||
|
int git_remote_set_callbacks(git_remote *remote, const git_remote_callbacks *callbacks);
|
||||||
|
size_t git_remote_refspec_count(git_remote *remote);
|
||||||
|
const git_refspec * git_remote_get_refspec(git_remote *remote, size_t n);
|
||||||
|
|
||||||
|
int git_remote_get_fetch_refspecs(git_strarray *array, git_remote *remote);
|
||||||
|
int git_remote_set_fetch_refspecs(git_remote *remote, git_strarray *array);
|
||||||
|
int git_remote_get_push_refspecs(git_strarray *array, git_remote *remote);
|
||||||
|
int git_remote_set_push_refspecs(git_remote *remote, git_strarray *array);
|
||||||
|
|
||||||
|
void git_remote_free(git_remote *remote);
|
||||||
|
|
||||||
|
int git_push_new(git_push **push, git_remote *remote);
|
||||||
|
int git_push_add_refspec(git_push *push, const char *refspec);
|
||||||
|
int git_push_finish(git_push *push);
|
||||||
|
int git_push_unpack_ok(git_push *push);
|
||||||
|
|
||||||
|
int git_push_status_foreach(git_push *push,
|
||||||
|
int (*cb)(const char *ref, const char *msg, void *data),
|
||||||
|
void *data);
|
||||||
|
|
||||||
|
int git_push_update_tips(git_push *push);
|
||||||
|
void git_push_free(git_push *push);
|
||||||
|
|
||||||
|
const char * git_refspec_src(const git_refspec *refspec);
|
||||||
|
const char * git_refspec_dst(const git_refspec *refspec);
|
||||||
|
int git_refspec_force(const git_refspec *refspec);
|
||||||
|
const char * git_refspec_string(const git_refspec *refspec);
|
||||||
|
git_direction git_refspec_direction(const git_refspec *spec);
|
||||||
|
|
||||||
|
int git_refspec_src_matches(const git_refspec *refspec, const char *refname);
|
||||||
|
int git_refspec_dst_matches(const git_refspec *refspec, const char *refname);
|
||||||
|
|
||||||
|
int git_refspec_transform(char *out, size_t outlen, const git_refspec *spec, const char *name);
|
||||||
|
int git_refspec_rtransform(char *out, size_t outlen, const git_refspec *spec, const char *name);
|
||||||
55
pygit2/errors.py
Normal file
55
pygit2/errors.py
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
# -*- 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.
|
||||||
|
|
||||||
|
# Import from the Standard Library
|
||||||
|
from string import hexdigits
|
||||||
|
|
||||||
|
# ffi
|
||||||
|
from .ffi import ffi, C
|
||||||
|
|
||||||
|
from _pygit2 import GitError
|
||||||
|
|
||||||
|
def check_error(err):
|
||||||
|
if err >= 0:
|
||||||
|
return
|
||||||
|
|
||||||
|
message = "(no message provided)"
|
||||||
|
giterr = C.giterr_last()
|
||||||
|
if giterr != ffi.NULL:
|
||||||
|
message = ffi.string(giterr.message).decode()
|
||||||
|
|
||||||
|
if err in [C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EEXISTS, C.GIT_EAMBIGUOUS]:
|
||||||
|
raise ValueError(message)
|
||||||
|
elif err == C.GIT_ENOTFOUND:
|
||||||
|
raise KeyError(message)
|
||||||
|
elif err == C.GIT_EINVALIDSPEC:
|
||||||
|
raise ValueError(message)
|
||||||
|
elif err == C.GIT_ITEROVER:
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
raise GitError(message)
|
||||||
|
|
||||||
106
pygit2/ffi.py
Normal file
106
pygit2/ffi.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
# -*- 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.
|
||||||
|
|
||||||
|
# Import from the future
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
import inspect
|
||||||
|
from os import path
|
||||||
|
from cffi import FFI
|
||||||
|
import sys
|
||||||
|
|
||||||
|
if sys.version_info.major < 3:
|
||||||
|
def to_str(s, encoding='utf-8', errors='strict'):
|
||||||
|
if s == ffi.NULL:
|
||||||
|
return ffi.NULL
|
||||||
|
encoding = encoding or 'utf-8'
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
return s.encode(encoding, errors)
|
||||||
|
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
def to_str(s, encoding='utf-8', errors='strict'):
|
||||||
|
if isinstance(s, bytes):
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
return bytes(s, encoding, errors)
|
||||||
|
|
||||||
|
if sys.version_info.major < 3:
|
||||||
|
def is_string(s):
|
||||||
|
return isinstance(s, str)
|
||||||
|
else:
|
||||||
|
def is_string(s):
|
||||||
|
return isinstance(s, basestring)
|
||||||
|
|
||||||
|
ffi = FFI()
|
||||||
|
|
||||||
|
def strarray_to_strings(arr):
|
||||||
|
l = [None] * arr.count
|
||||||
|
for i in range(arr.count):
|
||||||
|
l[i] = ffi.string(arr.strings[i]).decode()
|
||||||
|
|
||||||
|
return l
|
||||||
|
|
||||||
|
def strings_to_strarray(l):
|
||||||
|
"""Convert a list of strings to a git_strarray
|
||||||
|
|
||||||
|
We return first the git_strarray* you can pass to libgit2 and a
|
||||||
|
list of references to the memory, which we must keep around for as
|
||||||
|
long as the git_strarray must live.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if not isinstance(l, list):
|
||||||
|
raise TypeError("Value must be a list")
|
||||||
|
|
||||||
|
arr = ffi.new('git_strarray *')
|
||||||
|
strings = ffi.new('char *[]', len(l))
|
||||||
|
|
||||||
|
# We need refs in order to keep a reference to the value returned
|
||||||
|
# by the ffi.new(). Otherwise, they will be freed and the memory
|
||||||
|
# re-used, with less than great consequences.
|
||||||
|
refs = [None] * len(l)
|
||||||
|
|
||||||
|
for i in range(len(l)):
|
||||||
|
if not is_string(l[i]):
|
||||||
|
raise TypeError("Value must be a string")
|
||||||
|
|
||||||
|
s = ffi.new('char []', l[i])
|
||||||
|
refs[i] = s
|
||||||
|
strings[i] = s
|
||||||
|
|
||||||
|
arr.strings = strings
|
||||||
|
arr.count = len(l)
|
||||||
|
|
||||||
|
return arr, refs
|
||||||
|
|
||||||
|
dir_path = path.dirname(path.abspath(inspect.getfile(inspect.currentframe())))
|
||||||
|
|
||||||
|
decl_path = path.join(dir_path, 'decl.h')
|
||||||
|
with open(decl_path, 'rb') as f:
|
||||||
|
ffi.cdef(f.read())
|
||||||
|
|
||||||
|
C = ffi.verify("#include <git2.h>", libraries=["git2"])
|
||||||
110
pygit2/refspec.py
Normal file
110
pygit2/refspec.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# -*- 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.
|
||||||
|
|
||||||
|
# Import from the future
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from .ffi import ffi, C, to_str
|
||||||
|
from .errors import check_error
|
||||||
|
|
||||||
|
class Refspec(object):
|
||||||
|
def __init__(self, owner, ptr):
|
||||||
|
self._owner = owner
|
||||||
|
self._refspec = ptr
|
||||||
|
|
||||||
|
@property
|
||||||
|
def src(self):
|
||||||
|
"""Source or lhs of the refspec"""
|
||||||
|
return ffi.string(C.git_refspec_src(self._refspec)).decode()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def dst(self):
|
||||||
|
"""Destinaton or rhs of the refspec"""
|
||||||
|
return ffi.string(C.git_refspec_dst(self._refspec)).decode()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def force(self):
|
||||||
|
"""Whether this refspeca llows non-fast-forward updates"""
|
||||||
|
return bool(C.git_refspec_force(self._refspec))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def string(self):
|
||||||
|
"""String which was used to create this refspec"""
|
||||||
|
return ffi.string(C.git_refspec_string(self._refspec)).decode()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def direction(self):
|
||||||
|
"""Direction of this refspec (fetch or push)"""
|
||||||
|
return C.git_refspec_direction(self._refspec)
|
||||||
|
|
||||||
|
def src_matches(self, ref):
|
||||||
|
"""src_matches(str) -> Bool
|
||||||
|
|
||||||
|
Returns whether the given string matches the source of this refspec"""
|
||||||
|
return bool(C.git_refspec_src_matches(self._refspec, to_str(ref)))
|
||||||
|
|
||||||
|
def dst_matches(self, ref):
|
||||||
|
"""dst_matches(str) -> Bool
|
||||||
|
|
||||||
|
Returns whether the given string matches the destination of this refspec"""
|
||||||
|
return bool(C.git_refspec_dst_matches(self._refspec, to_str(ref)))
|
||||||
|
|
||||||
|
def transform(self, ref):
|
||||||
|
"""transform(str) -> str
|
||||||
|
|
||||||
|
Transform a reference name according to this refspec from the lhs to the rhs."""
|
||||||
|
alen = len(ref)
|
||||||
|
err = C.GIT_EBUFS
|
||||||
|
ptr = None
|
||||||
|
ref_str = to_str(ref)
|
||||||
|
|
||||||
|
while err == C.GIT_EBUFS:
|
||||||
|
alen *= 2
|
||||||
|
ptr = ffi.new('char []', alen)
|
||||||
|
|
||||||
|
err = C.git_refspec_transform(ptr, alen, self._refspec, ref_str)
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
return ffi.string(ptr).decode()
|
||||||
|
|
||||||
|
def rtransform(self, ref):
|
||||||
|
"""transform(str) -> str
|
||||||
|
|
||||||
|
Transform a reference name according to this refspec from the lhs to the rhs"""
|
||||||
|
alen = len(ref)
|
||||||
|
err = C.GIT_EBUFS
|
||||||
|
ptr = None
|
||||||
|
ref_str = to_str(ref)
|
||||||
|
|
||||||
|
while err == C.GIT_EBUFS:
|
||||||
|
alen *= 2
|
||||||
|
ptr = ffi.new('char []', alen)
|
||||||
|
|
||||||
|
err = C.git_refspec_rtransform(ptr, alen, self._refspec, ref_str)
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
return ffi.string(ptr).decode()
|
||||||
207
pygit2/remote.py
Normal file
207
pygit2/remote.py
Normal file
@@ -0,0 +1,207 @@
|
|||||||
|
# -*- 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.
|
||||||
|
|
||||||
|
# Import from the future
|
||||||
|
from __future__ import absolute_import
|
||||||
|
|
||||||
|
from .ffi import ffi, C, to_str, strarray_to_strings, strings_to_strarray
|
||||||
|
from .errors import check_error, GitError
|
||||||
|
from .refspec import Refspec
|
||||||
|
|
||||||
|
def maybe_string(ptr):
|
||||||
|
if not ptr:
|
||||||
|
return None
|
||||||
|
|
||||||
|
return ffi.string(ptr).decode()
|
||||||
|
|
||||||
|
|
||||||
|
class TransferProgress(object):
|
||||||
|
"""Progress downloading and indexing data during a fetch"""
|
||||||
|
|
||||||
|
def __init__(self, tp):
|
||||||
|
self.total_objects = tp.total_objects
|
||||||
|
self.indexed_objects = tp.indexed_objects
|
||||||
|
self.received_objects = tp.received_objects
|
||||||
|
self.local_objects = tp.local_objects
|
||||||
|
self.total_deltas = tp.total_deltas
|
||||||
|
self.indexed_deltas = tp.indexed_deltas
|
||||||
|
self.received_bytes = tp.received_bytes
|
||||||
|
|
||||||
|
class Remote(object):
|
||||||
|
def __init__(self, repo, ptr):
|
||||||
|
"""The constructor is for internal use only"""
|
||||||
|
|
||||||
|
self._repo = repo
|
||||||
|
self._remote = ptr
|
||||||
|
|
||||||
|
# Build the callback structure
|
||||||
|
callbacks = ffi.new('git_remote_callbacks *')
|
||||||
|
callbacks.version = 1
|
||||||
|
callbacks.transfer_progress = self._transfer_progress_cb
|
||||||
|
# We need to make sure that this handle stays alive
|
||||||
|
self._self_handle = ffi.new_handle(self)
|
||||||
|
callbacks.payload = self._self_handle
|
||||||
|
|
||||||
|
err = C.git_remote_set_callbacks(self._remote, callbacks)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
C.git_remote_free(self._remote)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name(self):
|
||||||
|
return maybe_string(C.git_remote_name(self._remote))
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
err = C.git_remote_rename(self._remote, to_str(value), ffi.NULL, ffi.NULL)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
return maybe_string(C.git_remote_url(self._remote))
|
||||||
|
|
||||||
|
@url.setter
|
||||||
|
def url(self, value):
|
||||||
|
err = C.git_remote_set_url(self._remote, to_str(value))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def push_url(self):
|
||||||
|
return maybe_string(C.git_remote_pushurl(self._remote))
|
||||||
|
|
||||||
|
@push_url.setter
|
||||||
|
def push_url(self, value):
|
||||||
|
err = C.git_remote_set_pushurl(self._remote, to_str(value))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
err = C.git_remote_save(self._remote)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def fetch(self):
|
||||||
|
err = C.git_remote_fetch(self._remote)
|
||||||
|
if err == C.GIT_EUSER:
|
||||||
|
raise self._stored_exception
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return TransferProgress(C.git_remote_stats(self._remote))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def refspec_count(self):
|
||||||
|
return C.git_remote_refspec_count(self._remote)
|
||||||
|
|
||||||
|
def get_refspec(self, n):
|
||||||
|
spec = C.git_remote_get_refspec(self._remote, n)
|
||||||
|
return Refspec(self, spec)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fetch_refspecs(self):
|
||||||
|
specs = ffi.new('git_strarray *')
|
||||||
|
err = C.git_remote_get_fetch_refspecs(specs, self._remote)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return strarray_to_strings(specs)
|
||||||
|
|
||||||
|
@fetch_refspecs.setter
|
||||||
|
def fetch_refspecs(self, l):
|
||||||
|
arr, refs = strings_to_strarray(l)
|
||||||
|
err = C.git_remote_set_fetch_refspecs(self._remote, arr)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def push_refspecs(self):
|
||||||
|
specs = ffi.new('git_strarray *')
|
||||||
|
err = C.git_remote_get_push_refspecs(specs, self._remote)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return strarray_to_strings(specs)
|
||||||
|
|
||||||
|
@push_refspecs.setter
|
||||||
|
def push_refspecs(self, l):
|
||||||
|
arr, refs = strings_to_strarray(l)
|
||||||
|
err = C.git_remote_set_push_refspecs(self._remote, arr)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def add_fetch(self, spec):
|
||||||
|
err = C.git_remote_add_fetch(self._remote, to_str(spec))
|
||||||
|
|
||||||
|
def add_push(self, spec):
|
||||||
|
err = C.git_remote_add_push(self._remote, to_str(spec))
|
||||||
|
|
||||||
|
@ffi.callback("int (*cb)(const char *ref, const char *msg, void *data)")
|
||||||
|
def _push_cb(ref, msg, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
if msg:
|
||||||
|
self._bad_message = ffi.string(msg).decode()
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def push(self, spec):
|
||||||
|
cpush = ffi.new('git_push **')
|
||||||
|
err = C.git_push_new(cpush, self._remote)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
push = cpush[0]
|
||||||
|
|
||||||
|
try:
|
||||||
|
err = C.git_push_add_refspec(push, to_str(spec))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
err = C.git_push_finish(push)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
if not C.git_push_unpack_ok(push):
|
||||||
|
raise GitError("remote failed to unpack objects")
|
||||||
|
|
||||||
|
err = C.git_push_status_foreach(push, self._push_cb, ffi.new_handle(self))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
if hasattr(self, '_bad_message'):
|
||||||
|
raise GitError(self._bad_message)
|
||||||
|
|
||||||
|
err = C.git_push_update_tips(push)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
C.git_push_free(push)
|
||||||
|
|
||||||
|
# These functions exist to be called by the git_remote as
|
||||||
|
# callbacks. They proxy the call to whatever the user set
|
||||||
|
|
||||||
|
@ffi.callback('int (*transfer_progress)(const git_transfer_progress *stats, void *data)')
|
||||||
|
def _transfer_progress_cb(stats_ptr, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
if not hasattr(self, 'transfer_progress'):
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.transfer_progress(TransferProgress(stats_ptr))
|
||||||
|
except Exception, e:
|
||||||
|
self._stored_exception = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
@@ -35,6 +35,9 @@ from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
|
|||||||
from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL
|
from _pygit2 import GIT_CHECKOUT_SAFE_CREATE, GIT_DIFF_NORMAL
|
||||||
from _pygit2 import Reference, Tree, Commit, Blob
|
from _pygit2 import Reference, Tree, Commit, Blob
|
||||||
|
|
||||||
|
from .ffi import ffi, C, to_str
|
||||||
|
from .errors import check_error
|
||||||
|
from .remote import Remote
|
||||||
|
|
||||||
class Repository(_Repository):
|
class Repository(_Repository):
|
||||||
|
|
||||||
@@ -59,6 +62,51 @@ class Repository(_Repository):
|
|||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return "pygit2.Repository(%r)" % self.path
|
return "pygit2.Repository(%r)" % self.path
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Remotes
|
||||||
|
#
|
||||||
|
def create_remote(self, name, url):
|
||||||
|
"""create_remote(name, url) -> Remote
|
||||||
|
|
||||||
|
Creates a new remote.
|
||||||
|
"""
|
||||||
|
|
||||||
|
repo_cptr = ffi.new('git_repository **')
|
||||||
|
repo_cptr[0] = ffi.cast('git_repository *', self._pointer)
|
||||||
|
cremote = ffi.new('git_remote **')
|
||||||
|
|
||||||
|
repo = repo_cptr[0]
|
||||||
|
err = C.git_remote_create(cremote, repo, to_str(name), to_str(url))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return Remote(repo, cremote[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def remotes(self):
|
||||||
|
"""Returns all configured remotes"""
|
||||||
|
|
||||||
|
repo_cptr = ffi.new('git_repository **')
|
||||||
|
repo_cptr[0] = ffi.cast('git_repository *', self._pointer)
|
||||||
|
names = ffi.new('git_strarray *')
|
||||||
|
|
||||||
|
repo = repo_cptr[0]
|
||||||
|
try:
|
||||||
|
err = C.git_remote_list(names, repo)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
l = [None] * names.count
|
||||||
|
cremote = ffi.new('git_remote **')
|
||||||
|
for i in range(names.count):
|
||||||
|
err = C.git_remote_load(cremote, repo, names.strings[i])
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
l[i] = Remote(repo, cremote[0])
|
||||||
|
return l
|
||||||
|
finally:
|
||||||
|
C.git_strarray_free(names)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# References
|
# References
|
||||||
#
|
#
|
||||||
|
|||||||
297
src/refspec.c
297
src/refspec.c
@@ -1,297 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <structmember.h>
|
|
||||||
#include "error.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "refspec.h"
|
|
||||||
|
|
||||||
|
|
||||||
extern PyTypeObject RefspecType;
|
|
||||||
|
|
||||||
Refspec *
|
|
||||||
wrap_refspec(const Remote *owner, const git_refspec *refspec)
|
|
||||||
{
|
|
||||||
Refspec *spec;
|
|
||||||
|
|
||||||
spec = PyObject_New(Refspec, &RefspecType);
|
|
||||||
if (!spec)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
Py_INCREF(owner);
|
|
||||||
spec->owner = owner;
|
|
||||||
spec->refspec = refspec;
|
|
||||||
|
|
||||||
return spec;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_direction__doc__,
|
|
||||||
"The direction of this refspec (fetch or push)");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_direction__get__(Refspec *self)
|
|
||||||
{
|
|
||||||
return Py_BuildValue("i", git_refspec_direction(self->refspec));
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_src__doc__, "Source or lhs of the refspec");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_src__get__(Refspec *self)
|
|
||||||
{
|
|
||||||
return to_unicode(git_refspec_src(self->refspec), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_dst__doc__, "Destination or rhs of the refspec");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_dst__get__(Refspec *self)
|
|
||||||
{
|
|
||||||
return to_unicode(git_refspec_dst(self->refspec), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_string__doc__, "String used to create this refspec");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_string__get__(Refspec *self)
|
|
||||||
{
|
|
||||||
return to_unicode(git_refspec_string(self->refspec), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_force__doc__,
|
|
||||||
"Whether this refspec allows non-fast-forward updates");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_force__get__(Refspec *self)
|
|
||||||
{
|
|
||||||
if (git_refspec_force(self->refspec))
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_src_matches__doc__,
|
|
||||||
"src_matches(str) -> Bool\n"
|
|
||||||
"\n"
|
|
||||||
"Returns whether the string matches the source refspec\n");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_src_matches(Refspec *self, PyObject *py_str)
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
PyObject *tstr;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
if (!str)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
res = git_refspec_src_matches(self->refspec, str);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_dst_matches__doc__,
|
|
||||||
"dst_matches(str) -> Bool\n"
|
|
||||||
"\n"
|
|
||||||
"Returns whether the string matches the destination refspec\n");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_dst_matches(Refspec *self, PyObject *py_str)
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
PyObject *tstr;
|
|
||||||
int res;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
if (!str)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
res = git_refspec_dst_matches(self->refspec, str);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (res)
|
|
||||||
Py_RETURN_TRUE;
|
|
||||||
|
|
||||||
Py_RETURN_FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_transform__doc__,
|
|
||||||
"transform(str) -> str\n"
|
|
||||||
"\n"
|
|
||||||
"Transform a reference according to the refspec\n");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_transform(Refspec *self, PyObject *py_str)
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
char *trans;
|
|
||||||
int err, len, alen;
|
|
||||||
PyObject *py_trans, *tstr;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
alen = len = strlen(str);
|
|
||||||
|
|
||||||
do {
|
|
||||||
alen *= alen;
|
|
||||||
trans = malloc(alen);
|
|
||||||
if (!trans) {
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
return PyErr_NoMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
err = git_refspec_transform(trans, alen, self->refspec, str);
|
|
||||||
} while(err == GIT_EBUFS);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
free(trans);
|
|
||||||
Error_set(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_trans = to_unicode(trans, NULL, NULL);
|
|
||||||
|
|
||||||
free(trans);
|
|
||||||
|
|
||||||
return py_trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec_rtransform__doc__,
|
|
||||||
"rtransform(str) -> str\n"
|
|
||||||
"\n"
|
|
||||||
"Transform a reference according to the refspec in reverse\n");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Refspec_rtransform(Refspec *self, PyObject *py_str)
|
|
||||||
{
|
|
||||||
const char *str;
|
|
||||||
char *trans;
|
|
||||||
int err, len, alen;
|
|
||||||
PyObject *py_trans, *tstr;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
alen = len = strlen(str);
|
|
||||||
|
|
||||||
do {
|
|
||||||
alen *= alen;
|
|
||||||
trans = malloc(alen);
|
|
||||||
if (!trans) {
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
return PyErr_NoMemory();
|
|
||||||
}
|
|
||||||
|
|
||||||
err = git_refspec_rtransform(trans, alen, self->refspec, str);
|
|
||||||
} while(err == GIT_EBUFS);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
free(trans);
|
|
||||||
Error_set(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_trans = to_unicode(trans, NULL, NULL);
|
|
||||||
|
|
||||||
free(trans);
|
|
||||||
|
|
||||||
return py_trans;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMethodDef Refspec_methods[] = {
|
|
||||||
METHOD(Refspec, src_matches, METH_O),
|
|
||||||
METHOD(Refspec, dst_matches, METH_O),
|
|
||||||
METHOD(Refspec, transform, METH_O),
|
|
||||||
METHOD(Refspec, rtransform, METH_O),
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyGetSetDef Refspec_getseters[] = {
|
|
||||||
GETTER(Refspec, direction),
|
|
||||||
GETTER(Refspec, src),
|
|
||||||
GETTER(Refspec, dst),
|
|
||||||
GETTER(Refspec, string),
|
|
||||||
GETTER(Refspec, force),
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void
|
|
||||||
Refspec_dealloc(Refspec *self)
|
|
||||||
{
|
|
||||||
Py_CLEAR(self->owner);
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Refspec__doc__, "Refspec object.");
|
|
||||||
|
|
||||||
PyTypeObject RefspecType = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"_pygit2.Refspec", /* tp_name */
|
|
||||||
sizeof(Refspec), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)Refspec_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, /* tp_flags */
|
|
||||||
Refspec__doc__, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
0, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
Refspec_methods, /* tp_methods */
|
|
||||||
0, /* tp_members */
|
|
||||||
Refspec_getseters, /* tp_getset */
|
|
||||||
0, /* tp_base */
|
|
||||||
0, /* tp_dict */
|
|
||||||
0, /* tp_descr_get */
|
|
||||||
0, /* tp_descr_set */
|
|
||||||
0, /* tp_dictoffset */
|
|
||||||
0, /* tp_init */
|
|
||||||
0, /* tp_alloc */
|
|
||||||
0, /* tp_new */
|
|
||||||
};
|
|
||||||
@@ -1277,67 +1277,6 @@ Repository_TreeBuilder(Repository *self, PyObject *args)
|
|||||||
return (PyObject*)builder;
|
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)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
|
|
||||||
return (PyObject*) wrap_remote(remote, self);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_remotes__doc__, "Returns all configured remotes.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Repository_remotes__get__(Repository *self)
|
|
||||||
{
|
|
||||||
git_strarray remotes;
|
|
||||||
git_remote *remote = NULL;
|
|
||||||
PyObject *py_list = NULL;
|
|
||||||
PyObject *py_remote = NULL;
|
|
||||||
size_t i;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
git_remote_list(&remotes, self->repo);
|
|
||||||
|
|
||||||
py_list = PyList_New(remotes.count);
|
|
||||||
for (i=0; i < remotes.count; ++i) {
|
|
||||||
err = git_remote_load(&remote, self->repo, remotes.strings[i]);
|
|
||||||
if (err < 0)
|
|
||||||
goto cleanup;
|
|
||||||
py_remote = wrap_remote(remote, self);
|
|
||||||
if (py_remote == NULL)
|
|
||||||
goto cleanup;
|
|
||||||
PyList_SetItem(py_list, i, py_remote);
|
|
||||||
}
|
|
||||||
|
|
||||||
git_strarray_free(&remotes);
|
|
||||||
return (PyObject*) py_list;
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
git_strarray_free(&remotes);
|
|
||||||
if (py_list)
|
|
||||||
Py_DECREF(py_list);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_default_signature__doc__, "Return the signature according to the repository's configuration");
|
PyDoc_STRVAR(Repository_default_signature__doc__, "Return the signature according to the repository's configuration");
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
@@ -1352,6 +1291,19 @@ Repository_default_signature__get__(Repository *self)
|
|||||||
return build_signature(NULL, sig, "utf-8");
|
return build_signature(NULL, sig, "utf-8");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Repository__pointer__doc__, "Get the repo's pointer. For internal use only.");
|
||||||
|
PyObject *
|
||||||
|
Repository__pointer__get__(Repository *self)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* This is pretty bad. We shouldn't be casting a pointer into an
|
||||||
|
* integer, but we can't access the contents of a PyCapsule from
|
||||||
|
* python code, which we need to do in order to get a type that
|
||||||
|
* cffi likes.
|
||||||
|
*/
|
||||||
|
return PyLong_FromLongLong((long long) self->repo);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_checkout_head__doc__,
|
PyDoc_STRVAR(Repository_checkout_head__doc__,
|
||||||
"checkout_head(strategy)\n"
|
"checkout_head(strategy)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1633,7 +1585,6 @@ PyMethodDef Repository_methods[] = {
|
|||||||
METHOD(Repository, revparse_single, METH_O),
|
METHOD(Repository, revparse_single, METH_O),
|
||||||
METHOD(Repository, status, METH_NOARGS),
|
METHOD(Repository, status, METH_NOARGS),
|
||||||
METHOD(Repository, status_file, METH_O),
|
METHOD(Repository, status_file, METH_O),
|
||||||
METHOD(Repository, create_remote, METH_VARARGS),
|
|
||||||
METHOD(Repository, checkout_head, METH_VARARGS),
|
METHOD(Repository, checkout_head, METH_VARARGS),
|
||||||
METHOD(Repository, checkout_index, METH_VARARGS),
|
METHOD(Repository, checkout_index, METH_VARARGS),
|
||||||
METHOD(Repository, checkout_tree, METH_VARARGS),
|
METHOD(Repository, checkout_tree, METH_VARARGS),
|
||||||
@@ -1659,8 +1610,8 @@ PyGetSetDef Repository_getseters[] = {
|
|||||||
GETTER(Repository, is_bare),
|
GETTER(Repository, is_bare),
|
||||||
GETTER(Repository, config),
|
GETTER(Repository, config),
|
||||||
GETTER(Repository, workdir),
|
GETTER(Repository, workdir),
|
||||||
GETTER(Repository, remotes),
|
|
||||||
GETTER(Repository, default_signature),
|
GETTER(Repository, default_signature),
|
||||||
|
GETTER(Repository, _pointer),
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -189,9 +189,9 @@ class EmptyRepositoryTest(utils.EmptyRepoTestCase):
|
|||||||
def test_fetch(self):
|
def test_fetch(self):
|
||||||
remote = self.repo.remotes[0]
|
remote = self.repo.remotes[0]
|
||||||
stats = remote.fetch()
|
stats = remote.fetch()
|
||||||
self.assertEqual(stats['received_bytes'], REMOTE_REPO_BYTES)
|
self.assertEqual(stats.received_bytes, REMOTE_REPO_BYTES)
|
||||||
self.assertEqual(stats['indexed_objects'], REMOTE_REPO_OBJECTS)
|
self.assertEqual(stats.indexed_objects, REMOTE_REPO_OBJECTS)
|
||||||
self.assertEqual(stats['received_objects'], REMOTE_REPO_OBJECTS)
|
self.assertEqual(stats.received_objects, REMOTE_REPO_OBJECTS)
|
||||||
|
|
||||||
def test_transfer_progress(self):
|
def test_transfer_progress(self):
|
||||||
self.tp = None
|
self.tp = None
|
||||||
@@ -201,9 +201,9 @@ class EmptyRepositoryTest(utils.EmptyRepoTestCase):
|
|||||||
remote = self.repo.remotes[0]
|
remote = self.repo.remotes[0]
|
||||||
remote.transfer_progress = tp_cb
|
remote.transfer_progress = tp_cb
|
||||||
stats = remote.fetch()
|
stats = remote.fetch()
|
||||||
self.assertEqual(stats['received_bytes'], self.tp.received_bytes)
|
self.assertEqual(stats.received_bytes, self.tp.received_bytes)
|
||||||
self.assertEqual(stats['indexed_objects'], self.tp.indexed_objects)
|
self.assertEqual(stats.indexed_objects, self.tp.indexed_objects)
|
||||||
self.assertEqual(stats['received_objects'], self.tp.received_objects)
|
self.assertEqual(stats.received_objects, self.tp.received_objects)
|
||||||
|
|
||||||
def test_update_tips(self):
|
def test_update_tips(self):
|
||||||
remote = self.repo.remotes[0]
|
remote = self.repo.remotes[0]
|
||||||
|
|||||||
Reference in New Issue
Block a user