Skip to content

Commit e0e89bc

Browse files
committed
Squashed commit of the following:
commit f618e30b21401aca34f77c7b7e05c710528697ae Author: CJ Harries <[email protected]> Date: Sun Mar 18 08:23:37 2018 -0500 Pass decoded value via valua and raw value via raw_value commit 5a4203b Merge: 8ca94fc 0c1f2d8 Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:08:12 2018 -0500 Merge branch 'feature/update-docs' into feature/return-config-entry-from-iter commit 0c1f2d8 Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:06:51 2018 -0500 Add ConfigEntry docs commit 67701ed Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:05:59 2018 -0500 Update __iter__ docs commit cdd9566 Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:04:24 2018 -0500 Document properties commit 8f74752 Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:02:51 2018 -0500 Document decode_as_string commit f938b49 Author: CJ Harries <[email protected]> Date: Fri Mar 16 21:01:59 2018 -0500 Document _from_c commit 8ca94fc Merge: 835e711 52de16a Author: CJ Harries <[email protected]> Date: Fri Mar 16 20:15:49 2018 -0500 Merge branch 'feature/iterate-over-config-entries' into feature/return-config-entry-from-iter commit 52de16a Author: CJ Harries <[email protected]> Date: Fri Mar 16 20:15:08 2018 -0500 Update test_iterator to consume ConfigEntr[ies] commit e7798bb Author: CJ Harries <[email protected]> Date: Fri Mar 16 20:03:39 2018 -0500 Return entry, a ConfigEntry from ConfigIterator.__next__ commit 835e711 Merge: bbcb464 55604ca Author: CJ Harries <[email protected]> Date: Fri Mar 16 20:02:45 2018 -0500 Merge branch 'feature/decode-name' into feature/return-config-entry-from-iter commit 55604ca Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:57:25 2018 -0500 Return properly decoded entry.name commit 44326fa Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:57:06 2018 -0500 Decode ConfigEntry name without prompting commit bbcb464 Merge: 74544d6 1c47ece Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:56:29 2018 -0500 Merge branch 'feature/decode-value' into feature/return-config-entry-from-iter commit 1c47ece Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:54:45 2018 -0500 Return entry.value_string from __getitem__ commit cb873be Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:52:14 2018 -0500 Return entry.value_string from ConfigMultivarIterator commit 2e14065 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:51:53 2018 -0500 Add value_string property, decode_as_string(entry.value) commit 9d10675 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:51:13 2018 -0500 Add decode_as_string method commit 74544d6 Merge: 3d76e44 ae6eead Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:28:08 2018 -0500 Merge branch 'feature/expose-entry-properties' into feature/return-config-entry-from-iter commit ae6eead Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:26:07 2018 -0500 Return simplified name from __next__ commit 6ca5789 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:25:11 2018 -0500 Add name property commit c9fdd27 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:24:47 2018 -0500 Add level property commit 3d76e44 Merge: 0f64ac4 f471b6d Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:23:54 2018 -0500 Merge branch 'feature/return-config-entry-name-from-iter' into feature/return-config-entry-from-iter commit f471b6d Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:20:30 2018 -0500 Expose the proper name (entry._entry.name) commit 6ef0abb Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:20:17 2018 -0500 Return a ConfigEntry from _next_entry commit f48d0d8 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:19:27 2018 -0500 Only free the entry if it did not come from an iterator commit df0e8b6 Author: CJ Harries <[email protected]> Date: Fri Mar 16 19:19:00 2018 -0500 Add from_iterator creation flag commit 0f64ac4 Author: J. David Ibáñez <[email protected]> Date: Sat Mar 10 17:04:14 2018 +0100 Fix segfault when calling repr(repo) before init Fixes #775 commit 2d4c1f5 Author: Brandon Milton <[email protected]> Date: Mon Mar 5 09:18:43 2018 -0800 Remove Repository.parse_diff, remove repo check from Diff.merge commit 711e9eb Author: Brandon Milton <[email protected]> Date: Sat Mar 3 11:14:40 2018 -0800 Add static Diff.parse_diff commit f1e9c3b Merge: e2eaa46 fefd09e Author: J. David Ibáñez <[email protected]> Date: Sat Mar 3 14:29:53 2018 +0100 Merge remote-tracking branch 'ZenSecurity/master' commit fefd09e Author: Mikhail Yushkovskiy <[email protected]> Date: Sat Mar 3 14:09:32 2018 +0300 Add my name, for the fame commit e2eaa46 Author: J. David Ibáñez <[email protected]> Date: Sat Mar 3 10:52:45 2018 +0100 Fix compile warning
1 parent 9534ae8 commit e0e89bc

File tree

10 files changed

+120
-87
lines changed

10 files changed

+120
-87
lines changed

.mailmap

+1
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,4 @@ Vlad Temian <[email protected]>
2525
Xavier Delannoy <[email protected]>
2626
2727
28+
Mikhail Yushkovskiy <[email protected]>

README.rst

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ How to install
2828
Authors
2929
==============
3030

31-
125 developers have contributed at least 1 commit to pygit2::
31+
126 developers have contributed at least 1 commit to pygit2::
3232

3333
J. David Ibáñez Carlos Martín Nieto Nico von Geyso
3434
W. Trevor King Dave Borowitz Matthias Bartelmeß
@@ -71,7 +71,7 @@ Authors
7171
Peter Dave Hello Philippe Ombredanne Ridge Kennedy
7272
Ross Nicoll Rui Abreu Ferreira Sheeo
7373
Soasme Vladimir Rutsky Yu Jianjian
74-
chengyuhang earl
74+
chengyuhang earl Mikhail Yushkovskiy
7575

7676

7777
License

docs/config.rst

+12-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ The Config type
1717
.. method:: Config.__iter__()
1818

1919
The :class:`Config` class has an iterator which can be used to loop
20-
through all the entries in the configuration. Each element is a tuple
21-
containing the name and the value of each configuration variable. Be
20+
through all the entries in the configuration. Each element is a ``ConfigEntry`` object containing the name, level, and value of each configuration variable. Be
2221
aware that this may return multiple versions of each entry if they are
2322
set multiple times in the configuration files.
2423

@@ -32,3 +31,14 @@ string. In order to apply the git-config parsing rules, you can use
3231

3332
.. automethod:: pygit2.Config.get_bool
3433
.. automethod:: pygit2.Config.get_int
34+
35+
36+
The ConfigEntry type
37+
====================
38+
39+
.. automethod:: pygit2.ConfigEntry.decode_as_string
40+
.. automethod:: pygit2.ConfigEntry._from_c
41+
.. automethod:: pygit2.ConfigEntry.name
42+
.. automethod:: pygit2.ConfigEntry.level
43+
.. automethod:: pygit2.ConfigEntry.value
44+
.. automethod:: pygit2.ConfigEntry.value_string

pygit2/config.py

+40-8
Original file line numberDiff line numberDiff line change
@@ -56,20 +56,20 @@ def _next_entry(self):
5656
err = C.git_config_next(centry, self._iter)
5757
check_error(err)
5858

59-
return centry[0]
59+
return ConfigEntry._from_c(centry[0], True)
6060

6161
def next(self):
6262
return self.__next__()
6363

6464
def __next__(self):
6565
entry = self._next_entry()
66-
return ffi.string(entry.name).decode('utf-8')
66+
return entry
6767

6868

6969
class ConfigMultivarIterator(ConfigIterator):
7070
def __next__(self):
7171
entry = self._next_entry()
72-
return ffi.string(entry.value).decode('utf-8')
72+
return entry.value
7373

7474

7575
class Config(object):
@@ -128,7 +128,7 @@ def __contains__(self, key):
128128
def __getitem__(self, key):
129129
entry = self._get_entry(key)
130130

131-
return ffi.string(entry.value).decode('utf-8')
131+
return entry.value
132132

133133
def __setitem__(self, key, value):
134134
assert_string(key, "key")
@@ -195,7 +195,7 @@ def get_bool(self, key):
195195

196196
entry = self._get_entry(key)
197197
res = ffi.new('int *')
198-
err = C.git_config_parse_bool(res, entry.value)
198+
err = C.git_config_parse_bool(res, entry.raw_value)
199199
check_error(err)
200200

201201
return res[0] != 0
@@ -210,7 +210,7 @@ def get_int(self, key):
210210

211211
entry = self._get_entry(key)
212212
res = ffi.new('int64_t *')
213-
err = C.git_config_parse_int64(res, entry.value)
213+
err = C.git_config_parse_int64(res, entry.raw_value)
214214
check_error(err)
215215

216216
return res[0]
@@ -291,14 +291,46 @@ class ConfigEntry(object):
291291
"""
292292

293293
@classmethod
294-
def _from_c(cls, ptr):
294+
def _from_c(cls, ptr, from_iterator=False):
295+
"""Builds the entry from a ``git_config_entry`` pointer. ``from_iterator``
296+
should be ``True`` when the entry was created during ``git_config_iterator``
297+
actions
298+
"""
295299
entry = cls.__new__(cls)
296300
entry._entry = ptr
301+
entry.from_iterator = from_iterator
297302
return entry
298303

299304
def __del__(self):
300-
C.git_config_entry_free(self._entry)
305+
if not self.from_iterator:
306+
C.git_config_entry_free(self._entry)
301307

302308
@property
303309
def value(self):
310+
"""The entry's value as a string
311+
"""
312+
return self.decode_as_string(self._entry.value)
313+
314+
@property
315+
def level(self):
316+
"""The entry's ``git_config_level_t`` value
317+
"""
318+
return self._entry.level
319+
320+
@property
321+
def name(self):
322+
"""The entry's name
323+
"""
324+
return self.decode_as_string(self._entry.name)
325+
326+
@property
327+
def raw_value(self):
328+
"""The raw ``cData`` entry value
329+
"""
304330
return self._entry.value
331+
332+
@staticmethod
333+
def decode_as_string(value):
334+
"""Returns ``value`` as a decoded ``utf-8`` string.
335+
"""
336+
return ffi.string(value).decode('utf-8')

src/commit.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ Commit_gpg_signature__get__(Commit *commit)
7373
git_buf gpg_signature = { NULL }, signed_data = { NULL };
7474
PyObject *py_gpg_signature, *py_signed_data;
7575

76-
git_oid *oid = git_commit_id(commit->commit);
76+
const git_oid *oid = git_commit_id(commit->commit);
7777
int err = git_commit_extract_signature(
78-
&gpg_signature, &signed_data, commit->repo->repo, oid, NULL
78+
&gpg_signature, &signed_data, commit->repo->repo, (git_oid*) oid, NULL
7979
);
8080

8181
if (err != GIT_OK){

src/diff.c

+29-4
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ wrap_diff(git_diff *diff, Repository *repo)
5454

5555
py_diff = PyObject_New(Diff, &DiffType);
5656
if (py_diff) {
57-
Py_INCREF(repo);
57+
Py_XINCREF(repo);
5858
py_diff->repo = repo;
5959
py_diff->diff = diff;
6060
}
@@ -831,9 +831,6 @@ Diff_merge(Diff *self, PyObject *args)
831831
if (!PyArg_ParseTuple(args, "O!", &DiffType, &py_diff))
832832
return NULL;
833833

834-
if (py_diff->repo->repo != self->repo->repo)
835-
return Error_set(GIT_ERROR);
836-
837834
err = git_diff_merge(self->diff, py_diff->diff);
838835
if (err < 0)
839836
return Error_set(err);
@@ -901,6 +898,32 @@ Diff_stats__get__(Diff *self)
901898
return wrap_diff_stats(self->diff);
902899
}
903900

901+
PyDoc_STRVAR(Diff_parse_diff__doc__,
902+
"parse_diff(git_diff: str) -> Diff\n"
903+
"\n"
904+
"Parses a git unified diff into a diff object without a repository");
905+
906+
static PyObject *
907+
Diff_parse_diff(PyObject *self, PyObject *args)
908+
{
909+
/* A wrapper around
910+
* git_diff_from_buffer
911+
*/
912+
git_diff *diff;
913+
const char *content = NULL;
914+
Py_ssize_t content_len;
915+
int err;
916+
917+
if (!PyArg_ParseTuple(args, "s#", &content, &content_len))
918+
return NULL;
919+
920+
err = git_diff_from_buffer(&diff, content, content_len);
921+
if (err < 0)
922+
return Error_set(err);
923+
924+
return wrap_diff(diff, NULL);
925+
}
926+
904927
static void
905928
Diff_dealloc(Diff *self)
906929
{
@@ -926,6 +949,8 @@ static PyMethodDef Diff_methods[] = {
926949
METHOD(Diff, merge, METH_VARARGS),
927950
METHOD(Diff, find_similar, METH_VARARGS | METH_KEYWORDS),
928951
METHOD(Diff, from_c, METH_STATIC | METH_VARARGS),
952+
{"parse_diff", (PyCFunction) Diff_parse_diff,
953+
METH_VARARGS | METH_STATIC, Diff_parse_diff__doc__},
929954
{NULL}
930955
};
931956

src/repository.c

+3-27
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,9 @@ PyDoc_STRVAR(Repository_path__doc__,
519519
PyObject *
520520
Repository_path__get__(Repository *self, void *closure)
521521
{
522+
if (self->repo == NULL)
523+
Py_RETURN_NONE;
524+
522525
return to_path(git_repository_path(self->repo));
523526
}
524527

@@ -1465,32 +1468,6 @@ Repository_create_reference_symbolic(Repository *self, PyObject *args,
14651468
return wrap_reference(c_reference, self);
14661469
}
14671470

1468-
PyDoc_STRVAR(Repository_parse_diff__doc__,
1469-
"parse_diff(git_diff: str) -> Diff\n"
1470-
"\n"
1471-
"Parses a git unified diff into a diff object applied to the repository");
1472-
1473-
PyObject *
1474-
Repository_parse_diff(PyObject *self, PyObject *args)
1475-
{
1476-
/* A wrapper around
1477-
* git_diff_from_buffer
1478-
*/
1479-
git_diff *diff;
1480-
const char *content = NULL;
1481-
Py_ssize_t content_len;
1482-
int err;
1483-
1484-
if (!PyArg_ParseTuple(args, "s#", &content, &content_len))
1485-
return NULL;
1486-
1487-
err = git_diff_from_buffer(&diff, content, content_len);
1488-
if (err < 0)
1489-
return Error_set(err);
1490-
1491-
return wrap_diff(diff, (Repository *) self);
1492-
}
1493-
14941471
PyDoc_STRVAR(Repository_status__doc__,
14951472
"status() -> {str: int}\n"
14961473
"\n"
@@ -1839,7 +1816,6 @@ PyMethodDef Repository_methods[] = {
18391816
METHOD(Repository, init_submodules, METH_VARARGS | METH_KEYWORDS),
18401817
METHOD(Repository, lookup_reference, METH_O),
18411818
METHOD(Repository, revparse_single, METH_O),
1842-
METHOD(Repository, parse_diff, METH_VARARGS),
18431819
METHOD(Repository, status, METH_NOARGS),
18441820
METHOD(Repository, status_file, METH_O),
18451821
METHOD(Repository, notes, METH_VARARGS),

test/test_config.py

+3-2
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,9 @@ def test_iterator(self):
173173
config = self.repo.config
174174
lst = {}
175175

176-
for name in config:
177-
lst[name] = config[name]
176+
for entry in config:
177+
self.assertGreater(entry.level, -1)
178+
lst[entry.name] = entry.value
178179

179180
self.assertTrue('core.bare' in lst)
180181
self.assertTrue(lst['core.bare'])

test/test_diff.py

+28
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
from __future__ import absolute_import
3131
from __future__ import unicode_literals
32+
import textwrap
3233
import unittest
3334
import pygit2
3435
from pygit2 import GIT_DIFF_INCLUDE_UNMODIFIED
@@ -343,6 +344,33 @@ def test_deltas(self):
343344
# As explained in the libgit2 documentation, flags are not set
344345
#self.assertEqual(delta.flags, patch_delta.flags)
345346

347+
def test_diff_parse(self):
348+
diff = pygit2.Diff.parse_diff(PATCH)
349+
350+
stats = diff.stats
351+
self.assertEqual(2, stats.deletions)
352+
self.assertEqual(1, stats.insertions)
353+
self.assertEqual(2, stats.files_changed)
354+
355+
deltas = list(diff.deltas)
356+
self.assertEqual(2, len(deltas))
357+
358+
def test_parse_diff_null(self):
359+
with self.assertRaises(Exception):
360+
self.repo.parse_diff(None)
361+
362+
def test_parse_diff_bad(self):
363+
diff = textwrap.dedent(
364+
"""
365+
diff --git a/file1 b/file1
366+
old mode 0644
367+
new mode 0644
368+
@@ -1,1 +1,1 @@
369+
-Hi!
370+
""")
371+
with self.assertRaises(Exception):
372+
self.repo.parse_diff(diff)
373+
346374

347375
class BinaryDiffTest(utils.BinaryFileRepoTestCase):
348376
def test_binary_diff(self):

test/test_repository.py

-40
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import binascii
3636
import unittest
3737
import tempfile
38-
import textwrap
3938
import os
4039
from os.path import join, realpath
4140
import sys
@@ -197,45 +196,6 @@ def test_hash(self):
197196
written_sha1 = self.repo.create_blob(data)
198197
self.assertEqual(hashed_sha1, written_sha1)
199198

200-
def test_parse_diff_null(self):
201-
with self.assertRaises(Exception):
202-
self.repo.parse_diff(None)
203-
204-
def test_parse_diff_bad(self):
205-
diff = textwrap.dedent(
206-
"""
207-
diff --git a/file1 b/file1
208-
old mode 0644
209-
new mode 0644
210-
@@ -1,1 +1,1 @@
211-
-Hi!
212-
""")
213-
with self.assertRaises(Exception):
214-
self.repo.parse_diff(diff)
215-
216-
def test_parse_diff(self):
217-
diff = textwrap.dedent(
218-
"""
219-
diff --git a/file1 b/file1
220-
old mode 0644
221-
new mode 0644
222-
@@ -1,1 +1,1 @@
223-
-Hello, world!
224-
+Hola, Mundo!
225-
"""
226-
)
227-
git_diff = self.repo.parse_diff(diff)
228-
stats = git_diff.stats
229-
deltas = list(git_diff.deltas)
230-
231-
self.assertEqual(1, stats.deletions)
232-
self.assertEqual(1, stats.insertions)
233-
self.assertEqual(1, stats.files_changed)
234-
235-
self.assertEqual(1, len(deltas))
236-
self.assertEqual("file1", deltas[0].old_file.path)
237-
self.assertEqual("file1", deltas[0].new_file.path)
238-
239199
def test_hashfile(self):
240200
data = "bazbarfoo"
241201
handle, tempfile_path = tempfile.mkstemp()

0 commit comments

Comments
 (0)