
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.
208 lines
6.4 KiB
Python
208 lines
6.4 KiB
Python
# -*- 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
|