Merge remote-tracking branch 'upstream/master' into development
Reconcile the changes between the ffi changes upstream with the changes to libgit2 in the dev branch. Conflicts: src/config.c src/options.c src/refspec.c src/remote.c
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__
|
||||||
|
@@ -1,7 +1,6 @@
|
|||||||
language: python
|
language: python
|
||||||
|
|
||||||
python:
|
python:
|
||||||
- "2.6"
|
|
||||||
- "2.7"
|
- "2.7"
|
||||||
- "3.2"
|
- "3.2"
|
||||||
- "3.3"
|
- "3.3"
|
||||||
@@ -11,6 +10,7 @@ env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib
|
|||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- sudo apt-get install cmake
|
- sudo apt-get install cmake
|
||||||
|
- pip install cffi
|
||||||
- "./.travis.sh"
|
- "./.travis.sh"
|
||||||
|
|
||||||
script:
|
script:
|
||||||
|
52
README.rst
52
README.rst
@@ -6,8 +6,12 @@ pygit2 - libgit2 bindings in Python
|
|||||||
:target: http://travis-ci.org/libgit2/pygit2
|
:target: http://travis-ci.org/libgit2/pygit2
|
||||||
|
|
||||||
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
||||||
implements the core of Git. Pygit2 works with Python 2.6, 2.7, 3.1, 3.2 and
|
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
|
||||||
3.3
|
pypy.
|
||||||
|
|
||||||
|
It is likely to work with Python 2.6 and 3.1, but these versions are not
|
||||||
|
officially supported.
|
||||||
|
|
||||||
|
|
||||||
Pygit2 links:
|
Pygit2 links:
|
||||||
|
|
||||||
@@ -44,33 +48,35 @@ for the topic), send a pull request.
|
|||||||
Authors
|
Authors
|
||||||
==============
|
==============
|
||||||
|
|
||||||
57 developers have contributed at least 1 commit to pygit2::
|
62 developers have contributed at least 1 commit to pygit2::
|
||||||
|
|
||||||
J. David Ibáñez Brodie Rao Adam Spiers
|
J. David Ibáñez Rémi Duraffort András Veres-Szentkirályi
|
||||||
Nico von Geyso David Versmisse Alexander Bayandin
|
Nico von Geyso Sebastian Thiel Benjamin Kircher
|
||||||
Carlos Martín Nieto Rémi Duraffort Andrew Chin
|
Carlos Martín Nieto Fraser Tweedale Benjamin Pollack
|
||||||
W. Trevor King Sebastian Thiel András Veres-Szentkirályi
|
W. Trevor King Han-Wen Nienhuys Bryan O'Sullivan
|
||||||
Dave Borowitz Fraser Tweedale Benjamin Kircher
|
Dave Borowitz Leonardo Rhodes David Fischer
|
||||||
Daniel Rodríguez Troitiño Han-Wen Nienhuys Benjamin Pollack
|
Daniel Rodríguez Troitiño Petr Viktorin David Sanders
|
||||||
Richo Healey Petr Viktorin Bryan O'Sullivan
|
Richo Healey Alex Chamberlain Devaev Maxim
|
||||||
Christian Boos Alex Chamberlain David Fischer
|
Christian Boos Amit Bakshi Eric Davis
|
||||||
Julien Miotte Amit Bakshi David Sanders
|
Julien Miotte Andrey Devyatkin Erik Meusel
|
||||||
Xu Tao Andrey Devyatkin Eric Davis
|
Xu Tao Ben Davis Erik van Zijst
|
||||||
Jose Plana Ben Davis Erik van Zijst
|
Jose Plana Eric Schrijver Ferengee
|
||||||
Martin Lenders Eric Schrijver Ferengee
|
Martin Lenders Hervé Cauwelier Gustavo Di Pietro
|
||||||
Petr Hosek Hervé Cauwelier Gustavo Di Pietro
|
Petr Hosek Huang Huang Hugh Cole-Baker
|
||||||
Victor Garcia Huang Huang Hugh Cole-Baker
|
Victor Garcia Jared Flatow Josh Bleecher Snyder
|
||||||
Xavier Delannoy Jared Flatow Josh Bleecher Snyder
|
Xavier Delannoy Jiunn Haur Lim Jun Omae
|
||||||
Yonggang Luo Jiunn Haur Lim Jun Omae
|
Yonggang Luo Sarath Lakshman Óscar San José
|
||||||
Valentin Haenel Sarath Lakshman Óscar San José
|
Valentin Haenel Vicent Marti Ridge Kennedy
|
||||||
Bernardo Heynemann Vicent Marti Ridge Kennedy
|
Bernardo Heynemann Zoran Zaric Rui Abreu Ferreira
|
||||||
John Szakmeister Zoran Zaric Rui Abreu Ferreira
|
John Szakmeister Adam Spiers Thomas Kluyver
|
||||||
|
Brodie Rao Alexander Bayandin earl
|
||||||
|
David Versmisse Andrew Chin
|
||||||
|
|
||||||
|
|
||||||
Changelog
|
Changelog
|
||||||
==============
|
==============
|
||||||
|
|
||||||
0.20.3 (2014-04-XX)
|
0.20.3 (2014-04-02)
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
- A number of memory issues fixed
|
- A number of memory issues fixed
|
||||||
|
@@ -50,7 +50,7 @@ copyright = u'2010-2014 The pygit2 contributors'
|
|||||||
# The short X.Y version.
|
# The short X.Y version.
|
||||||
version = '0.20'
|
version = '0.20'
|
||||||
# The full version, including alpha/beta/rc tags.
|
# The full version, including alpha/beta/rc tags.
|
||||||
release = '0.20.2'
|
release = '0.20.3'
|
||||||
|
|
||||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
# for a list of supported languages.
|
# for a list of supported languages.
|
||||||
|
@@ -22,4 +22,13 @@ The Config type
|
|||||||
aware that this may return multiple versions of each entry if they are
|
aware that this may return multiple versions of each entry if they are
|
||||||
set multiple times in the configuration files.
|
set multiple times in the configuration files.
|
||||||
|
|
||||||
|
.. currentmodule:: pygit2
|
||||||
|
|
||||||
The :class:`Config` Mapping interface.
|
The :class:`Config` Mapping interface.
|
||||||
|
|
||||||
|
When using the mapping interface, the value is returned as a
|
||||||
|
string. In order to apply the git-config parsing rules, you can use
|
||||||
|
:meth:`Config.get_bool` or :meth:`Config.get_int`.
|
||||||
|
|
||||||
|
.. automethod:: pygit2.Config.get_bool
|
||||||
|
.. automethod:: pygit2.Config.get_int
|
||||||
|
@@ -10,8 +10,11 @@ Welcome to pygit2's documentation!
|
|||||||
:target: http://travis-ci.org/libgit2/pygit2
|
:target: http://travis-ci.org/libgit2/pygit2
|
||||||
|
|
||||||
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
||||||
implements the core of Git. Pygit2 works with Python 2.6, 2.7, 3.1, 3.2 and
|
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
|
||||||
3.3
|
pypy.
|
||||||
|
|
||||||
|
It is likely to work with Python 2.6 and 3.1, but these versions are not
|
||||||
|
officially supported.
|
||||||
|
|
||||||
Pygit2 links:
|
Pygit2 links:
|
||||||
|
|
||||||
|
@@ -13,7 +13,7 @@ website:
|
|||||||
|
|
||||||
http://libgit2.github.com
|
http://libgit2.github.com
|
||||||
|
|
||||||
Also, make sure you have Python 2.6+ installed together with the Python
|
Also, make sure you have Python 2.7 or 3.2+ installed together with the Python
|
||||||
development headers.
|
development headers.
|
||||||
|
|
||||||
When those are installed, you can install pygit2:
|
When those are installed, you can install pygit2:
|
||||||
|
@@ -16,9 +16,9 @@ The Remote type
|
|||||||
.. autoattribute:: pygit2.Remote.refspec_count
|
.. autoattribute:: pygit2.Remote.refspec_count
|
||||||
.. autoattribute:: pygit2.Remote.push_refspecs
|
.. autoattribute:: pygit2.Remote.push_refspecs
|
||||||
.. autoattribute:: pygit2.Remote.fetch_refspecs
|
.. autoattribute:: pygit2.Remote.fetch_refspecs
|
||||||
.. autoattribute:: pygit2.Remote.progress
|
.. automethod:: pygit2.Remote.progress
|
||||||
.. autoattribute:: pygit2.Remote.transfer_progress
|
.. automethod:: pygit2.Remote.transfer_progress
|
||||||
.. autoattribute:: pygit2.Remote.update_tips
|
.. automethod:: pygit2.Remote.update_tips
|
||||||
.. automethod:: pygit2.Remote.get_refspec
|
.. automethod:: pygit2.Remote.get_refspec
|
||||||
.. automethod:: pygit2.Remote.fetch
|
.. automethod:: pygit2.Remote.fetch
|
||||||
.. automethod:: pygit2.Remote.push
|
.. automethod:: pygit2.Remote.push
|
||||||
|
@@ -37,6 +37,10 @@ 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, get_credentials
|
||||||
|
from .config import Config
|
||||||
|
from .errors import check_error
|
||||||
|
from .ffi import ffi, C, to_str
|
||||||
|
|
||||||
def init_repository(path, bare=False):
|
def init_repository(path, bare=False):
|
||||||
"""
|
"""
|
||||||
@@ -49,6 +53,19 @@ def init_repository(path, bare=False):
|
|||||||
return Repository(path)
|
return Repository(path)
|
||||||
|
|
||||||
|
|
||||||
|
@ffi.callback('int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)')
|
||||||
|
def _credentials_cb(cred_out, url, username_from_url, allowed, data):
|
||||||
|
d = ffi.from_handle(data)
|
||||||
|
|
||||||
|
try:
|
||||||
|
ccred = get_credentials(d['callback'], url, username_from_url, allowed)
|
||||||
|
cred_out[0] = ccred[0]
|
||||||
|
except Exception as e:
|
||||||
|
d['exception'] = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
def clone_repository(
|
def clone_repository(
|
||||||
url, path, bare=False, ignore_cert_errors=False,
|
url, path, bare=False, ignore_cert_errors=False,
|
||||||
remote_name="origin", checkout_branch=None, credentials=None):
|
remote_name="origin", checkout_branch=None, credentials=None):
|
||||||
@@ -74,8 +91,42 @@ def clone_repository(
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
_pygit2.clone_repository(
|
opts = ffi.new('git_clone_options *')
|
||||||
url, path, bare, ignore_cert_errors, remote_name, checkout_branch, credentials)
|
crepo = ffi.new('git_repository **')
|
||||||
|
|
||||||
|
branch = checkout_branch or None
|
||||||
|
|
||||||
|
# Data, let's use a dict as we don't really want much more
|
||||||
|
d = {}
|
||||||
|
d['callback'] = credentials
|
||||||
|
d_handle = ffi.new_handle(d)
|
||||||
|
|
||||||
|
# We need to keep the ref alive ourselves
|
||||||
|
checkout_branch_ref = None
|
||||||
|
if branch:
|
||||||
|
checkout_branch_ref = ffi.new('char []', branch)
|
||||||
|
opts.checkout_branch = checkout_branch_ref
|
||||||
|
|
||||||
|
remote_name_ref = ffi.new('char []', to_str(remote_name))
|
||||||
|
opts.remote_name = remote_name_ref
|
||||||
|
|
||||||
|
opts.version = 1
|
||||||
|
opts.ignore_cert_errors = ignore_cert_errors
|
||||||
|
opts.bare = bare
|
||||||
|
opts.remote_callbacks.version = 1
|
||||||
|
opts.checkout_opts.version = 1
|
||||||
|
if credentials:
|
||||||
|
opts.remote_callbacks.credentials = _credentials_cb
|
||||||
|
opts.remote_callbacks.payload = d_handle
|
||||||
|
|
||||||
|
err = C.git_clone(crepo, to_str(url), to_str(path), opts)
|
||||||
|
C.git_repository_free(crepo[0])
|
||||||
|
|
||||||
|
if 'exception' in d:
|
||||||
|
raise d['exception']
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
return Repository(path)
|
return Repository(path)
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
|
281
pygit2/config.py
Normal file
281
pygit2/config.py
Normal file
@@ -0,0 +1,281 @@
|
|||||||
|
# -*- 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, unicode_literals
|
||||||
|
|
||||||
|
from _pygit2 import Oid
|
||||||
|
|
||||||
|
from .ffi import ffi, C, to_str, is_string
|
||||||
|
from .errors import check_error, GitError
|
||||||
|
from .refspec import Refspec
|
||||||
|
|
||||||
|
def assert_string(v, desc):
|
||||||
|
if not is_string(v):
|
||||||
|
raise TypeError("%s must be a string" % desc)
|
||||||
|
|
||||||
|
class ConfigIterator(object):
|
||||||
|
|
||||||
|
def __init__(self, config, ptr):
|
||||||
|
self._iter = ptr
|
||||||
|
self._config = config
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
C.git_config_iterator_free(self._iter)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def _next_entry(self):
|
||||||
|
centry = ffi.new('git_config_entry **')
|
||||||
|
err = C.git_config_next(centry, self._iter)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return centry[0]
|
||||||
|
|
||||||
|
def next(self):
|
||||||
|
return self.__next__()
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
entry = self._next_entry()
|
||||||
|
name = ffi.string(entry.name).decode('utf-8')
|
||||||
|
value = ffi.string(entry.value).decode('utf-8')
|
||||||
|
|
||||||
|
return name, value
|
||||||
|
|
||||||
|
class ConfigMultivarIterator(ConfigIterator):
|
||||||
|
def __next__(self):
|
||||||
|
entry = self._next_entry()
|
||||||
|
|
||||||
|
return ffi.string(entry.value).decode('utf-8')
|
||||||
|
|
||||||
|
class Config(object):
|
||||||
|
"""Git configuration management"""
|
||||||
|
|
||||||
|
def __init__(self, path=None):
|
||||||
|
cconfig = ffi.new('git_config **')
|
||||||
|
|
||||||
|
if not path:
|
||||||
|
err = C.git_config_new(cconfig)
|
||||||
|
else:
|
||||||
|
assert_string(path, "path")
|
||||||
|
err = C.git_config_open_ondisk(cconfig, to_str(path))
|
||||||
|
|
||||||
|
check_error(err, True)
|
||||||
|
self._config = cconfig[0]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_c(cls, repo, ptr):
|
||||||
|
config = cls.__new__(cls)
|
||||||
|
config._repo = repo
|
||||||
|
config._config = ptr
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
def __del__(self):
|
||||||
|
C.git_config_free(self._config)
|
||||||
|
|
||||||
|
def _get(self, key):
|
||||||
|
assert_string(key, "key")
|
||||||
|
|
||||||
|
cstr = ffi.new('char **')
|
||||||
|
err = C.git_config_get_string(cstr, self._config, to_str(key))
|
||||||
|
|
||||||
|
return err, cstr
|
||||||
|
|
||||||
|
def _get_string(self, key):
|
||||||
|
err, cstr = self._get(key)
|
||||||
|
|
||||||
|
if err == C.GIT_ENOTFOUND:
|
||||||
|
raise KeyError(key)
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
return cstr[0]
|
||||||
|
|
||||||
|
def __contains__(self, key):
|
||||||
|
err, cstr = self._get(key)
|
||||||
|
|
||||||
|
if err == C.GIT_ENOTFOUND:
|
||||||
|
return False
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
def __getitem__(self, key):
|
||||||
|
val = self._get_string(key)
|
||||||
|
|
||||||
|
return ffi.string(val).decode()
|
||||||
|
|
||||||
|
def __setitem__(self, key, value):
|
||||||
|
assert_string(key, "key")
|
||||||
|
|
||||||
|
err = 0
|
||||||
|
if isinstance(value, bool):
|
||||||
|
err = C.git_config_set_bool(self._config, to_str(key), value)
|
||||||
|
elif isinstance(value, int):
|
||||||
|
err = C.git_config_set_int64(self._config, to_str(key), value)
|
||||||
|
else:
|
||||||
|
err = C.git_config_set_string(self._config, to_str(key), to_str(value))
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def __delitem__(self, key):
|
||||||
|
assert_string(key, "key")
|
||||||
|
|
||||||
|
err = C.git_config_delete_entry(self._config, to_str(key))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
citer = ffi.new('git_config_iterator **')
|
||||||
|
err = C.git_config_iterator_new(citer, self._config)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return ConfigIterator(self, citer[0])
|
||||||
|
|
||||||
|
def get_multivar(self, name, regex=None):
|
||||||
|
"""get_multivar(name[, regex]) -> [str, ...]
|
||||||
|
|
||||||
|
Get each value of a multivar ''name'' as a list. The optional ''regex''
|
||||||
|
parameter is expected to be a regular expression to filter the variables
|
||||||
|
we're interested in."""
|
||||||
|
|
||||||
|
assert_string(name, "name")
|
||||||
|
|
||||||
|
citer = ffi.new('git_config_iterator **')
|
||||||
|
err = C.git_config_multivar_iterator_new(citer, self._config, to_str(name), to_str(regex))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return ConfigMultivarIterator(self, citer[0])
|
||||||
|
|
||||||
|
def set_multivar(self, name, regex, value):
|
||||||
|
"""set_multivar(name, regex, value)
|
||||||
|
|
||||||
|
Set a multivar ''name'' to ''value''. ''regexp'' is a regular expression
|
||||||
|
to indicate which values to replace"""
|
||||||
|
|
||||||
|
assert_string(name, "name")
|
||||||
|
assert_string(regex, "regex")
|
||||||
|
assert_string(value, "value")
|
||||||
|
|
||||||
|
err = C.git_config_set_multivar(self._config, to_str(name), to_str(regex), to_str(value))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def get_bool(self, key):
|
||||||
|
"""get_bool(key) -> Bool
|
||||||
|
|
||||||
|
Look up *key* and parse its value as a boolean as per the git-config rules
|
||||||
|
|
||||||
|
Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false',
|
||||||
|
0, 'off' and 'no'"""
|
||||||
|
|
||||||
|
val = self._get_string(key)
|
||||||
|
res = ffi.new('int *')
|
||||||
|
err = C.git_config_parse_bool(res, val)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return res[0] != 0
|
||||||
|
|
||||||
|
def get_int(self, key):
|
||||||
|
"""get_int(key) -> int
|
||||||
|
|
||||||
|
Look up *key* and parse its value as an integer as per the git-config rules.
|
||||||
|
|
||||||
|
A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo', 'mega' and
|
||||||
|
'giga' respectively"""
|
||||||
|
|
||||||
|
val = self._get_string(key)
|
||||||
|
res = ffi.new('int64_t *')
|
||||||
|
err = C.git_config_parse_int64(res, val)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
def add_file(self, path, level=0, force=0):
|
||||||
|
"""add_file(path, level=0, force=0)
|
||||||
|
|
||||||
|
Add a config file instance to an existing config."""
|
||||||
|
|
||||||
|
err = C.git_config_add_file_ondisk(self._config, to_str(path), level, force)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
#
|
||||||
|
# Methods to parse a string according to the git-config rules
|
||||||
|
#
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_bool(text):
|
||||||
|
res = ffi.new('int *')
|
||||||
|
err = C.git_config_parse_bool(res, to_str(text))
|
||||||
|
|
||||||
|
return res[0] != 0
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def parse_int(text):
|
||||||
|
res = ffi.new('int64_t *')
|
||||||
|
err = C.git_config_parse_int64(res, to_str(text))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return res[0]
|
||||||
|
|
||||||
|
#
|
||||||
|
# Static methods to get specialized version of the config
|
||||||
|
#
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _from_found_config(fn):
|
||||||
|
buf = ffi.new('git_buf *', (ffi.NULL, 0))
|
||||||
|
err = fn(buf)
|
||||||
|
check_error(err, True)
|
||||||
|
cpath = ffi.string(buf.ptr).decode()
|
||||||
|
C.git_buf_free(buf)
|
||||||
|
|
||||||
|
return Config(cpath)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_system_config():
|
||||||
|
"""get_system_config() -> Config
|
||||||
|
|
||||||
|
Return an object representing the system configuration file."""
|
||||||
|
|
||||||
|
return Config._from_found_config(C.git_config_find_system)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_global_config():
|
||||||
|
"""get_global_config() -> Config
|
||||||
|
|
||||||
|
Return an object representing the global configuration file."""
|
||||||
|
|
||||||
|
return Config._from_found_config(C.git_config_find_global)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_xdg_config():
|
||||||
|
"""get_xdg_config() -> Config
|
||||||
|
|
||||||
|
Return an object representing the global configuration file."""
|
||||||
|
|
||||||
|
return Config._from_found_config(C.git_config_find_xdg)
|
@@ -25,8 +25,10 @@
|
|||||||
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
# Import from pygit2
|
from .ffi import ffi, C
|
||||||
from _pygit2 import GIT_CREDTYPE_USERPASS_PLAINTEXT, GIT_CREDTYPE_SSH_KEY
|
|
||||||
|
GIT_CREDTYPE_USERPASS_PLAINTEXT = C.GIT_CREDTYPE_USERPASS_PLAINTEXT
|
||||||
|
GIT_CREDTYPE_SSH_KEY = C.GIT_CREDTYPE_SSH_KEY
|
||||||
|
|
||||||
class UserPass(object):
|
class UserPass(object):
|
||||||
"""Username/Password credentials
|
"""Username/Password credentials
|
||||||
|
285
pygit2/decl.h
Normal file
285
pygit2/decl.h
Normal file
@@ -0,0 +1,285 @@
|
|||||||
|
typedef ... git_repository;
|
||||||
|
typedef ... git_remote;
|
||||||
|
typedef ... git_refspec;
|
||||||
|
typedef ... git_push;
|
||||||
|
typedef ... git_cred;
|
||||||
|
typedef ... git_diff_file;
|
||||||
|
typedef ... git_tree;
|
||||||
|
typedef ... git_config;
|
||||||
|
typedef ... git_config_iterator;
|
||||||
|
typedef ... git_signature;
|
||||||
|
|
||||||
|
#define GIT_OID_RAWSZ ...
|
||||||
|
#define GIT_PATH_MAX ...
|
||||||
|
|
||||||
|
typedef struct git_oid {
|
||||||
|
unsigned char id[20];
|
||||||
|
} git_oid;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *ptr;
|
||||||
|
size_t asize, size;
|
||||||
|
} git_buf;
|
||||||
|
void git_buf_free(git_buf *buffer);
|
||||||
|
|
||||||
|
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);
|
||||||
|
void git_repository_free(git_repository *repo);
|
||||||
|
|
||||||
|
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 enum {
|
||||||
|
GIT_CREDTYPE_USERPASS_PLAINTEXT = ...,
|
||||||
|
GIT_CREDTYPE_SSH_KEY = ...,
|
||||||
|
GIT_CREDTYPE_SSH_CUSTOM = ...,
|
||||||
|
GIT_CREDTYPE_DEFAULT = ...,
|
||||||
|
} git_credtype_t;
|
||||||
|
|
||||||
|
typedef int (*git_transport_message_cb)(const char *str, int len, void *data);
|
||||||
|
typedef int (*git_cred_acquire_cb)(
|
||||||
|
git_cred **cred,
|
||||||
|
const char *url,
|
||||||
|
const char *username_from_url,
|
||||||
|
unsigned int allowed_types,
|
||||||
|
void *payload);
|
||||||
|
typedef int (*git_transfer_progress_cb)(const git_transfer_progress *stats, void *payload);
|
||||||
|
|
||||||
|
struct git_remote_callbacks {
|
||||||
|
unsigned int version;
|
||||||
|
git_transport_message_cb sideband_progress;
|
||||||
|
int (*completion)(git_remote_completion_type type, void *data);
|
||||||
|
git_cred_acquire_cb credentials;
|
||||||
|
git_transfer_progress_cb transfer_progress;
|
||||||
|
int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
|
||||||
|
void *payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct git_remote_callbacks 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_signature *signature, const char *reflog_message);
|
||||||
|
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,
|
||||||
|
const git_signature *signature,
|
||||||
|
const char *reflog_message);
|
||||||
|
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(git_buf *buf, const git_refspec *spec, const char *name);
|
||||||
|
int git_refspec_rtransform(git_buf *buf, const git_refspec *spec, const char *name);
|
||||||
|
|
||||||
|
int git_cred_userpass_plaintext_new(
|
||||||
|
git_cred **out,
|
||||||
|
const char *username,
|
||||||
|
const char *password);
|
||||||
|
int git_cred_ssh_key_new(
|
||||||
|
git_cred **out,
|
||||||
|
const char *username,
|
||||||
|
const char *publickey,
|
||||||
|
const char *privatekey,
|
||||||
|
const char *passphrase);
|
||||||
|
|
||||||
|
typedef enum { ... } git_checkout_notify_t;
|
||||||
|
|
||||||
|
typedef int (*git_checkout_notify_cb)(
|
||||||
|
git_checkout_notify_t why,
|
||||||
|
const char *path,
|
||||||
|
const git_diff_file *baseline,
|
||||||
|
const git_diff_file *target,
|
||||||
|
const git_diff_file *workdir,
|
||||||
|
void *payload);
|
||||||
|
|
||||||
|
typedef void (*git_checkout_progress_cb)(
|
||||||
|
const char *path,
|
||||||
|
size_t completed_steps,
|
||||||
|
size_t total_steps,
|
||||||
|
void *payload);
|
||||||
|
|
||||||
|
typedef struct git_checkout_options {
|
||||||
|
unsigned int version;
|
||||||
|
|
||||||
|
unsigned int checkout_strategy;
|
||||||
|
|
||||||
|
int disable_filters;
|
||||||
|
unsigned int dir_mode;
|
||||||
|
unsigned int file_mode;
|
||||||
|
int file_open_flags;
|
||||||
|
|
||||||
|
unsigned int notify_flags;
|
||||||
|
git_checkout_notify_cb notify_cb;
|
||||||
|
void *notify_payload;
|
||||||
|
|
||||||
|
git_checkout_progress_cb progress_cb;
|
||||||
|
void *progress_payload;
|
||||||
|
|
||||||
|
git_strarray paths;
|
||||||
|
|
||||||
|
git_tree *baseline;
|
||||||
|
|
||||||
|
const char *target_directory;
|
||||||
|
|
||||||
|
const char *ancestor_label;
|
||||||
|
const char *our_label;
|
||||||
|
const char *their_label;
|
||||||
|
} git_checkout_options;
|
||||||
|
|
||||||
|
typedef struct git_clone_options {
|
||||||
|
unsigned int version;
|
||||||
|
|
||||||
|
git_checkout_options checkout_opts;
|
||||||
|
git_remote_callbacks remote_callbacks;
|
||||||
|
|
||||||
|
int bare;
|
||||||
|
int ignore_cert_errors;
|
||||||
|
const char *remote_name;
|
||||||
|
const char* checkout_branch;
|
||||||
|
git_signature *signature;
|
||||||
|
} git_clone_options;
|
||||||
|
|
||||||
|
int git_clone(git_repository **out,
|
||||||
|
const char *url,
|
||||||
|
const char *local_path,
|
||||||
|
const git_clone_options *options);
|
||||||
|
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
GIT_CONFIG_LEVEL_SYSTEM = 1,
|
||||||
|
GIT_CONFIG_LEVEL_XDG = 2,
|
||||||
|
GIT_CONFIG_LEVEL_GLOBAL = 3,
|
||||||
|
GIT_CONFIG_LEVEL_LOCAL = 4,
|
||||||
|
GIT_CONFIG_LEVEL_APP = 5,
|
||||||
|
GIT_CONFIG_HIGHEST_LEVEL = -1,
|
||||||
|
} git_config_level_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
const char *value;
|
||||||
|
git_config_level_t level;
|
||||||
|
} git_config_entry;
|
||||||
|
|
||||||
|
int git_repository_config(git_config **out, git_repository *repo);
|
||||||
|
void git_config_free(git_config *cfg);
|
||||||
|
|
||||||
|
int git_config_get_string(const char **out, const git_config *cfg, const char *name);
|
||||||
|
int git_config_set_string(git_config *cfg, const char *name, const char *value);
|
||||||
|
int git_config_set_bool(git_config *cfg, const char *name, int value);
|
||||||
|
int git_config_set_int64(git_config *cfg, const char *name, int64_t value);
|
||||||
|
|
||||||
|
int git_config_parse_bool(int *out, const char *value);
|
||||||
|
int git_config_parse_int64(int64_t *out, const char *value);
|
||||||
|
|
||||||
|
int git_config_delete_entry(git_config *cfg, const char *name);
|
||||||
|
int git_config_add_file_ondisk(git_config *cfg,
|
||||||
|
const char *path,
|
||||||
|
git_config_level_t level,
|
||||||
|
int force);
|
||||||
|
|
||||||
|
int git_config_iterator_new(git_config_iterator **out, const git_config *cfg);
|
||||||
|
int git_config_next(git_config_entry **entry, git_config_iterator *iter);
|
||||||
|
void git_config_iterator_free(git_config_iterator *iter);
|
||||||
|
|
||||||
|
int git_config_multivar_iterator_new(git_config_iterator **out, const git_config *cfg, const char *name, const char *regexp);
|
||||||
|
int git_config_set_multivar(git_config *cfg, const char *name, const char *regexp, const char *value);
|
||||||
|
|
||||||
|
int git_config_new(git_config **out);
|
||||||
|
int git_config_open_ondisk(git_config **out, const char *path);
|
||||||
|
int git_config_find_system(git_buf *out);
|
||||||
|
int git_config_find_global(git_buf *out);
|
||||||
|
int git_config_find_xdg(git_buf *out);
|
58
pygit2/errors.py
Normal file
58
pygit2/errors.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# -*- 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, io=False):
|
||||||
|
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:
|
||||||
|
if io:
|
||||||
|
raise IOError(message)
|
||||||
|
else:
|
||||||
|
raise KeyError(message)
|
||||||
|
elif err == C.GIT_EINVALIDSPEC:
|
||||||
|
raise ValueError(message)
|
||||||
|
elif err == C.GIT_ITEROVER:
|
||||||
|
raise StopIteration()
|
||||||
|
|
||||||
|
raise GitError(message)
|
||||||
|
|
121
pygit2/ffi.py
Normal file
121
pygit2/ffi.py
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
# -*- 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
|
||||||
|
import codecs
|
||||||
|
from os import path, getenv
|
||||||
|
from cffi import FFI
|
||||||
|
import sys
|
||||||
|
|
||||||
|
(major_version, _, _, _, _) = sys.version_info
|
||||||
|
|
||||||
|
if major_version < 3:
|
||||||
|
def to_str(s, encoding='utf-8', errors='strict'):
|
||||||
|
if s == ffi.NULL or s == None:
|
||||||
|
return ffi.NULL
|
||||||
|
|
||||||
|
if isinstance(s, unicode):
|
||||||
|
encoding = encoding or 'utf-8'
|
||||||
|
return s.encode(encoding, errors)
|
||||||
|
|
||||||
|
return s
|
||||||
|
else:
|
||||||
|
def to_str(s, encoding='utf-8', errors='strict'):
|
||||||
|
if s == ffi.NULL or s == None:
|
||||||
|
return ffi.NULL
|
||||||
|
|
||||||
|
if isinstance(s, bytes):
|
||||||
|
return s
|
||||||
|
|
||||||
|
return s.encode(encoding, errors)
|
||||||
|
|
||||||
|
if major_version < 3:
|
||||||
|
def is_string(s):
|
||||||
|
return isinstance(s, basestring)
|
||||||
|
else:
|
||||||
|
def is_string(s):
|
||||||
|
return isinstance(s, str)
|
||||||
|
|
||||||
|
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 []', to_str(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 codecs.open(decl_path, 'r', 'utf-8') as header:
|
||||||
|
ffi.cdef(header.read())
|
||||||
|
|
||||||
|
# if LIBGIT2 exists, set build and link against that version
|
||||||
|
libgit2_path = getenv('LIBGIT2')
|
||||||
|
include_dirs = []
|
||||||
|
library_dirs = []
|
||||||
|
if libgit2_path:
|
||||||
|
include_dirs = [path.join(libgit2_path, 'include')]
|
||||||
|
library_dirs = [path.join(libgit2_path, 'lib')]
|
||||||
|
|
||||||
|
C = ffi.verify("#include <git2.h>", libraries=["git2"], include_dirs=include_dirs, library_dirs=library_dirs)
|
96
pygit2/refspec.py
Normal file
96
pygit2/refspec.py
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
# -*- 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, fn):
|
||||||
|
buf = ffi.new('git_buf *', (ffi.NULL, 0))
|
||||||
|
err = fn(buf, self._refspec, to_str(ref))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return ffi.string(buf.ptr).decode()
|
||||||
|
finally:
|
||||||
|
C.git_buf_free(buf)
|
||||||
|
|
||||||
|
def transform(self, ref):
|
||||||
|
"""transform(str) -> str
|
||||||
|
|
||||||
|
Transform a reference name according to this refspec from the lhs to the rhs."""
|
||||||
|
return self._transform(ref, C.git_refspec_transform)
|
||||||
|
|
||||||
|
def rtransform(self, ref):
|
||||||
|
"""transform(str) -> str
|
||||||
|
|
||||||
|
Transform a reference name according to this refspec from the lhs to the rhs"""
|
||||||
|
return self._transform(ref, C.git_refspec_rtransform)
|
413
pygit2/remote.py
Normal file
413
pygit2/remote.py
Normal file
@@ -0,0 +1,413 @@
|
|||||||
|
# -*- 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 _pygit2 import Oid
|
||||||
|
|
||||||
|
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
|
||||||
|
"""Total number objects to download"""
|
||||||
|
|
||||||
|
self.indexed_objects = tp.indexed_objects
|
||||||
|
"""Objects which have been indexed"""
|
||||||
|
|
||||||
|
self.received_objects = tp.received_objects
|
||||||
|
"""Objects which have been received up to now"""
|
||||||
|
|
||||||
|
self.local_objects = tp.local_objects
|
||||||
|
"""Local objects which were used to fix the thin pack"""
|
||||||
|
|
||||||
|
self.total_deltas = tp.total_deltas
|
||||||
|
"""Total number of deltas in the pack"""
|
||||||
|
|
||||||
|
self.indexed_deltas = tp.indexed_deltas
|
||||||
|
"""Deltas which have been indexed"""
|
||||||
|
|
||||||
|
self.received_bytes = tp.received_bytes
|
||||||
|
""""Number of bytes received up to now"""
|
||||||
|
|
||||||
|
class Remote(object):
|
||||||
|
|
||||||
|
def sideband_progress(self, string):
|
||||||
|
"""Progress output callback
|
||||||
|
|
||||||
|
Override this function with your own progress reporting function
|
||||||
|
|
||||||
|
:param str string: Progress otuput from the remote
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def credentials(self, url, username_from_url, allowed_types):
|
||||||
|
"""Credentials callback
|
||||||
|
|
||||||
|
If the remote server requires authentication, this function will
|
||||||
|
be called and its return value used for authentication. Override
|
||||||
|
it if you want to be able to perform authentication.
|
||||||
|
|
||||||
|
:param str url: The url of the remote
|
||||||
|
:param username_from_url: Username extracted from the url, if any
|
||||||
|
:type username_from_url: str or None
|
||||||
|
:param int allowed_types: credential types supported by the remote
|
||||||
|
:rtype: credential
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def transfer_progress(self, stats):
|
||||||
|
"""Transfer progress callback
|
||||||
|
|
||||||
|
Override with your own function to report transfer progress.
|
||||||
|
|
||||||
|
:param TransferProgress stats: The progress up to now
|
||||||
|
"""
|
||||||
|
pass
|
||||||
|
|
||||||
|
def update_tips(self, refname, old, new):
|
||||||
|
"""Update tips callabck
|
||||||
|
|
||||||
|
Override with your own function to report reference updates
|
||||||
|
|
||||||
|
:param str refname: the name of the reference that's being updated
|
||||||
|
:param Oid old: the reference's old value
|
||||||
|
:param Oid new: the reference's new value
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, repo, ptr):
|
||||||
|
"""The constructor is for internal use only"""
|
||||||
|
|
||||||
|
self._repo = repo
|
||||||
|
self._remote = ptr
|
||||||
|
self._stored_exception = None
|
||||||
|
|
||||||
|
# Build the callback structure
|
||||||
|
callbacks = ffi.new('git_remote_callbacks *')
|
||||||
|
callbacks.version = 1
|
||||||
|
callbacks.sideband_progress = self._sideband_progress_cb
|
||||||
|
callbacks.transfer_progress = self._transfer_progress_cb
|
||||||
|
callbacks.update_tips = self._update_tips_cb
|
||||||
|
callbacks.credentials = self._credentials_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):
|
||||||
|
"""Name of the remote"""
|
||||||
|
|
||||||
|
return maybe_string(C.git_remote_name(self._remote))
|
||||||
|
|
||||||
|
@name.setter
|
||||||
|
def name(self, value):
|
||||||
|
if not value:
|
||||||
|
raise ValueError("New remote name must be a non-empty string")
|
||||||
|
|
||||||
|
err = C.git_remote_rename(self._remote, to_str(value), ffi.NULL, ffi.NULL)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def url(self):
|
||||||
|
"""Url of the remote"""
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Push url of the remote"""
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""save()
|
||||||
|
|
||||||
|
Save a remote to its repository's configuration"""
|
||||||
|
|
||||||
|
err = C.git_remote_save(self._remote)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
def fetch(self, signature=None, message=None):
|
||||||
|
"""fetch(signature, message) -> TransferProgress
|
||||||
|
|
||||||
|
Perform a fetch against this remote.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if signature:
|
||||||
|
ptr = signature._pointer[:]
|
||||||
|
else:
|
||||||
|
ptr = ffi.NULL
|
||||||
|
|
||||||
|
self._stored_exception = None
|
||||||
|
err = C.git_remote_fetch(self._remote, ptr, to_str(message))
|
||||||
|
if self._stored_exception:
|
||||||
|
raise self._stored_exception
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return TransferProgress(C.git_remote_stats(self._remote))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def refspec_count(self):
|
||||||
|
"""Total number of refspecs in this remote"""
|
||||||
|
|
||||||
|
return C.git_remote_refspec_count(self._remote)
|
||||||
|
|
||||||
|
def get_refspec(self, n):
|
||||||
|
"""get_refspec(n) -> Refspec
|
||||||
|
|
||||||
|
Return the refspec at the given position
|
||||||
|
"""
|
||||||
|
spec = C.git_remote_get_refspec(self._remote, n)
|
||||||
|
return Refspec(self, spec)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def fetch_refspecs(self):
|
||||||
|
"""Refspecs that will be used for fetching"""
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""Refspecs that will be used for pushing"""
|
||||||
|
|
||||||
|
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):
|
||||||
|
"""add_fetch(refspec)
|
||||||
|
|
||||||
|
Add a fetch refspec to the remote"""
|
||||||
|
|
||||||
|
err = C.git_remote_add_fetch(self._remote, to_str(spec))
|
||||||
|
|
||||||
|
def add_push(self, spec):
|
||||||
|
"""add_push(refspec)
|
||||||
|
|
||||||
|
Add a push refspec to the remote"""
|
||||||
|
|
||||||
|
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, signature=None, message=None):
|
||||||
|
"""push(refspec, signature, message)
|
||||||
|
|
||||||
|
Push the given refspec to the remote. Raises ``GitError`` on error
|
||||||
|
|
||||||
|
:param str spec: push refspec to use
|
||||||
|
:param Signature signature: signature to use when updating the tips
|
||||||
|
:param str message: message to use when updating the tips
|
||||||
|
"""
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
if signature:
|
||||||
|
ptr = signature._pointer[:]
|
||||||
|
else:
|
||||||
|
ptr = ffi.NULL
|
||||||
|
|
||||||
|
err = C.git_push_update_tips(push, ptr, to_str(message))
|
||||||
|
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('git_transfer_progress_cb')
|
||||||
|
def _transfer_progress_cb(stats_ptr, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
|
||||||
|
if not hasattr(self, 'transfer_progress') or not self.transfer_progress:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
self.transfer_progress(TransferProgress(stats_ptr))
|
||||||
|
except Exception as e:
|
||||||
|
self._stored_exception = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@ffi.callback('git_transport_message_cb')
|
||||||
|
def _sideband_progress_cb(string, length, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
|
||||||
|
if not hasattr(self, 'progress') or not self.progress:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = ffi.string(string, length).decode()
|
||||||
|
self.progress(s)
|
||||||
|
except Exception as e:
|
||||||
|
self._stored_exception = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@ffi.callback('int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data)')
|
||||||
|
def _update_tips_cb(refname, a, b, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
|
||||||
|
if not hasattr(self, 'update_tips') or not self.update_tips:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
s = maybe_string(refname)
|
||||||
|
a = Oid(raw=bytes(ffi.buffer(a)[:]))
|
||||||
|
b = Oid(raw=bytes(ffi.buffer(b)[:]))
|
||||||
|
|
||||||
|
self.update_tips(s, a, b)
|
||||||
|
except Exception as e:
|
||||||
|
self._stored_exception = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
@ffi.callback('int (*credentials)(git_cred **cred, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)')
|
||||||
|
def _credentials_cb(cred_out, url, username, allowed, data):
|
||||||
|
self = ffi.from_handle(data)
|
||||||
|
|
||||||
|
if not hasattr(self, 'credentials') or not self.credentials:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
try:
|
||||||
|
ccred = get_credentials(self.credentials, url, username, allowed)
|
||||||
|
cred_out[0] = ccred[0]
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
self._stored_exception = e
|
||||||
|
return C.GIT_EUSER
|
||||||
|
|
||||||
|
return 0
|
||||||
|
|
||||||
|
def get_credentials(fn, url, username, allowed):
|
||||||
|
"""Call fn and return the credentials object"""
|
||||||
|
|
||||||
|
url_str = maybe_string(url)
|
||||||
|
username_str = maybe_string(username)
|
||||||
|
|
||||||
|
creds = fn(url_str, username_str, allowed)
|
||||||
|
|
||||||
|
if not hasattr(creds, 'credential_type') or not hasattr(creds, 'credential_tuple'):
|
||||||
|
raise TypeError("credential does not implement interface")
|
||||||
|
|
||||||
|
cred_type = creds.credential_type
|
||||||
|
|
||||||
|
if not (allowed & cred_type):
|
||||||
|
raise TypeError("invalid credential type")
|
||||||
|
|
||||||
|
ccred = ffi.new('git_cred **')
|
||||||
|
if cred_type == C.GIT_CREDTYPE_USERPASS_PLAINTEXT:
|
||||||
|
name, passwd = creds.credential_tuple
|
||||||
|
err = C.git_cred_userpass_plaintext_new(ccred, to_str(name), to_str(passwd))
|
||||||
|
|
||||||
|
elif cred_type == C.GIT_CREDTYPE_SSH_KEY:
|
||||||
|
name, pubkey, privkey, passphrase = creds.credential_tuple
|
||||||
|
err = C.git_cred_ssh_key_new(ccred, to_str(name),to_str(pubkey),
|
||||||
|
to_str(privkey), to_str(passphrase))
|
||||||
|
|
||||||
|
else:
|
||||||
|
raise TypeError("unsupported credential type")
|
||||||
|
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return ccred
|
@@ -35,9 +35,22 @@ 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
|
||||||
|
from .config import Config
|
||||||
|
|
||||||
class Repository(_Repository):
|
class Repository(_Repository):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super(Repository, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Get the pointer as the contents of a buffer and store it for
|
||||||
|
# later access
|
||||||
|
repo_cptr = ffi.new('git_repository **')
|
||||||
|
ffi.buffer(repo_cptr)[:] = self._pointer[:]
|
||||||
|
self._repo = repo_cptr[0]
|
||||||
|
|
||||||
#
|
#
|
||||||
# Mapping interface
|
# Mapping interface
|
||||||
#
|
#
|
||||||
@@ -59,6 +72,62 @@ 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
cremote = ffi.new('git_remote **')
|
||||||
|
|
||||||
|
err = C.git_remote_create(cremote, self._repo, to_str(name), to_str(url))
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return Remote(self, cremote[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def remotes(self):
|
||||||
|
"""Returns all configured remotes"""
|
||||||
|
|
||||||
|
names = ffi.new('git_strarray *')
|
||||||
|
|
||||||
|
try:
|
||||||
|
err = C.git_remote_list(names, self._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, self._repo, names.strings[i])
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
l[i] = Remote(self, cremote[0])
|
||||||
|
return l
|
||||||
|
finally:
|
||||||
|
C.git_strarray_free(names)
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# Configuration
|
||||||
|
#
|
||||||
|
@property
|
||||||
|
def config(self):
|
||||||
|
"""The configuration file for this repository
|
||||||
|
|
||||||
|
If a the configuration hasn't been set yet, the default config for
|
||||||
|
repository will be returned, including global and system configurations
|
||||||
|
(if they are available)."""
|
||||||
|
|
||||||
|
cconfig = ffi.new('git_config **')
|
||||||
|
err = C.git_repository_config(cconfig, self._repo)
|
||||||
|
check_error(err)
|
||||||
|
|
||||||
|
return Config.from_c(self, cconfig[0])
|
||||||
|
|
||||||
#
|
#
|
||||||
# References
|
# References
|
||||||
#
|
#
|
||||||
@@ -78,7 +147,7 @@ class Repository(_Repository):
|
|||||||
|
|
||||||
Examples::
|
Examples::
|
||||||
|
|
||||||
repo.create_reference('refs/heads/foo', repo.head.hex)
|
repo.create_reference('refs/heads/foo', repo.head.target)
|
||||||
repo.create_reference('refs/tags/foo', 'refs/heads/master')
|
repo.create_reference('refs/tags/foo', 'refs/heads/master')
|
||||||
repo.create_reference('refs/tags/foo', 'bbb78a9cec580')
|
repo.create_reference('refs/tags/foo', 'bbb78a9cec580')
|
||||||
"""
|
"""
|
||||||
|
@@ -23,4 +23,4 @@
|
|||||||
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||||
# Boston, MA 02110-1301, USA.
|
# Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
__version__ = '0.20.2'
|
__version__ = '0.20.3'
|
||||||
|
8
setup.py
8
setup.py
@@ -173,6 +173,11 @@ classifiers = [
|
|||||||
with codecs.open('README.rst', 'r', 'utf-8') as readme:
|
with codecs.open('README.rst', 'r', 'utf-8') as readme:
|
||||||
long_description = readme.read()
|
long_description = readme.read()
|
||||||
|
|
||||||
|
# This ffi is pygit2.ffi due to the path trick used in the beginning
|
||||||
|
# of the file
|
||||||
|
from ffi import ffi
|
||||||
|
ffi_ext = ffi.verifier.get_extension()
|
||||||
|
|
||||||
setup(name='pygit2',
|
setup(name='pygit2',
|
||||||
description='Python bindings for libgit2.',
|
description='Python bindings for libgit2.',
|
||||||
keywords='git',
|
keywords='git',
|
||||||
@@ -184,10 +189,13 @@ setup(name='pygit2',
|
|||||||
maintainer_email='jdavid.ibp@gmail.com',
|
maintainer_email='jdavid.ibp@gmail.com',
|
||||||
long_description=long_description,
|
long_description=long_description,
|
||||||
packages=['pygit2'],
|
packages=['pygit2'],
|
||||||
|
package_data={'pygit2': ['decl.h']},
|
||||||
|
install_requires=['cffi'],
|
||||||
ext_modules=[
|
ext_modules=[
|
||||||
Extension('_pygit2', pygit2_exts,
|
Extension('_pygit2', pygit2_exts,
|
||||||
include_dirs=[libgit2_include, 'include'],
|
include_dirs=[libgit2_include, 'include'],
|
||||||
library_dirs=[libgit2_lib],
|
library_dirs=[libgit2_lib],
|
||||||
libraries=['git2']),
|
libraries=['git2']),
|
||||||
|
ffi_ext,
|
||||||
],
|
],
|
||||||
cmdclass=cmdclass)
|
cmdclass=cmdclass)
|
||||||
|
64
src/blob.c
64
src/blob.c
@@ -63,7 +63,7 @@ Blob_diff(Blob *self, PyObject *args, PyObject *kwds)
|
|||||||
int err;
|
int err;
|
||||||
char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", NULL};
|
char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!ssI", keywords,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!Iss", keywords,
|
||||||
&BlobType, &py_blob, &opts.flags,
|
&BlobType, &py_blob, &opts.flags,
|
||||||
&old_as_path, &new_as_path))
|
&old_as_path, &new_as_path))
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -106,7 +106,7 @@ Blob_diff_to_buffer(Blob *self, PyObject *args, PyObject *kwds)
|
|||||||
char *keywords[] = {"buffer", "flag", "old_as_path", "buffer_as_path",
|
char *keywords[] = {"buffer", "flag", "old_as_path", "buffer_as_path",
|
||||||
NULL};
|
NULL};
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s#ssI", keywords,
|
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s#Iss", keywords,
|
||||||
&buffer, &buffer_len, &opts.flags,
|
&buffer, &buffer_len, &opts.flags,
|
||||||
&old_as_path, &buffer_as_path))
|
&old_as_path, &buffer_as_path))
|
||||||
return NULL;
|
return NULL;
|
||||||
@@ -158,8 +158,58 @@ PyGetSetDef Blob_getseters[] = {
|
|||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
Blob_getbuffer(Blob *self, Py_buffer *view, int flags)
|
||||||
|
{
|
||||||
|
return PyBuffer_FillInfo(view, (PyObject *) self,
|
||||||
|
(void *) git_blob_rawcontent(self->blob),
|
||||||
|
git_blob_rawsize(self->blob), 1, flags);
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Blob__doc__, "Blob objects.");
|
#if PY_MAJOR_VERSION == 2
|
||||||
|
|
||||||
|
static Py_ssize_t
|
||||||
|
Blob_getreadbuffer(Blob *self, Py_ssize_t index, const void **ptr)
|
||||||
|
{
|
||||||
|
if (index != 0) {
|
||||||
|
PyErr_SetString(PyExc_SystemError,
|
||||||
|
"accessing non-existent blob segment");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*ptr = (void *) git_blob_rawcontent(self->blob);
|
||||||
|
return git_blob_rawsize(self->blob);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Py_ssize_t
|
||||||
|
Blob_getsegcount(Blob *self, Py_ssize_t *lenp)
|
||||||
|
{
|
||||||
|
if (lenp)
|
||||||
|
*lenp = git_blob_rawsize(self->blob);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyBufferProcs Blob_as_buffer = {
|
||||||
|
(readbufferproc)Blob_getreadbuffer,
|
||||||
|
NULL, /* bf_getwritebuffer */
|
||||||
|
(segcountproc)Blob_getsegcount,
|
||||||
|
NULL, /* charbufferproc */
|
||||||
|
(getbufferproc)Blob_getbuffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
static PyBufferProcs Blob_as_buffer = {
|
||||||
|
(getbufferproc)Blob_getbuffer,
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* python 2 vs python 3 buffers */
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Blob__doc__, "Blob object.\n"
|
||||||
|
"\n"
|
||||||
|
"Blobs implement the buffer interface, which means you can get access\n"
|
||||||
|
"to its data via `memoryview(blob)` without the need to create a copy."
|
||||||
|
);
|
||||||
|
|
||||||
PyTypeObject BlobType = {
|
PyTypeObject BlobType = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
@@ -180,8 +230,14 @@ PyTypeObject BlobType = {
|
|||||||
0, /* tp_str */
|
0, /* tp_str */
|
||||||
0, /* tp_getattro */
|
0, /* tp_getattro */
|
||||||
0, /* tp_setattro */
|
0, /* tp_setattro */
|
||||||
0, /* tp_as_buffer */
|
&Blob_as_buffer, /* tp_as_buffer */
|
||||||
|
#if PY_MAJOR_VERSION == 2
|
||||||
|
Py_TPFLAGS_DEFAULT | /* tp_flags */
|
||||||
|
Py_TPFLAGS_HAVE_GETCHARBUFFER |
|
||||||
|
Py_TPFLAGS_HAVE_NEWBUFFER,
|
||||||
|
#else
|
||||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||||
|
#endif
|
||||||
Blob__doc__, /* tp_doc */
|
Blob__doc__, /* tp_doc */
|
||||||
0, /* tp_traverse */
|
0, /* tp_traverse */
|
||||||
0, /* tp_clear */
|
0, /* tp_clear */
|
||||||
|
495
src/config.c
495
src/config.c
@@ -1,495 +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 "error.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
extern PyTypeObject ConfigType;
|
|
||||||
extern PyTypeObject ConfigIterType;
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
wrap_config(char *c_path) {
|
|
||||||
int err;
|
|
||||||
PyObject *py_path;
|
|
||||||
Config *py_config;
|
|
||||||
|
|
||||||
py_path = Py_BuildValue("(s)", c_path);
|
|
||||||
py_config = PyObject_New(Config, &ConfigType);
|
|
||||||
|
|
||||||
err = Config_init(py_config, py_path, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
return (PyObject*) py_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
Config_init(Config *self, PyObject *args, PyObject *kwds)
|
|
||||||
{
|
|
||||||
char *path = NULL;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (kwds && PyDict_Size(kwds) > 0) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"Config takes no keyword arguments");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "|s", &path))
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (path == NULL)
|
|
||||||
err = git_config_new(&self->config);
|
|
||||||
else
|
|
||||||
err = git_config_open_ondisk(&self->config, path);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
git_config_free(self->config);
|
|
||||||
|
|
||||||
if (err == GIT_ENOTFOUND)
|
|
||||||
Error_set_exc(PyExc_IOError);
|
|
||||||
else
|
|
||||||
Error_set(err);
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
Config_dealloc(Config *self)
|
|
||||||
{
|
|
||||||
git_config_free(self->config);
|
|
||||||
Py_TYPE(self)->tp_free(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_get_global_config__doc__,
|
|
||||||
"get_global_config() -> Config\n"
|
|
||||||
"\n"
|
|
||||||
"Return an object representing the global configuration file.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_get_global_config(void)
|
|
||||||
{
|
|
||||||
git_buf path = {NULL};
|
|
||||||
PyObject *py_config;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = git_config_find_global(&path);
|
|
||||||
if (err < 0) {
|
|
||||||
if (err == GIT_ENOTFOUND) {
|
|
||||||
PyErr_SetString(PyExc_IOError, "Global config file not found.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
py_config = wrap_config(path.ptr);
|
|
||||||
|
|
||||||
git_buf_free(&path);
|
|
||||||
return py_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_get_system_config__doc__,
|
|
||||||
"get_system_config() -> Config\n"
|
|
||||||
"\n"
|
|
||||||
"Return an object representing the system configuration file.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_get_system_config(void)
|
|
||||||
{
|
|
||||||
git_buf path = {NULL};
|
|
||||||
PyObject *py_config;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = git_config_find_system(&path);
|
|
||||||
if (err < 0) {
|
|
||||||
if (err == GIT_ENOTFOUND) {
|
|
||||||
PyErr_SetString(PyExc_IOError, "System config file not found.");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
return Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
py_config = wrap_config(path.ptr);
|
|
||||||
|
|
||||||
git_buf_free(&path);
|
|
||||||
return py_config;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
Config_contains(Config *self, PyObject *py_key) {
|
|
||||||
int err;
|
|
||||||
const char *c_value, *c_key;
|
|
||||||
PyObject *tkey;
|
|
||||||
|
|
||||||
c_key = py_str_borrow_c_str(&tkey, py_key, NULL);
|
|
||||||
if (c_key == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = git_config_get_string(&c_value, self->config, c_key);
|
|
||||||
Py_DECREF(tkey);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
if (err == GIT_ENOTFOUND)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Error_set(err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_getitem(Config *self, PyObject *py_key)
|
|
||||||
{
|
|
||||||
int64_t value_int;
|
|
||||||
int err, value_bool;
|
|
||||||
const char *value_str;
|
|
||||||
const char *key;
|
|
||||||
PyObject* py_value, *tmp;
|
|
||||||
|
|
||||||
key = py_str_borrow_c_str(&tmp, py_key, NULL);
|
|
||||||
if (key == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
err = git_config_get_string(&value_str, self->config, key);
|
|
||||||
Py_CLEAR(tmp);
|
|
||||||
if (err < 0)
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
if (git_config_parse_int64(&value_int, value_str) == 0)
|
|
||||||
py_value = PyLong_FromLongLong(value_int);
|
|
||||||
else if(git_config_parse_bool(&value_bool, value_str) == 0)
|
|
||||||
py_value = PyBool_FromLong(value_bool);
|
|
||||||
else
|
|
||||||
py_value = to_unicode(value_str, NULL, NULL);
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
if (err < 0) {
|
|
||||||
if (err == GIT_ENOTFOUND) {
|
|
||||||
PyErr_SetObject(PyExc_KeyError, py_key);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return py_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Config_setitem(Config *self, PyObject *py_key, PyObject *py_value)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char *key, *value;
|
|
||||||
PyObject *tkey, *tvalue;
|
|
||||||
|
|
||||||
key = py_str_borrow_c_str(&tkey, py_key, NULL);
|
|
||||||
if (key == NULL)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
if (py_value == NULL)
|
|
||||||
err = git_config_delete_entry(self->config, key);
|
|
||||||
else if (PyBool_Check(py_value)) {
|
|
||||||
err = git_config_set_bool(self->config, key,
|
|
||||||
(int)PyObject_IsTrue(py_value));
|
|
||||||
} else if (PyLong_Check(py_value)) {
|
|
||||||
err = git_config_set_int64(self->config, key,
|
|
||||||
(int64_t)PyLong_AsLong(py_value));
|
|
||||||
} else {
|
|
||||||
value = py_str_borrow_c_str(&tvalue, py_value, NULL);
|
|
||||||
err = git_config_set_string(self->config, key, value);
|
|
||||||
Py_DECREF(tvalue);
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_DECREF(tkey);
|
|
||||||
if (err < 0) {
|
|
||||||
Error_set(err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_add_file__doc__,
|
|
||||||
"add_file(path, level=0, force=0)\n"
|
|
||||||
"\n"
|
|
||||||
"Add a config file instance to an existing config.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_add_file(Config *self, PyObject *args, PyObject *kwds)
|
|
||||||
{
|
|
||||||
char *keywords[] = {"path", "level", "force", NULL};
|
|
||||||
int err;
|
|
||||||
char *path;
|
|
||||||
unsigned int level = 0;
|
|
||||||
int force = 0;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|Ii", keywords,
|
|
||||||
&path, &level, &force))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
err = git_config_add_file_ondisk(self->config, path, level, force);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set_str(err, path);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_get_multivar__doc__,
|
|
||||||
"get_multivar(name[, regex]) -> [str, ...]\n"
|
|
||||||
"\n"
|
|
||||||
"Get each value of a multivar ''name'' as a list. The optional ''regex''\n"
|
|
||||||
"parameter is expected to be a regular expression to filter the variables\n"
|
|
||||||
"we're interested in.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_get_multivar(Config *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
PyObject *list;
|
|
||||||
const char *name = NULL;
|
|
||||||
const char *regex = NULL;
|
|
||||||
git_config_iterator *iter;
|
|
||||||
git_config_entry *entry;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s|s", &name, ®ex))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
list = PyList_New(0);
|
|
||||||
err = git_config_multivar_iterator_new(&iter, self->config, name, regex);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
while ((err = git_config_next(&entry, iter)) == 0) {
|
|
||||||
PyObject *item;
|
|
||||||
|
|
||||||
item = to_unicode(entry->value, NULL, NULL);
|
|
||||||
if (item == NULL) {
|
|
||||||
git_config_iterator_free(iter);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyList_Append(list, item);
|
|
||||||
Py_CLEAR(item);
|
|
||||||
}
|
|
||||||
|
|
||||||
git_config_iterator_free(iter);
|
|
||||||
if (err == GIT_ITEROVER)
|
|
||||||
err = 0;
|
|
||||||
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
return list;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config_set_multivar__doc__,
|
|
||||||
"set_multivar(name, regex, value)\n"
|
|
||||||
"\n"
|
|
||||||
"Set a multivar ''name'' to ''value''. ''regexp'' is a regular expression\n"
|
|
||||||
"to indicate which values to replace");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_set_multivar(Config *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char *name = NULL;
|
|
||||||
const char *regex = NULL;
|
|
||||||
const char *value = NULL;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "sss", &name, ®ex, &value))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
err = git_config_set_multivar(self->config, name, regex, value);
|
|
||||||
if (err < 0) {
|
|
||||||
if (err == GIT_ENOTFOUND)
|
|
||||||
Error_set(err);
|
|
||||||
else
|
|
||||||
PyErr_SetNone(PyExc_TypeError);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Config_iter(Config *self)
|
|
||||||
{
|
|
||||||
ConfigIter *iter;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
iter = PyObject_New(ConfigIter, &ConfigIterType);
|
|
||||||
if (!iter)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if ((err = git_config_iterator_new(&iter->iter, self->config)) < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
Py_INCREF(self);
|
|
||||||
iter->owner = self;
|
|
||||||
|
|
||||||
return (PyObject*)iter;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMethodDef Config_methods[] = {
|
|
||||||
METHOD(Config, get_system_config, METH_NOARGS | METH_STATIC),
|
|
||||||
METHOD(Config, get_global_config, METH_NOARGS | METH_STATIC),
|
|
||||||
METHOD(Config, add_file, METH_VARARGS | METH_KEYWORDS),
|
|
||||||
METHOD(Config, get_multivar, METH_VARARGS),
|
|
||||||
METHOD(Config, set_multivar, METH_VARARGS),
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PySequenceMethods Config_as_sequence = {
|
|
||||||
0, /* sq_length */
|
|
||||||
0, /* sq_concat */
|
|
||||||
0, /* sq_repeat */
|
|
||||||
0, /* sq_item */
|
|
||||||
0, /* sq_slice */
|
|
||||||
0, /* sq_ass_item */
|
|
||||||
0, /* sq_ass_slice */
|
|
||||||
(objobjproc)Config_contains, /* sq_contains */
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMappingMethods Config_as_mapping = {
|
|
||||||
0, /* mp_length */
|
|
||||||
(binaryfunc)Config_getitem, /* mp_subscript */
|
|
||||||
(objobjargproc)Config_setitem, /* mp_ass_subscript */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Config__doc__, "Configuration management.");
|
|
||||||
|
|
||||||
PyTypeObject ConfigType = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"_pygit2.Config", /* tp_name */
|
|
||||||
sizeof(Config), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)Config_dealloc, /* tp_dealloc */
|
|
||||||
0, /* tp_print */
|
|
||||||
0, /* tp_getattr */
|
|
||||||
0, /* tp_setattr */
|
|
||||||
0, /* tp_compare */
|
|
||||||
0, /* tp_repr */
|
|
||||||
0, /* tp_as_number */
|
|
||||||
&Config_as_sequence, /* tp_as_sequence */
|
|
||||||
&Config_as_mapping, /* 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, /* tp_flags */
|
|
||||||
Config__doc__, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
(getiterfunc)Config_iter, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
Config_methods, /* tp_methods */
|
|
||||||
0, /* tp_members */
|
|
||||||
0, /* tp_getset */
|
|
||||||
0, /* tp_base */
|
|
||||||
0, /* tp_dict */
|
|
||||||
0, /* tp_descr_get */
|
|
||||||
0, /* tp_descr_set */
|
|
||||||
0, /* tp_dictoffset */
|
|
||||||
(initproc)Config_init, /* tp_init */
|
|
||||||
0, /* tp_alloc */
|
|
||||||
0, /* tp_new */
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
ConfigIter_dealloc(ConfigIter *self)
|
|
||||||
{
|
|
||||||
Py_CLEAR(self->owner);
|
|
||||||
git_config_iterator_free(self->iter);
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
ConfigIter_iternext(ConfigIter *self)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
git_config_entry *entry;
|
|
||||||
|
|
||||||
if ((err = git_config_next(&entry, self->iter)) < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
return Py_BuildValue("ss", entry->name, entry->value);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(ConfigIter__doc__, "Configuration iterator.");
|
|
||||||
|
|
||||||
PyTypeObject ConfigIterType = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"_pygit2.ConfigIter", /* tp_name */
|
|
||||||
sizeof(ConfigIter), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)ConfigIter_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 */
|
|
||||||
ConfigIter__doc__, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
PyObject_SelfIter, /* tp_iter */
|
|
||||||
(iternextfunc)ConfigIter_iternext, /* tp_iternext */
|
|
||||||
|
|
||||||
};
|
|
45
src/config.h
45
src/config.h
@@ -1,45 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_pygit2_config_h
|
|
||||||
#define INCLUDE_pygit2_config_h
|
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <git2.h>
|
|
||||||
|
|
||||||
PyObject* wrap_config(char *c_path);
|
|
||||||
PyObject* Config_get_global_config(void);
|
|
||||||
PyObject* Config_get_system_config(void);
|
|
||||||
PyObject* Config_add_file(Config *self, PyObject *args, PyObject *kwds);
|
|
||||||
PyObject* Config_getitem(Config *self, PyObject *key);
|
|
||||||
PyObject* Config_foreach(Config *self, PyObject *args);
|
|
||||||
PyObject* Config_get_multivar(Config *self, PyObject *args);
|
|
||||||
PyObject* Config_set_multivar(Config *self, PyObject *args);
|
|
||||||
int Config_init(Config *self, PyObject *args, PyObject *kwds);
|
|
||||||
int Config_setitem(Config *self, PyObject *key, PyObject *value);
|
|
||||||
#endif
|
|
87
src/pygit2.c
87
src/pygit2.c
@@ -56,8 +56,6 @@ extern PyTypeObject IndexType;
|
|||||||
extern PyTypeObject IndexEntryType;
|
extern PyTypeObject IndexEntryType;
|
||||||
extern PyTypeObject IndexIterType;
|
extern PyTypeObject IndexIterType;
|
||||||
extern PyTypeObject WalkerType;
|
extern PyTypeObject WalkerType;
|
||||||
extern PyTypeObject ConfigType;
|
|
||||||
extern PyTypeObject ConfigIterType;
|
|
||||||
extern PyTypeObject ReferenceType;
|
extern PyTypeObject ReferenceType;
|
||||||
extern PyTypeObject RefLogIterType;
|
extern PyTypeObject RefLogIterType;
|
||||||
extern PyTypeObject RefLogEntryType;
|
extern PyTypeObject RefLogEntryType;
|
||||||
@@ -65,7 +63,6 @@ extern PyTypeObject BranchType;
|
|||||||
extern PyTypeObject SignatureType;
|
extern PyTypeObject SignatureType;
|
||||||
extern PyTypeObject RemoteType;
|
extern PyTypeObject RemoteType;
|
||||||
extern PyTypeObject RefspecType;
|
extern PyTypeObject RefspecType;
|
||||||
extern PyTypeObject TransferProgressType;
|
|
||||||
extern PyTypeObject NoteType;
|
extern PyTypeObject NoteType;
|
||||||
extern PyTypeObject NoteIterType;
|
extern PyTypeObject NoteIterType;
|
||||||
extern PyTypeObject BlameType;
|
extern PyTypeObject BlameType;
|
||||||
@@ -105,69 +102,6 @@ init_repository(PyObject *self, PyObject *args) {
|
|||||||
Py_RETURN_NONE;
|
Py_RETURN_NONE;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int
|
|
||||||
credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)
|
|
||||||
{
|
|
||||||
PyObject *credentials = (PyObject *) data;
|
|
||||||
|
|
||||||
return callable_to_credentials(out, url, username_from_url, allowed_types, credentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(clone_repository__doc__,
|
|
||||||
"clone_repository(url, path, bare, remote_name, checkout_branch)\n"
|
|
||||||
"\n"
|
|
||||||
"Clones a Git repository in the given url to the given path "
|
|
||||||
"with the specified options.\n"
|
|
||||||
"\n"
|
|
||||||
"Arguments:\n"
|
|
||||||
"\n"
|
|
||||||
"url\n"
|
|
||||||
" Git repository remote url.\n"
|
|
||||||
"path\n"
|
|
||||||
" Path where to create the repository.\n"
|
|
||||||
"bare\n"
|
|
||||||
" If 'bare' is not 0, then a bare git repository will be created.\n"
|
|
||||||
"remote_name\n"
|
|
||||||
" The name given to the 'origin' remote. The default is 'origin'.\n"
|
|
||||||
"checkout_branch\n"
|
|
||||||
" The name of the branch to checkout. None means use the remote's "
|
|
||||||
"HEAD.\n");
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
clone_repository(PyObject *self, PyObject *args) {
|
|
||||||
git_repository *repo;
|
|
||||||
const char *url;
|
|
||||||
const char *path;
|
|
||||||
unsigned int bare, ignore_cert_errors;
|
|
||||||
const char *remote_name, *checkout_branch;
|
|
||||||
PyObject *credentials = NULL;
|
|
||||||
int err;
|
|
||||||
git_clone_options opts = GIT_CLONE_OPTIONS_INIT;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "zzIIzzO",
|
|
||||||
&url, &path, &bare, &ignore_cert_errors, &remote_name, &checkout_branch, &credentials))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
opts.bare = bare;
|
|
||||||
opts.ignore_cert_errors = ignore_cert_errors;
|
|
||||||
opts.remote_name = remote_name;
|
|
||||||
opts.checkout_branch = checkout_branch;
|
|
||||||
|
|
||||||
if (credentials != Py_None) {
|
|
||||||
opts.remote_callbacks.credentials = credentials_cb;
|
|
||||||
opts.remote_callbacks.payload = credentials;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = git_clone(&repo, url, path, &opts);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
git_repository_free(repo);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(discover_repository__doc__,
|
PyDoc_STRVAR(discover_repository__doc__,
|
||||||
"discover_repository(path[, across_fs[, ceiling_dirs]]) -> str\n"
|
"discover_repository(path[, across_fs[, ceiling_dirs]]) -> str\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -246,8 +180,6 @@ hash(PyObject *self, PyObject *args)
|
|||||||
|
|
||||||
PyMethodDef module_methods[] = {
|
PyMethodDef module_methods[] = {
|
||||||
{"init_repository", init_repository, METH_VARARGS, init_repository__doc__},
|
{"init_repository", init_repository, METH_VARARGS, init_repository__doc__},
|
||||||
{"clone_repository", clone_repository, METH_VARARGS,
|
|
||||||
clone_repository__doc__},
|
|
||||||
{"discover_repository", discover_repository, METH_VARARGS,
|
{"discover_repository", discover_repository, METH_VARARGS,
|
||||||
discover_repository__doc__},
|
discover_repository__doc__},
|
||||||
{"hashfile", hashfile, METH_VARARGS, hashfile__doc__},
|
{"hashfile", hashfile, METH_VARARGS, hashfile__doc__},
|
||||||
@@ -444,25 +376,6 @@ moduleinit(PyObject* m)
|
|||||||
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_XDG);
|
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_XDG);
|
||||||
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_SYSTEM);
|
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_SYSTEM);
|
||||||
|
|
||||||
INIT_TYPE(ConfigType, NULL, PyType_GenericNew)
|
|
||||||
INIT_TYPE(ConfigIterType, NULL, NULL)
|
|
||||||
ADD_TYPE(m, Config)
|
|
||||||
ADD_TYPE(m, ConfigIter)
|
|
||||||
|
|
||||||
/* Remotes */
|
|
||||||
INIT_TYPE(RemoteType, NULL, NULL)
|
|
||||||
INIT_TYPE(RefspecType, NULL, NULL)
|
|
||||||
INIT_TYPE(TransferProgressType, NULL, NULL)
|
|
||||||
ADD_TYPE(m, Remote)
|
|
||||||
ADD_TYPE(m, Refspec)
|
|
||||||
ADD_TYPE(m, TransferProgress)
|
|
||||||
/* Direction for the refspec */
|
|
||||||
ADD_CONSTANT_INT(m, GIT_DIRECTION_FETCH)
|
|
||||||
ADD_CONSTANT_INT(m, GIT_DIRECTION_PUSH)
|
|
||||||
/* Credential types */
|
|
||||||
ADD_CONSTANT_INT(m, GIT_CREDTYPE_USERPASS_PLAINTEXT)
|
|
||||||
ADD_CONSTANT_INT(m, GIT_CREDTYPE_SSH_KEY)
|
|
||||||
|
|
||||||
/* Blame */
|
/* Blame */
|
||||||
INIT_TYPE(BlameType, NULL, NULL)
|
INIT_TYPE(BlameType, NULL, NULL)
|
||||||
INIT_TYPE(BlameIterType, NULL, NULL)
|
INIT_TYPE(BlameIterType, NULL, NULL)
|
||||||
|
275
src/refspec.c
275
src/refspec.c
@@ -1,275 +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)
|
|
||||||
{
|
|
||||||
git_buf trans = {NULL};
|
|
||||||
const char *str;
|
|
||||||
int err;
|
|
||||||
PyObject *py_trans, *tstr;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
|
|
||||||
err = git_refspec_transform(&trans, self->refspec, str);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
Error_set(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_trans = to_unicode(trans.ptr, NULL, NULL);
|
|
||||||
|
|
||||||
git_buf_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)
|
|
||||||
{
|
|
||||||
git_buf trans = {NULL};
|
|
||||||
const char *str;
|
|
||||||
int err;
|
|
||||||
PyObject *py_trans, *tstr;
|
|
||||||
|
|
||||||
str = py_str_borrow_c_str(&tstr, py_str, NULL);
|
|
||||||
|
|
||||||
err = git_refspec_rtransform(&trans, self->refspec, str);
|
|
||||||
Py_DECREF(tstr);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
Error_set(err);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_trans = to_unicode(trans.ptr, NULL, NULL);
|
|
||||||
|
|
||||||
git_buf_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 */
|
|
||||||
};
|
|
@@ -1,38 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_pygit2_refspec_h
|
|
||||||
#define INCLUDE_pygit2_refspec_h
|
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <git2.h>
|
|
||||||
#include <git2/refspec.h>
|
|
||||||
|
|
||||||
Refspec* wrap_refspec(const Remote *owner, const git_refspec *refspec);
|
|
||||||
|
|
||||||
#endif
|
|
728
src/remote.c
728
src/remote.c
@@ -1,728 +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 "oid.h"
|
|
||||||
#include "refspec.h"
|
|
||||||
#include "remote.h"
|
|
||||||
|
|
||||||
|
|
||||||
extern PyObject *GitError;
|
|
||||||
extern PyTypeObject RepositoryType;
|
|
||||||
extern PyTypeObject TransferProgressType;
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
wrap_transfer_progress(const git_transfer_progress *stats)
|
|
||||||
{
|
|
||||||
TransferProgress *py_stats;
|
|
||||||
|
|
||||||
py_stats = PyObject_New(TransferProgress, &TransferProgressType);
|
|
||||||
if (!py_stats)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
py_stats->total_objects = stats->total_objects;
|
|
||||||
py_stats->indexed_objects = stats->indexed_objects;
|
|
||||||
py_stats->received_objects = stats->received_objects;
|
|
||||||
py_stats->local_objects = stats->local_objects;
|
|
||||||
py_stats->total_deltas = stats->total_deltas;
|
|
||||||
py_stats->indexed_deltas = stats->indexed_deltas;
|
|
||||||
py_stats->received_bytes = stats->received_bytes;
|
|
||||||
|
|
||||||
return (PyObject *) py_stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
TransferProgress_dealloc(TransferProgress *self)
|
|
||||||
{
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMemberDef TransferProgress_members[] = {
|
|
||||||
RMEMBER(TransferProgress, total_objects, T_UINT,
|
|
||||||
"Total number objects to download"),
|
|
||||||
RMEMBER(TransferProgress, indexed_objects, T_UINT,
|
|
||||||
"Objects which have been indexed"),
|
|
||||||
RMEMBER(TransferProgress, received_objects, T_UINT,
|
|
||||||
"Objects which have been received up to now"),
|
|
||||||
RMEMBER(TransferProgress, local_objects, T_UINT,
|
|
||||||
"Local objects which were used to fix the thin pack"),
|
|
||||||
RMEMBER(TransferProgress, total_deltas, T_UINT,
|
|
||||||
"Total number of deltas in the pack"),
|
|
||||||
RMEMBER(TransferProgress, indexed_deltas, T_UINT,
|
|
||||||
"Deltas which have been indexed"),
|
|
||||||
/* FIXME: technically this is unsigned, but there's no value for size_t
|
|
||||||
* here. */
|
|
||||||
RMEMBER(TransferProgress, received_bytes, T_PYSSIZET,
|
|
||||||
"Number of bytes received up to now"),
|
|
||||||
{NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
PyDoc_STRVAR(TransferProgress__doc__,
|
|
||||||
"Progress downloading and indexing data during a fetch");
|
|
||||||
|
|
||||||
PyTypeObject TransferProgressType = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"_pygit2.TransferProgress", /* tp_name */
|
|
||||||
sizeof(TransferProgress), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)TransferProgress_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, /* tp_flags */
|
|
||||||
TransferProgress__doc__, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
0, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
0, /* tp_methods */
|
|
||||||
TransferProgress_members, /* tp_members */
|
|
||||||
0, /* 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 */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
|
||||||
progress_cb(const char *str, int len, void *data)
|
|
||||||
{
|
|
||||||
Remote *remote = (Remote *) data;
|
|
||||||
PyObject *arglist, *ret;
|
|
||||||
|
|
||||||
if (remote->progress == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(remote->progress)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "progress callback is not callable");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
arglist = Py_BuildValue("(s#)", str, len);
|
|
||||||
ret = PyObject_CallObject(remote->progress, arglist);
|
|
||||||
Py_DECREF(arglist);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Py_DECREF(ret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
credentials_cb(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, void *data)
|
|
||||||
{
|
|
||||||
Remote *remote = (Remote *) data;
|
|
||||||
|
|
||||||
return callable_to_credentials(out, url, username_from_url, allowed_types, remote->credentials);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
transfer_progress_cb(const git_transfer_progress *stats, void *data)
|
|
||||||
{
|
|
||||||
Remote *remote = (Remote *) data;
|
|
||||||
PyObject *py_stats, *ret;
|
|
||||||
|
|
||||||
if (remote->transfer_progress == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(remote->transfer_progress)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "transfer progress callback is not callable");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
py_stats = wrap_transfer_progress(stats);
|
|
||||||
if (!py_stats)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
ret = PyObject_CallFunctionObjArgs(remote->transfer_progress, py_stats, NULL);
|
|
||||||
Py_DECREF(py_stats);
|
|
||||||
if (!ret)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Py_DECREF(ret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
update_tips_cb(const char *refname, const git_oid *a, const git_oid *b, void *data)
|
|
||||||
{
|
|
||||||
Remote *remote = (Remote *) data;
|
|
||||||
PyObject *ret;
|
|
||||||
PyObject *old, *new;
|
|
||||||
|
|
||||||
if (remote->update_tips == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(remote->update_tips)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "update tips callback is not callable");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
old = git_oid_to_python(a);
|
|
||||||
new = git_oid_to_python(b);
|
|
||||||
|
|
||||||
ret = PyObject_CallFunction(remote->update_tips, "(s,O,O)", refname, old ,new);
|
|
||||||
|
|
||||||
Py_DECREF(old);
|
|
||||||
Py_DECREF(new);
|
|
||||||
|
|
||||||
if (!ret)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
Py_DECREF(ret);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
Remote_dealloc(Remote *self)
|
|
||||||
{
|
|
||||||
Py_CLEAR(self->repo);
|
|
||||||
Py_CLEAR(self->progress);
|
|
||||||
git_remote_free(self->remote);
|
|
||||||
PyObject_Del(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_name__doc__, "Name of the remote refspec");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_name__get__(Remote *self)
|
|
||||||
{
|
|
||||||
return to_unicode(git_remote_name(self->remote), NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Remote_name__set__(Remote *self, PyObject* py_name)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char* name;
|
|
||||||
PyObject *tname;
|
|
||||||
|
|
||||||
name = py_str_borrow_c_str(&tname, py_name, NULL);
|
|
||||||
if (name != NULL) {
|
|
||||||
err = git_remote_rename(self->remote, name, NULL, NULL);
|
|
||||||
Py_DECREF(tname);
|
|
||||||
|
|
||||||
if (err == GIT_OK)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_fetch_refspecs__doc__, "Fetch refspecs");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_fetch_refspecs__get__(Remote *self)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
git_strarray refspecs;
|
|
||||||
PyObject *new_list;
|
|
||||||
|
|
||||||
err = git_remote_get_fetch_refspecs(&refspecs, self->remote);
|
|
||||||
if (err != GIT_OK)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
new_list = get_pylist_from_git_strarray(&refspecs);
|
|
||||||
|
|
||||||
git_strarray_free(&refspecs);
|
|
||||||
return new_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Remote_fetch_refspecs__set__(Remote *self, PyObject *py_list)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
git_strarray fetch_refspecs;
|
|
||||||
|
|
||||||
if (get_strarraygit_from_pylist(&fetch_refspecs, py_list) < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = git_remote_set_fetch_refspecs(self->remote, &fetch_refspecs);
|
|
||||||
git_strarray_free(&fetch_refspecs);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
Error_set(err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_push_refspecs__doc__, "Push refspecs");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_push_refspecs__get__(Remote *self)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
git_strarray refspecs;
|
|
||||||
PyObject *new_list;
|
|
||||||
|
|
||||||
err = git_remote_get_push_refspecs(&refspecs, self->remote);
|
|
||||||
if (err != GIT_OK)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
new_list = get_pylist_from_git_strarray(&refspecs);
|
|
||||||
|
|
||||||
git_strarray_free(&refspecs);
|
|
||||||
return new_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
Remote_push_refspecs__set__(Remote *self, PyObject *py_list)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
git_strarray push_refspecs;
|
|
||||||
|
|
||||||
if (get_strarraygit_from_pylist(&push_refspecs, py_list) != 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = git_remote_set_push_refspecs(self->remote, &push_refspecs);
|
|
||||||
git_strarray_free(&push_refspecs);
|
|
||||||
|
|
||||||
if (err < 0) {
|
|
||||||
Error_set(err);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_url__doc__, "Url of the remote");
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_url__get__(Remote *self)
|
|
||||||
{
|
|
||||||
const char *url;
|
|
||||||
|
|
||||||
url = git_remote_url(self->remote);
|
|
||||||
if (!url)
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
|
|
||||||
return to_unicode(url, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
Remote_url__set__(Remote *self, PyObject* py_url)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char* url = NULL;
|
|
||||||
PyObject *turl;
|
|
||||||
|
|
||||||
url = py_str_borrow_c_str(&turl, py_url, NULL);
|
|
||||||
if (url != NULL) {
|
|
||||||
err = git_remote_set_url(self->remote, url);
|
|
||||||
Py_DECREF(turl);
|
|
||||||
|
|
||||||
if (err == GIT_OK)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_push_url__doc__, "Push url of the remote");
|
|
||||||
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_push_url__get__(Remote *self)
|
|
||||||
{
|
|
||||||
const char *url;
|
|
||||||
|
|
||||||
url = git_remote_pushurl(self->remote);
|
|
||||||
if (!url)
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
|
|
||||||
return to_unicode(url, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
Remote_push_url__set__(Remote *self, PyObject* py_url)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char* url = NULL;
|
|
||||||
PyObject *turl;
|
|
||||||
|
|
||||||
url = py_str_borrow_c_str(&turl, py_url, NULL);
|
|
||||||
if (url != NULL) {
|
|
||||||
err = git_remote_set_pushurl(self->remote, url);
|
|
||||||
Py_DECREF(turl);
|
|
||||||
|
|
||||||
if (err == GIT_OK)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_refspec_count__doc__, "Number of refspecs.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_refspec_count__get__(Remote *self)
|
|
||||||
{
|
|
||||||
size_t count;
|
|
||||||
|
|
||||||
count = git_remote_refspec_count(self->remote);
|
|
||||||
return PyLong_FromSize_t(count);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_get_refspec__doc__,
|
|
||||||
"get_refspec(n) -> (str, str)\n"
|
|
||||||
"\n"
|
|
||||||
"Return the refspec at the given position.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_get_refspec(Remote *self, PyObject *value)
|
|
||||||
{
|
|
||||||
size_t n;
|
|
||||||
const git_refspec *refspec;
|
|
||||||
|
|
||||||
n = PyLong_AsSize_t(value);
|
|
||||||
if (PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
refspec = git_remote_get_refspec(self->remote, n);
|
|
||||||
if (refspec == NULL) {
|
|
||||||
PyErr_SetObject(PyExc_IndexError, value);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (PyObject*) wrap_refspec(self, refspec);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_fetch__doc__,
|
|
||||||
"fetch() -> {'indexed_objects': int, 'received_objects' : int,"
|
|
||||||
" 'received_bytesa' : int}\n"
|
|
||||||
"\n"
|
|
||||||
"Negotiate what objects should be downloaded and download the\n"
|
|
||||||
"packfile with those objects");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_fetch(Remote *self, PyObject *args)
|
|
||||||
{
|
|
||||||
PyObject* py_stats = NULL;
|
|
||||||
const git_transfer_progress *stats;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
PyErr_Clear();
|
|
||||||
err = git_remote_fetch(self->remote, NULL, NULL);
|
|
||||||
/*
|
|
||||||
* XXX: We should be checking for GIT_EUSER, but on v0.20, this does not
|
|
||||||
* make it all the way to us for update_tips
|
|
||||||
*/
|
|
||||||
if (err < 0 && PyErr_Occurred())
|
|
||||||
return NULL;
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
stats = git_remote_stats(self->remote);
|
|
||||||
py_stats = Py_BuildValue("{s:I,s:I,s:n}",
|
|
||||||
"indexed_objects", stats->indexed_objects,
|
|
||||||
"received_objects", stats->received_objects,
|
|
||||||
"received_bytes", stats->received_bytes);
|
|
||||||
|
|
||||||
return (PyObject*) py_stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_save__doc__,
|
|
||||||
"save()\n\n"
|
|
||||||
"Save a remote to its repository configuration.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_save(Remote *self, PyObject *args)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = git_remote_save(self->remote);
|
|
||||||
if (err == GIT_OK) {
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return Error_set(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
push_status_foreach_callback(const char *ref, const char *msg, void *data)
|
|
||||||
{
|
|
||||||
const char **msg_dst = (const char **)data;
|
|
||||||
if (msg != NULL && *msg_dst == NULL)
|
|
||||||
*msg_dst = msg;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_push__doc__,
|
|
||||||
"push(refspec)\n"
|
|
||||||
"\n"
|
|
||||||
"Push the given refspec to the remote. Raises ``GitError`` on error.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_push(Remote *self, PyObject *args)
|
|
||||||
{
|
|
||||||
git_push *push = NULL;
|
|
||||||
const char *refspec = NULL;
|
|
||||||
const char *msg = NULL;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &refspec))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
err = git_push_new(&push, self->remote);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
err = git_push_add_refspec(push, refspec);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
err = git_push_finish(push);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
if (!git_push_unpack_ok(push)) {
|
|
||||||
git_push_free(push);
|
|
||||||
PyErr_SetString(GitError, "Remote failed to unpack objects");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = git_push_status_foreach(push, push_status_foreach_callback, &msg);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
|
||||||
if (msg != NULL) {
|
|
||||||
git_push_free(push);
|
|
||||||
PyErr_SetString(GitError, msg);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = git_push_update_tips(push, NULL, NULL);
|
|
||||||
if (err < 0)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
git_push_free(push);
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
|
|
||||||
error:
|
|
||||||
git_push_free(push);
|
|
||||||
return Error_set(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_add_push__doc__,
|
|
||||||
"add_push(refspec)\n"
|
|
||||||
"\n"
|
|
||||||
"Add a push refspec to the remote.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_add_push(Remote *self, PyObject *args)
|
|
||||||
{
|
|
||||||
git_remote *remote;
|
|
||||||
char *refspec = NULL;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &refspec))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
remote = self->remote;
|
|
||||||
err = git_remote_add_push(remote, refspec);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote_add_fetch__doc__,
|
|
||||||
"add_fetch(refspec)\n"
|
|
||||||
"\n"
|
|
||||||
"Add a fetch refspec to the remote.");
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
Remote_add_fetch(Remote *self, PyObject *args)
|
|
||||||
{
|
|
||||||
git_remote *remote;
|
|
||||||
char *refspec = NULL;
|
|
||||||
int err = 0;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "s", &refspec))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
remote = self->remote;
|
|
||||||
err = git_remote_add_fetch(remote, refspec);
|
|
||||||
if (err < 0)
|
|
||||||
return Error_set(err);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyMethodDef Remote_methods[] = {
|
|
||||||
METHOD(Remote, fetch, METH_NOARGS),
|
|
||||||
METHOD(Remote, save, METH_NOARGS),
|
|
||||||
METHOD(Remote, get_refspec, METH_O),
|
|
||||||
METHOD(Remote, push, METH_VARARGS),
|
|
||||||
METHOD(Remote, add_push, METH_VARARGS),
|
|
||||||
METHOD(Remote, add_fetch, METH_VARARGS),
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyGetSetDef Remote_getseters[] = {
|
|
||||||
GETSET(Remote, name),
|
|
||||||
GETSET(Remote, url),
|
|
||||||
GETSET(Remote, push_url),
|
|
||||||
GETTER(Remote, refspec_count),
|
|
||||||
GETSET(Remote, fetch_refspecs),
|
|
||||||
GETSET(Remote, push_refspecs),
|
|
||||||
{NULL}
|
|
||||||
};
|
|
||||||
|
|
||||||
PyMemberDef Remote_members[] = {
|
|
||||||
MEMBER(Remote, progress, T_OBJECT_EX, "Progress output callback"),
|
|
||||||
MEMBER(Remote, credentials, T_OBJECT_EX,
|
|
||||||
"credentials(url, username_from_url, allowed_types) -> credential\n"
|
|
||||||
"\n"
|
|
||||||
"Credentials callback\n"
|
|
||||||
"\n"
|
|
||||||
"If the remote server requires authentication, this function will\n"
|
|
||||||
"be called and its return value used for authentication.\n"
|
|
||||||
"\n"
|
|
||||||
":param str url: The url of the remote\n"
|
|
||||||
":param username_from_url: Username extracted from the url, if any\n"
|
|
||||||
":type username_from_url: str or None\n"
|
|
||||||
":param int allowed_types: credential types supported by the remote "),
|
|
||||||
MEMBER(Remote, transfer_progress, T_OBJECT_EX, "Transfer progress callback"),
|
|
||||||
MEMBER(Remote, update_tips, T_OBJECT_EX, "update tips callback"),
|
|
||||||
{NULL},
|
|
||||||
};
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Remote__doc__, "Remote object.");
|
|
||||||
|
|
||||||
PyTypeObject RemoteType = {
|
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
|
||||||
"_pygit2.Remote", /* tp_name */
|
|
||||||
sizeof(Remote), /* tp_basicsize */
|
|
||||||
0, /* tp_itemsize */
|
|
||||||
(destructor)Remote_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, /* tp_flags */
|
|
||||||
Remote__doc__, /* tp_doc */
|
|
||||||
0, /* tp_traverse */
|
|
||||||
0, /* tp_clear */
|
|
||||||
0, /* tp_richcompare */
|
|
||||||
0, /* tp_weaklistoffset */
|
|
||||||
0, /* tp_iter */
|
|
||||||
0, /* tp_iternext */
|
|
||||||
Remote_methods, /* tp_methods */
|
|
||||||
Remote_members, /* tp_members */
|
|
||||||
Remote_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 */
|
|
||||||
};
|
|
||||||
|
|
||||||
PyObject *
|
|
||||||
wrap_remote(git_remote *c_remote, Repository *repo)
|
|
||||||
{
|
|
||||||
Remote *py_remote = NULL;
|
|
||||||
git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT;
|
|
||||||
|
|
||||||
py_remote = PyObject_New(Remote, &RemoteType);
|
|
||||||
if (py_remote) {
|
|
||||||
Py_INCREF(repo);
|
|
||||||
py_remote->repo = repo;
|
|
||||||
py_remote->remote = c_remote;
|
|
||||||
py_remote->progress = NULL;
|
|
||||||
py_remote->credentials = NULL;
|
|
||||||
py_remote->transfer_progress = NULL;
|
|
||||||
py_remote->update_tips = NULL;
|
|
||||||
|
|
||||||
callbacks.progress = progress_cb;
|
|
||||||
callbacks.credentials = credentials_cb;
|
|
||||||
callbacks.transfer_progress = transfer_progress_cb;
|
|
||||||
callbacks.update_tips = update_tips_cb;
|
|
||||||
callbacks.payload = py_remote;
|
|
||||||
git_remote_set_callbacks(c_remote, &callbacks);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (PyObject *)py_remote;
|
|
||||||
}
|
|
39
src/remote.h
39
src/remote.h
@@ -1,39 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INCLUDE_pygit2_remote_h
|
|
||||||
#define INCLUDE_pygit2_remote_h
|
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <git2.h>
|
|
||||||
#include <git2/remote.h>
|
|
||||||
|
|
||||||
PyObject* Remote_fetch(Remote *self, PyObject *args);
|
|
||||||
PyObject* wrap_remote(git_remote *c_remote, Repository *repo);
|
|
||||||
|
|
||||||
#endif
|
|
124
src/repository.c
124
src/repository.c
@@ -35,7 +35,6 @@
|
|||||||
#include "oid.h"
|
#include "oid.h"
|
||||||
#include "note.h"
|
#include "note.h"
|
||||||
#include "repository.h"
|
#include "repository.h"
|
||||||
#include "remote.h"
|
|
||||||
#include "branch.h"
|
#include "branch.h"
|
||||||
#include "blame.h"
|
#include "blame.h"
|
||||||
#include "signature.h"
|
#include "signature.h"
|
||||||
@@ -53,7 +52,6 @@ extern PyTypeObject TreeType;
|
|||||||
extern PyTypeObject TreeBuilderType;
|
extern PyTypeObject TreeBuilderType;
|
||||||
extern PyTypeObject ConfigType;
|
extern PyTypeObject ConfigType;
|
||||||
extern PyTypeObject DiffType;
|
extern PyTypeObject DiffType;
|
||||||
extern PyTypeObject RemoteType;
|
|
||||||
extern PyTypeObject ReferenceType;
|
extern PyTypeObject ReferenceType;
|
||||||
extern PyTypeObject NoteType;
|
extern PyTypeObject NoteType;
|
||||||
extern PyTypeObject NoteIterType;
|
extern PyTypeObject NoteIterType;
|
||||||
@@ -514,45 +512,6 @@ Repository_workdir__get__(Repository *self, void *closure)
|
|||||||
return to_path(c_path);
|
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;
|
|
||||||
/* We need 2 refs here. One is returned, one is kept internally. */
|
|
||||||
Py_INCREF(self->config);
|
|
||||||
} else {
|
|
||||||
Py_INCREF(self->config);
|
|
||||||
}
|
|
||||||
|
|
||||||
return self->config;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_merge_base__doc__,
|
PyDoc_STRVAR(Repository_merge_base__doc__,
|
||||||
"merge_base(oid, oid) -> Oid\n"
|
"merge_base(oid, oid) -> Oid\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -948,7 +907,7 @@ PyDoc_STRVAR(Repository_create_branch__doc__,
|
|||||||
"\n"
|
"\n"
|
||||||
"Examples::\n"
|
"Examples::\n"
|
||||||
"\n"
|
"\n"
|
||||||
" repo.create_branch('foo', repo.head.hex, force=False)");
|
" repo.create_branch('foo', repo.head.get_object(), force=False)");
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
Repository_create_branch(Repository *self, PyObject *args)
|
Repository_create_branch(Repository *self, PyObject *args)
|
||||||
@@ -1097,7 +1056,7 @@ Repository_lookup_reference(Repository *self, PyObject *py_name)
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_create_reference_direct__doc__,
|
PyDoc_STRVAR(Repository_create_reference_direct__doc__,
|
||||||
"git_reference_create(name, target, force) -> Reference\n"
|
"create_reference_direct(name, target, force) -> Reference\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Create a new reference \"name\" which points to an object.\n"
|
"Create a new reference \"name\" which points to an object.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1109,7 +1068,7 @@ PyDoc_STRVAR(Repository_create_reference_direct__doc__,
|
|||||||
"\n"
|
"\n"
|
||||||
"Examples::\n"
|
"Examples::\n"
|
||||||
"\n"
|
"\n"
|
||||||
" repo.git_reference_create('refs/heads/foo', repo.head.hex, False)");
|
" repo.create_reference_direct('refs/heads/foo', repo.head.target, False)");
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
Repository_create_reference_direct(Repository *self, PyObject *args,
|
Repository_create_reference_direct(Repository *self, PyObject *args,
|
||||||
@@ -1136,7 +1095,7 @@ Repository_create_reference_direct(Repository *self, PyObject *args,
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_create_reference_symbolic__doc__,
|
PyDoc_STRVAR(Repository_create_reference_symbolic__doc__,
|
||||||
"git_reference_symbolic_create(name, source, force) -> Reference\n"
|
"create_reference_symbolic(name, source, force) -> Reference\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Create a new reference \"name\" which points to another reference.\n"
|
"Create a new reference \"name\" which points to another reference.\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1148,7 +1107,7 @@ PyDoc_STRVAR(Repository_create_reference_symbolic__doc__,
|
|||||||
"\n"
|
"\n"
|
||||||
"Examples::\n"
|
"Examples::\n"
|
||||||
"\n"
|
"\n"
|
||||||
" repo.git_reference_symbolic_create('refs/tags/foo', 'refs/heads/master', False)");
|
" repo.create_reference_symbolic('refs/tags/foo', 'refs/heads/master', False)");
|
||||||
|
|
||||||
PyObject *
|
PyObject *
|
||||||
Repository_create_reference_symbolic(Repository *self, PyObject *args,
|
Repository_create_reference_symbolic(Repository *self, PyObject *args,
|
||||||
@@ -1309,67 +1268,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 *
|
||||||
@@ -1384,6 +1282,14 @@ 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)
|
||||||
|
{
|
||||||
|
/* Bytes means a raw buffer */
|
||||||
|
return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *));
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Repository_checkout_head__doc__,
|
PyDoc_STRVAR(Repository_checkout_head__doc__,
|
||||||
"checkout_head(strategy)\n"
|
"checkout_head(strategy)\n"
|
||||||
"\n"
|
"\n"
|
||||||
@@ -1666,7 +1572,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),
|
||||||
@@ -1690,10 +1595,9 @@ PyGetSetDef Repository_getseters[] = {
|
|||||||
GETTER(Repository, head_is_unborn),
|
GETTER(Repository, head_is_unborn),
|
||||||
GETTER(Repository, is_empty),
|
GETTER(Repository, is_empty),
|
||||||
GETTER(Repository, is_bare),
|
GETTER(Repository, is_bare),
|
||||||
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}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -94,6 +94,13 @@ Signature_dealloc(Signature *self)
|
|||||||
PyObject_Del(self);
|
PyObject_Del(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyDoc_STRVAR(Signature__pointer__doc__, "Get the signature's pointer. For internal use only.");
|
||||||
|
PyObject *
|
||||||
|
Signature__pointer__get__(Repository *self)
|
||||||
|
{
|
||||||
|
/* Bytes means a raw buffer */
|
||||||
|
return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *));
|
||||||
|
}
|
||||||
|
|
||||||
PyDoc_STRVAR(Signature__encoding__doc__, "Encoding.");
|
PyDoc_STRVAR(Signature__encoding__doc__, "Encoding.");
|
||||||
|
|
||||||
@@ -171,6 +178,7 @@ PyGetSetDef Signature_getseters[] = {
|
|||||||
GETTER(Signature, email),
|
GETTER(Signature, email),
|
||||||
GETTER(Signature, time),
|
GETTER(Signature, time),
|
||||||
GETTER(Signature, offset),
|
GETTER(Signature, offset),
|
||||||
|
GETTER(Signature, _pointer),
|
||||||
{NULL}
|
{NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
49
src/types.h
49
src/types.h
@@ -32,6 +32,10 @@
|
|||||||
#include <Python.h>
|
#include <Python.h>
|
||||||
#include <git2.h>
|
#include <git2.h>
|
||||||
|
|
||||||
|
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 20)
|
||||||
|
#error You need a compatible libgit2 version (v0.20.x)
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Python objects
|
* Python objects
|
||||||
*
|
*
|
||||||
@@ -70,19 +74,6 @@ SIMPLE_TYPE(Tree, git_tree, tree)
|
|||||||
SIMPLE_TYPE(Blob, git_blob, blob)
|
SIMPLE_TYPE(Blob, git_blob, blob)
|
||||||
SIMPLE_TYPE(Tag, git_tag, tag)
|
SIMPLE_TYPE(Tag, git_tag, tag)
|
||||||
|
|
||||||
|
|
||||||
/* git_config */
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
git_config* config;
|
|
||||||
} Config;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
Config *owner;
|
|
||||||
git_config_iterator *iter;
|
|
||||||
} ConfigIter;
|
|
||||||
|
|
||||||
/* git_note */
|
/* git_note */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
PyObject_HEAD
|
PyObject_HEAD
|
||||||
@@ -194,38 +185,6 @@ typedef struct {
|
|||||||
char *encoding;
|
char *encoding;
|
||||||
} Signature;
|
} Signature;
|
||||||
|
|
||||||
|
|
||||||
/* git_remote */
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
Repository *repo;
|
|
||||||
git_remote *remote;
|
|
||||||
/* Callbacks for network events */
|
|
||||||
PyObject *progress;
|
|
||||||
PyObject *credentials;
|
|
||||||
PyObject *transfer_progress;
|
|
||||||
PyObject *update_tips;
|
|
||||||
} Remote;
|
|
||||||
|
|
||||||
/* git_refspec */
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
const Remote *owner;
|
|
||||||
const git_refspec *refspec;
|
|
||||||
} Refspec;
|
|
||||||
|
|
||||||
/* git_transfer_progress */
|
|
||||||
typedef struct {
|
|
||||||
PyObject_HEAD
|
|
||||||
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;
|
|
||||||
} TransferProgress;
|
|
||||||
|
|
||||||
/* git_blame */
|
/* git_blame */
|
||||||
SIMPLE_TYPE(Blame, git_blame, blame)
|
SIMPLE_TYPE(Blame, git_blame, blame)
|
||||||
|
|
||||||
|
89
src/utils.c
89
src/utils.c
@@ -153,92 +153,3 @@ on_error:
|
|||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
|
||||||
py_cred_to_git_cred(git_cred **out, PyObject *py_cred, unsigned int allowed)
|
|
||||||
{
|
|
||||||
PyObject *py_type, *py_tuple;
|
|
||||||
long type;
|
|
||||||
int err = -1;
|
|
||||||
|
|
||||||
py_type = PyObject_GetAttrString(py_cred, "credential_type");
|
|
||||||
py_tuple = PyObject_GetAttrString(py_cred, "credential_tuple");
|
|
||||||
|
|
||||||
if (!py_type || !py_tuple) {
|
|
||||||
printf("py_type %p, py_tuple %p\n", py_type, py_tuple);
|
|
||||||
PyErr_SetString(PyExc_TypeError, "credential doesn't implement the interface");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!PyLong_Check(py_type)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "credential type is not a long");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
type = PyLong_AsLong(py_type);
|
|
||||||
|
|
||||||
/* Sanity check, make sure we're given credentials we can use */
|
|
||||||
if (!(allowed & type)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "invalid credential type");
|
|
||||||
goto cleanup;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (type) {
|
|
||||||
case GIT_CREDTYPE_USERPASS_PLAINTEXT:
|
|
||||||
{
|
|
||||||
const char *username, *password;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(py_tuple, "ss", &username, &password))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
err = git_cred_userpass_plaintext_new(out, username, password);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GIT_CREDTYPE_SSH_KEY:
|
|
||||||
{
|
|
||||||
const char *username, *pubkey, *privkey, *passphrase;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(py_tuple, "ssss", &username, &pubkey, &privkey, &passphrase))
|
|
||||||
goto cleanup;
|
|
||||||
|
|
||||||
err = git_cred_ssh_key_new(out, username, pubkey, privkey, passphrase);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
PyErr_SetString(PyExc_TypeError, "unsupported credential type");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
cleanup:
|
|
||||||
Py_XDECREF(py_type);
|
|
||||||
Py_XDECREF(py_tuple);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
callable_to_credentials(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, PyObject *credentials)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
PyObject *py_cred = NULL, *arglist = NULL;
|
|
||||||
|
|
||||||
if (credentials == NULL || credentials == Py_None)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (!PyCallable_Check(credentials)) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "credentials callback is not callable");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
arglist = Py_BuildValue("(szI)", url, username_from_url, allowed_types);
|
|
||||||
py_cred = PyObject_CallObject(credentials, arglist);
|
|
||||||
Py_DECREF(arglist);
|
|
||||||
|
|
||||||
if (!py_cred)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
err = py_cred_to_git_cred(out, py_cred, allowed_types);
|
|
||||||
Py_DECREF(py_cred);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
#undef PyLong_Check
|
#undef PyLong_Check
|
||||||
#define PyLong_Check PyInt_Check
|
#define PyLong_Check PyInt_Check
|
||||||
#define PyLong_FromLong PyInt_FromLong
|
#define PyLong_FromLong PyInt_FromLong
|
||||||
|
#define PyInteger_Type PyInt_Type
|
||||||
#define PyBytes_AS_STRING PyString_AS_STRING
|
#define PyBytes_AS_STRING PyString_AS_STRING
|
||||||
#define PyBytes_AsString PyString_AsString
|
#define PyBytes_AsString PyString_AsString
|
||||||
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
|
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
|
||||||
@@ -57,6 +58,7 @@
|
|||||||
#define to_path(x) to_bytes(x)
|
#define to_path(x) to_bytes(x)
|
||||||
#define to_encoding(x) to_bytes(x)
|
#define to_encoding(x) to_bytes(x)
|
||||||
#else
|
#else
|
||||||
|
#define PyInteger_Type PyLong_Type
|
||||||
#define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict")
|
#define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict")
|
||||||
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
|
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
|
||||||
#endif
|
#endif
|
||||||
@@ -117,8 +119,6 @@ const char *py_str_borrow_c_str(PyObject **tvaue, PyObject *value, const char *e
|
|||||||
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
|
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
|
||||||
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
|
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
|
||||||
|
|
||||||
int callable_to_credentials(git_cred **out, const char *url, const char *username_from_url, unsigned int allowed_types, PyObject *credentials);
|
|
||||||
|
|
||||||
#define py_path_to_c_str(py_path) \
|
#define py_path_to_c_str(py_path) \
|
||||||
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
||||||
|
|
||||||
|
@@ -74,6 +74,13 @@ class BlobTest(utils.RepoTestCase):
|
|||||||
self.assertEqual(BLOB_NEW_CONTENT, blob.data)
|
self.assertEqual(BLOB_NEW_CONTENT, blob.data)
|
||||||
self.assertEqual(len(BLOB_NEW_CONTENT), blob.size)
|
self.assertEqual(len(BLOB_NEW_CONTENT), blob.size)
|
||||||
self.assertEqual(BLOB_NEW_CONTENT, blob.read_raw())
|
self.assertEqual(BLOB_NEW_CONTENT, blob.read_raw())
|
||||||
|
blob_buffer = memoryview(blob)
|
||||||
|
self.assertEqual(len(BLOB_NEW_CONTENT), len(blob_buffer))
|
||||||
|
self.assertEqual(BLOB_NEW_CONTENT, blob_buffer)
|
||||||
|
def set_content():
|
||||||
|
blob_buffer[:2] = b'hi'
|
||||||
|
|
||||||
|
self.assertRaises(TypeError, set_content)
|
||||||
|
|
||||||
def test_create_blob_fromworkdir(self):
|
def test_create_blob_fromworkdir(self):
|
||||||
|
|
||||||
|
@@ -74,7 +74,7 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
|
|
||||||
config_read = Config(CONFIG_FILENAME)
|
config_read = Config(CONFIG_FILENAME)
|
||||||
self.assertTrue('core.bare' in config_read)
|
self.assertTrue('core.bare' in config_read)
|
||||||
self.assertFalse(config_read['core.bare'])
|
self.assertFalse(config_read.get_bool('core.bare'))
|
||||||
self.assertTrue('core.editor' in config_read)
|
self.assertTrue('core.editor' in config_read)
|
||||||
self.assertEqual(config_read['core.editor'], 'ed')
|
self.assertEqual(config_read['core.editor'], 'ed')
|
||||||
|
|
||||||
@@ -88,9 +88,9 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
|
|
||||||
config.add_file(CONFIG_FILENAME, 0)
|
config.add_file(CONFIG_FILENAME, 0)
|
||||||
self.assertTrue('this.that' in config)
|
self.assertTrue('this.that' in config)
|
||||||
self.assertTrue(config['this.that'])
|
self.assertTrue(config.get_bool('this.that'))
|
||||||
self.assertTrue('something.other.here' in config)
|
self.assertTrue('something.other.here' in config)
|
||||||
self.assertFalse(config['something.other.here'])
|
self.assertFalse(config.get_bool('something.other.here'))
|
||||||
|
|
||||||
def test_read(self):
|
def test_read(self):
|
||||||
config = self.repo.config
|
config = self.repo.config
|
||||||
@@ -103,11 +103,11 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
lambda: config['abc.def'])
|
lambda: config['abc.def'])
|
||||||
|
|
||||||
self.assertTrue('core.bare' in config)
|
self.assertTrue('core.bare' in config)
|
||||||
self.assertFalse(config['core.bare'])
|
self.assertFalse(config.get_bool('core.bare'))
|
||||||
self.assertTrue('core.editor' in config)
|
self.assertTrue('core.editor' in config)
|
||||||
self.assertEqual(config['core.editor'], 'ed')
|
self.assertEqual(config['core.editor'], 'ed')
|
||||||
self.assertTrue('core.repositoryformatversion' in config)
|
self.assertTrue('core.repositoryformatversion' in config)
|
||||||
self.assertEqual(config['core.repositoryformatversion'], 0)
|
self.assertEqual(config.get_int('core.repositoryformatversion'), 0)
|
||||||
|
|
||||||
new_file = open(CONFIG_FILENAME, "w")
|
new_file = open(CONFIG_FILENAME, "w")
|
||||||
new_file.write("[this]\n\tthat = foobar\n\tthat = foobeer\n")
|
new_file.write("[this]\n\tthat = foobar\n\tthat = foobeer\n")
|
||||||
@@ -115,9 +115,10 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
|
|
||||||
config.add_file(CONFIG_FILENAME, 0)
|
config.add_file(CONFIG_FILENAME, 0)
|
||||||
self.assertTrue('this.that' in config)
|
self.assertTrue('this.that' in config)
|
||||||
self.assertEqual(len(config.get_multivar('this.that')), 2)
|
|
||||||
l = config.get_multivar('this.that', 'bar')
|
self.assertEqual(2, len(list(config.get_multivar('this.that'))))
|
||||||
self.assertEqual(len(l), 1)
|
l = list(config.get_multivar('this.that', 'bar'))
|
||||||
|
self.assertEqual(1, len(l))
|
||||||
self.assertEqual(l[0], 'foobar')
|
self.assertEqual(l[0], 'foobar')
|
||||||
|
|
||||||
def test_write(self):
|
def test_write(self):
|
||||||
@@ -129,7 +130,7 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
self.assertFalse('core.dummy1' in config)
|
self.assertFalse('core.dummy1' in config)
|
||||||
config['core.dummy1'] = 42
|
config['core.dummy1'] = 42
|
||||||
self.assertTrue('core.dummy1' in config)
|
self.assertTrue('core.dummy1' in config)
|
||||||
self.assertEqual(config['core.dummy1'], 42)
|
self.assertEqual(config.get_int('core.dummy1'), 42)
|
||||||
|
|
||||||
self.assertFalse('core.dummy2' in config)
|
self.assertFalse('core.dummy2' in config)
|
||||||
config['core.dummy2'] = 'foobar'
|
config['core.dummy2'] = 'foobar'
|
||||||
@@ -155,16 +156,16 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
config.add_file(CONFIG_FILENAME, 5)
|
config.add_file(CONFIG_FILENAME, 5)
|
||||||
self.assertTrue('this.that' in config)
|
self.assertTrue('this.that' in config)
|
||||||
l = config.get_multivar('this.that', 'foo.*')
|
l = config.get_multivar('this.that', 'foo.*')
|
||||||
self.assertEqual(len(l), 2)
|
self.assertEqual(2, len(list(l)))
|
||||||
|
|
||||||
config.set_multivar('this.that', '^.*beer', 'fool')
|
config.set_multivar('this.that', '^.*beer', 'fool')
|
||||||
l = config.get_multivar('this.that', 'fool')
|
l = list(config.get_multivar('this.that', 'fool'))
|
||||||
self.assertEqual(len(l), 1)
|
self.assertEqual(len(l), 1)
|
||||||
self.assertEqual(l[0], 'fool')
|
self.assertEqual(l[0], 'fool')
|
||||||
|
|
||||||
config.set_multivar('this.that', 'foo.*', 'foo-123456')
|
config.set_multivar('this.that', 'foo.*', 'foo-123456')
|
||||||
l = config.get_multivar('this.that', 'foo.*')
|
l = config.get_multivar('this.that', 'foo.*')
|
||||||
self.assertEqual(len(l), 2)
|
self.assertEqual(2, len(list(l)))
|
||||||
for i in l:
|
for i in l:
|
||||||
self.assertEqual(i, 'foo-123456')
|
self.assertEqual(i, 'foo-123456')
|
||||||
|
|
||||||
@@ -178,5 +179,12 @@ class ConfigTest(utils.RepoTestCase):
|
|||||||
self.assertTrue('core.bare' in lst)
|
self.assertTrue('core.bare' in lst)
|
||||||
self.assertTrue(lst['core.bare'])
|
self.assertTrue(lst['core.bare'])
|
||||||
|
|
||||||
|
def test_parsing(self):
|
||||||
|
self.assertTrue(Config.parse_bool("on"))
|
||||||
|
self.assertTrue(Config.parse_bool("1"))
|
||||||
|
|
||||||
|
self.assertEqual(5, Config.parse_int("5"))
|
||||||
|
self.assertEqual(1024, Config.parse_int("1k"))
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
@@ -65,6 +65,7 @@ class RepositoryTest(utils.RepoTestCase):
|
|||||||
self.assertEqual('new', remote.name)
|
self.assertEqual('new', remote.name)
|
||||||
|
|
||||||
self.assertRaisesAssign(ValueError, remote, 'name', '')
|
self.assertRaisesAssign(ValueError, remote, 'name', '')
|
||||||
|
self.assertRaisesAssign(ValueError, remote, 'name', None)
|
||||||
|
|
||||||
|
|
||||||
def test_remote_set_url(self):
|
def test_remote_set_url(self):
|
||||||
@@ -189,9 +190,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 +202,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