Compare commits
361 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
371c97cadb | ||
![]() |
ab3bb01249 | ||
![]() |
62c70e852d | ||
![]() |
e81f45c4c6 | ||
![]() |
295166bb64 | ||
![]() |
96d37e16a9 | ||
![]() |
2ce8b952c4 | ||
![]() |
e41f71f458 | ||
![]() |
c6305a062b | ||
![]() |
87beb76dcc | ||
![]() |
f18de427bf | ||
![]() |
f841c62fa6 | ||
![]() |
035d4a9396 | ||
![]() |
21d668421f | ||
![]() |
b88dc86842 | ||
![]() |
8559b2da20 | ||
![]() |
9325494d6f | ||
![]() |
74717bed55 | ||
![]() |
3818555e14 | ||
![]() |
706c60c4ab | ||
![]() |
0733ba4da3 | ||
![]() |
320ee5e733 | ||
![]() |
d6716e035a | ||
![]() |
d14438725e | ||
![]() |
dd57c9b366 | ||
![]() |
f2c89a760a | ||
![]() |
f37cf25b8e | ||
![]() |
11ff7a99eb | ||
![]() |
9335819795 | ||
![]() |
784583d21e | ||
![]() |
b81810e9cb | ||
![]() |
7ee851273a | ||
![]() |
1fadc2eae0 | ||
![]() |
453fd8a9a3 | ||
![]() |
630d905e73 | ||
![]() |
9be907983f | ||
![]() |
b31ac50210 | ||
![]() |
da233b16c5 | ||
![]() |
1a842ff8bd | ||
![]() |
cbbf9f1f87 | ||
![]() |
a294655aa5 | ||
![]() |
5a940987cd | ||
![]() |
354d56a95c | ||
![]() |
8327e1bee3 | ||
![]() |
15326b731f | ||
![]() |
f5cd6da307 | ||
![]() |
803b1cb154 | ||
![]() |
d622e87654 | ||
![]() |
819cbff552 | ||
![]() |
4fbc1f1c05 | ||
![]() |
5c061cbb0a | ||
![]() |
68817aad4f | ||
![]() |
0b513d57fa | ||
![]() |
074a726d7f | ||
![]() |
950249442e | ||
![]() |
809fe33b8a | ||
![]() |
6402302002 | ||
![]() |
77f0585645 | ||
![]() |
acdec78617 | ||
![]() |
66280af83a | ||
![]() |
b2a34bd901 | ||
![]() |
44ef9ad2e9 | ||
![]() |
db213113f4 | ||
![]() |
ee28de65a0 | ||
![]() |
825f3e45bd | ||
![]() |
00dd78bf1b | ||
![]() |
e2393a5e24 | ||
![]() |
da59cb1c92 | ||
![]() |
e873c6a363 | ||
![]() |
865c2f0e82 | ||
![]() |
6d6931cd26 | ||
![]() |
9b364dc7f3 | ||
![]() |
578cf58cd7 | ||
![]() |
554f167353 | ||
![]() |
54e4da837b | ||
![]() |
faf6a63d25 | ||
![]() |
30980751cf | ||
![]() |
dae61ded38 | ||
![]() |
0e270c72bd | ||
![]() |
1afbde0d7f | ||
![]() |
7fe7a4da8d | ||
![]() |
fd1e9e3d35 | ||
![]() |
cdd57b2c0f | ||
![]() |
ffc514fa24 | ||
![]() |
c57a3aeb22 | ||
![]() |
ca444f3c7d | ||
![]() |
96beae5c82 | ||
![]() |
68de0f8bb6 | ||
![]() |
df53551cb2 | ||
![]() |
5864b17b57 | ||
![]() |
6c4fa88d07 | ||
![]() |
e96d0286b8 | ||
![]() |
4fa43e234e | ||
![]() |
4416f65fe1 | ||
![]() |
5dcc793aff | ||
![]() |
30f539ff35 | ||
![]() |
df30f9213f | ||
![]() |
50c0569cf0 | ||
![]() |
d8fd2e78d8 | ||
![]() |
fd9a39a91b | ||
![]() |
270dad8cd3 | ||
![]() |
51915ddf0e | ||
![]() |
f2864c0511 | ||
![]() |
456bf59a88 | ||
![]() |
22021c67fc | ||
![]() |
c1d831c98a | ||
![]() |
391a3a74e9 | ||
![]() |
141f0abe62 | ||
![]() |
6b926494db | ||
![]() |
cde5b5170b | ||
![]() |
735510f14d | ||
![]() |
bc424e342f | ||
![]() |
3470fbc1c6 | ||
![]() |
487fb5913e | ||
![]() |
33cf1a1ca2 | ||
![]() |
95ad6b1b0a | ||
![]() |
fa60e2233d | ||
![]() |
daff45f2d4 | ||
![]() |
a5cfea21a7 | ||
![]() |
99dfce9ab8 | ||
![]() |
7a8474cd44 | ||
![]() |
91bb93d266 | ||
![]() |
13f4ddec1d | ||
![]() |
f92d38e25f | ||
![]() |
70edbf256a | ||
![]() |
203335bd63 | ||
![]() |
64150d3535 | ||
![]() |
d25a0d61de | ||
![]() |
f5aa1829ac | ||
![]() |
9db8737364 | ||
![]() |
cf439e4286 | ||
![]() |
eadc2a320f | ||
![]() |
2b083a1509 | ||
![]() |
681c7d4341 | ||
![]() |
8a66da1278 | ||
![]() |
0d2bc05708 | ||
![]() |
b8e6852d26 | ||
![]() |
563cb9018e | ||
![]() |
ac2e363d04 | ||
![]() |
ab97c08f72 | ||
![]() |
7b97ade6ce | ||
![]() |
e4ef8ea5c2 | ||
![]() |
50f4b20e7d | ||
![]() |
802976535a | ||
![]() |
ade211de60 | ||
![]() |
8911416d4f | ||
![]() |
4b607b8256 | ||
![]() |
ec23762c09 | ||
![]() |
ac7738bbb3 | ||
![]() |
29a8dbc6b2 | ||
![]() |
f28a199351 | ||
![]() |
becc265c78 | ||
![]() |
25d02259df | ||
![]() |
27e3450232 | ||
![]() |
4f00dad086 | ||
![]() |
9dd74dd593 | ||
![]() |
c5eae8942d | ||
![]() |
2fdfdcdc4b | ||
![]() |
7ff6f6efb7 | ||
![]() |
f09bbe79a8 | ||
![]() |
81520c9c62 | ||
![]() |
6939b9b203 | ||
![]() |
cc898d29e5 | ||
![]() |
060b3fbaec | ||
![]() |
5469f0c891 | ||
![]() |
74b81bf180 | ||
![]() |
e46119838b | ||
![]() |
8a196f656b | ||
![]() |
deb50536f0 | ||
![]() |
6da3d8f8a8 | ||
![]() |
52dd956896 | ||
![]() |
1f98ba6495 | ||
![]() |
d63c2d4fd7 | ||
![]() |
5b50579790 | ||
![]() |
42d81e33ec | ||
![]() |
0ce4d3b9a8 | ||
![]() |
3091c7aa87 | ||
![]() |
654e4bf56f | ||
![]() |
c072a77e4b | ||
![]() |
d3d60c75f8 | ||
![]() |
1b9cb54927 | ||
![]() |
efb49f8418 | ||
![]() |
7a6465833b | ||
![]() |
b69a2f6197 | ||
![]() |
b3025e3fe1 | ||
![]() |
f923e20f2d | ||
![]() |
cd7e2b21be | ||
![]() |
1f755c601c | ||
![]() |
08f2956e97 | ||
![]() |
99e1cad393 | ||
![]() |
da98890bd1 | ||
![]() |
ca39a65054 | ||
![]() |
cf56a695f9 | ||
![]() |
8b05b296c2 | ||
![]() |
b2ffc8a8d5 | ||
![]() |
e32df6a1c8 | ||
![]() |
fe849f659e | ||
![]() |
c099655fc0 | ||
![]() |
f5485bb86f | ||
![]() |
318c6a8bee | ||
![]() |
367084e3c1 | ||
![]() |
50a70086bf | ||
![]() |
9a4e002864 | ||
![]() |
71ca619e26 | ||
![]() |
38b1975991 | ||
![]() |
2d3f9d8e55 | ||
![]() |
d35ecf945a | ||
![]() |
86c51eadbf | ||
![]() |
404645042b | ||
![]() |
ef67c36d8c | ||
![]() |
bc668751a4 | ||
![]() |
adb351f7b3 | ||
![]() |
fbb11775a3 | ||
![]() |
c7609efc4b | ||
![]() |
82d5214321 | ||
![]() |
c91fdf1d21 | ||
![]() |
1cb62ab578 | ||
![]() |
69f539851b | ||
![]() |
3d896769d0 | ||
![]() |
7130df3a5e | ||
![]() |
94be744ba6 | ||
![]() |
40946cd795 | ||
![]() |
2b2beb8094 | ||
![]() |
c87d28c9a8 | ||
![]() |
d64dd15bd2 | ||
![]() |
9cce003efe | ||
![]() |
d4da228c0e | ||
![]() |
fcd4b9446b | ||
![]() |
fa380c0adb | ||
![]() |
718a2df1d5 | ||
![]() |
30e57e13e3 | ||
![]() |
0ba17a5b46 | ||
![]() |
4709cae1a1 | ||
![]() |
1361b2cce9 | ||
![]() |
7f21f6eb63 | ||
![]() |
f5a5dfc18a | ||
![]() |
961d007b02 | ||
![]() |
909e03d8fc | ||
![]() |
3ee1c798b2 | ||
![]() |
9771adf862 | ||
![]() |
8881b75aaa | ||
![]() |
e7fdaf2510 | ||
![]() |
061961f119 | ||
![]() |
c62a79cf81 | ||
![]() |
8a6e61551c | ||
![]() |
126308403b | ||
![]() |
9da91e554d | ||
![]() |
beaaca7f63 | ||
![]() |
b538163536 | ||
![]() |
9c9b925da8 | ||
![]() |
d0b00e3124 | ||
![]() |
81bde5d0e7 | ||
![]() |
e15c0d828b | ||
![]() |
b2abfdec9e | ||
![]() |
34fb1c00eb | ||
![]() |
52ac41a362 | ||
![]() |
5a06cd2688 | ||
![]() |
78695aa93a | ||
![]() |
66d55aee7e | ||
![]() |
f68b266e60 | ||
![]() |
1dbf94011a | ||
![]() |
4cbfade973 | ||
![]() |
e81d395adf | ||
![]() |
d341cff7d6 | ||
![]() |
4f88840e93 | ||
![]() |
22d1aef50d | ||
![]() |
ceb40ecc52 | ||
![]() |
e807ad43d7 | ||
![]() |
aff3a64e2d | ||
![]() |
df0e11726e | ||
![]() |
beff871923 | ||
![]() |
93be1f1910 | ||
![]() |
b80103b017 | ||
![]() |
b6f0bb0800 | ||
![]() |
6484ef1e37 | ||
![]() |
11eea2d574 | ||
![]() |
d4fc7010b3 | ||
![]() |
21e2102e7c | ||
![]() |
316d5af2d1 | ||
![]() |
cb310316bf | ||
![]() |
ab52904c5d | ||
![]() |
45be961d60 | ||
![]() |
1f0466fe49 | ||
![]() |
8e933c8019 | ||
![]() |
94f650a41d | ||
![]() |
a9fa063de3 | ||
![]() |
bc8b29b4f3 | ||
![]() |
3b27e16d08 | ||
![]() |
7653d12c72 | ||
![]() |
01067cb77f | ||
![]() |
93dd545069 | ||
![]() |
e325c51203 | ||
![]() |
6bb2b369fa | ||
![]() |
7daa95a3a5 | ||
![]() |
6677de82c2 | ||
![]() |
8ca75e2744 | ||
![]() |
05c570c3fc | ||
![]() |
ecba70198f | ||
![]() |
54720c4f01 | ||
![]() |
120fdedb5a | ||
![]() |
149bb1e9e2 | ||
![]() |
b8efdde626 | ||
![]() |
5d4c955d25 | ||
![]() |
fa20589fe9 | ||
![]() |
59da03476e | ||
![]() |
b98e9e85de | ||
![]() |
510f6174f1 | ||
![]() |
9aa39aafbc | ||
![]() |
6831983a26 | ||
![]() |
8bb263559d | ||
![]() |
548ba1ab84 | ||
![]() |
3e87adaccd | ||
![]() |
c997037c7b | ||
![]() |
5bc6a98004 | ||
![]() |
7d34d2bb27 | ||
![]() |
63377aad78 | ||
![]() |
51da3b767d | ||
![]() |
81104d4df2 | ||
![]() |
ab730cb1d4 | ||
![]() |
ae00fe4522 | ||
![]() |
82167827bc | ||
![]() |
a3e7a115f4 | ||
![]() |
5d8c108fe7 | ||
![]() |
7c350bdd7c | ||
![]() |
747e7c2136 | ||
![]() |
70256d1a00 | ||
![]() |
718c7f790c | ||
![]() |
cd08425927 | ||
![]() |
70410349ff | ||
![]() |
4d053cf066 | ||
![]() |
f35f58ca45 | ||
![]() |
ae495444a6 | ||
![]() |
a53d8b2213 | ||
![]() |
fe5c9d68c3 | ||
![]() |
617dd34f5e | ||
![]() |
dad9bc3612 | ||
![]() |
2f2d4005c7 | ||
![]() |
b550027234 | ||
![]() |
14bcce0dcf | ||
![]() |
21efebd305 | ||
![]() |
629eea01e9 | ||
![]() |
4a53b2c8ae | ||
![]() |
e4315aa0a5 | ||
![]() |
9718fd8c32 | ||
![]() |
2bd73f3bdf | ||
![]() |
82b342937f | ||
![]() |
acca2726df | ||
![]() |
a459712fde | ||
![]() |
4056ebf53b | ||
![]() |
99f295e2e8 | ||
![]() |
f0631868af | ||
![]() |
0813ec7923 | ||
![]() |
bedd9ee315 | ||
![]() |
99433ca66a | ||
![]() |
9ce6a26db3 | ||
![]() |
794dbe7b9c | ||
![]() |
6c4e1d093b | ||
![]() |
d752e8550b | ||
![]() |
f787a52e66 | ||
![]() |
f98dc8264a | ||
![]() |
78d134c016 |
.gitattributes.gitignore.mailmap.travis.sh.travis.ymlCHANGELOG.rstREADME.rstappveyor.yml
docs
backends.rstconf.pydevelopment.rstdiff.rstfeatures.rstgeneral.rstindex.rstinstall.rstmerge.rstobjects.rstrecipes.rst
recipes
references.rstremotes.rstrepository.rstsubmodule.rstworking-copy.rstpygit2
__init__.py_build.py_run.pyblame.pyconfig.pycredentials.pydecl.herrors.pyffi.pyindex.pypy2.pypy3.pyrefspec.pyremote.pyrepository.pysettings.pysubmodule.pyutils.pyversion.py
setup.pysrc
blame.cblob.cblob.hbranch.cbranch.hcommit.ccommit.hdiff.cdiff.herror.cerror.hnote.cnote.hobject.cobject.hoid.coid.hoptions.coptions.hpatch.cpatch.hpygit2.creference.creference.hrepository.crepository.hsignature.csignature.htag.ctag.htree.ctree.htreebuilder.ctreebuilder.htypes.hutils.cutils.hwalker.cwalker.h
test
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@ -0,0 +1 @@
|
||||
*.h text eol=lf
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ build
|
||||
dist
|
||||
pygit2.so
|
||||
_pygit2.so
|
||||
.tox/
|
||||
test/*.pyc
|
||||
test/__pycache__
|
||||
pygit2/*.pyc
|
||||
|
12
.mailmap
12
.mailmap
@ -14,3 +14,15 @@ Xu Tao <xutao881001@gmail.com>
|
||||
<petrhosek@gmail.com> <p.hosek@imperial.ac.uk>
|
||||
|
||||
Vlad Temian <vladtemian@gmail.com>
|
||||
|
||||
Matthew Gamble <git@matthewgamble.net>
|
||||
|
||||
Kaarel Kitsemets <kitsemets@gmail.com>
|
||||
|
||||
Matthias Bartelmeß <mba@fourplusone.de>
|
||||
Robert Hölzl <robert.hoelzl@posteo.de>
|
||||
Anatoly Techtonik <techtonik@gmail.com>
|
||||
|
||||
Guillermo Pérez <bisho@fb.com> <bisho@freedreams.org>
|
||||
Matthew Duggan <mduggan@qti.qualcomm.com> <mgithub@guarana.org>
|
||||
Alexander Bayandin <a.bayandin@gmail.com> <bayandin@users.noreply.github.com>
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
cd ~
|
||||
|
||||
git clone --depth=1 -b v0.21.1 https://github.com/libgit2/libgit2.git
|
||||
git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
|
||||
cd libgit2/
|
||||
|
||||
mkdir build && cd build
|
||||
|
@ -2,10 +2,12 @@ language: python
|
||||
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.2"
|
||||
- "3.3"
|
||||
- "3.4"
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "pypy"
|
||||
# - "pypy3"
|
||||
|
||||
env: LIBGIT2=~/libgit2/_install/ LD_LIBRARY_PATH=~/libgit2/_install/lib
|
||||
|
||||
|
859
CHANGELOG.rst
Normal file
859
CHANGELOG.rst
Normal file
@ -0,0 +1,859 @@
|
||||
0.26.0 (2017-07-06)
|
||||
-------------------------
|
||||
|
||||
- Update to libgit2 v0.26
|
||||
`#713 <https://github.com/libgit2/pygit2/pull/713>`_
|
||||
|
||||
- Drop support for Python 3.2, add support for cffi 1.10
|
||||
`#706 <https://github.com/libgit2/pygit2/pull/706>`_
|
||||
`#694 <https://github.com/libgit2/pygit2/issues/694>`_
|
||||
|
||||
- New ``Repository.revert_commit(...)``
|
||||
`#711 <https://github.com/libgit2/pygit2/pull/711>`_
|
||||
`#710 <https://github.com/libgit2/pygit2/issues/710>`_
|
||||
|
||||
- New ``Branch.is_checked_out()``
|
||||
`#696 <https://github.com/libgit2/pygit2/pull/696>`_
|
||||
|
||||
- Various fixes
|
||||
`#706 <https://github.com/libgit2/pygit2/pull/706>`_
|
||||
`#707 <https://github.com/libgit2/pygit2/pull/707>`_
|
||||
`#708 <https://github.com/libgit2/pygit2/pull/708>`_
|
||||
|
||||
|
||||
0.25.1 (2017-04-25)
|
||||
-------------------------
|
||||
|
||||
- Add suport for Python 3.6
|
||||
|
||||
- New support for stash: repository methods ``stash``, ``stash_apply``,
|
||||
``stash_drop`` and ``stash_pop``
|
||||
`#695 <https://github.com/libgit2/pygit2/pull/695>`_
|
||||
|
||||
- Improved support for submodules: new repository methods ``init_submodules``
|
||||
and ``update_submodules``
|
||||
`#692 <https://github.com/libgit2/pygit2/pull/692>`_
|
||||
|
||||
- New friendlier API for branches & references: ``Repository.branches`` and
|
||||
``Repository.references``
|
||||
`#700 <https://github.com/libgit2/pygit2/pull/700>`_
|
||||
`#701 <https://github.com/libgit2/pygit2/pull/701>`_
|
||||
|
||||
- New support for custom backends
|
||||
`#690 <https://github.com/libgit2/pygit2/pull/690>`_
|
||||
|
||||
- Fix ``init_repository`` crash on None input
|
||||
`#688 <https://github.com/libgit2/pygit2/issues/688>`_
|
||||
`#697 <https://github.com/libgit2/pygit2/pull/697>`_
|
||||
|
||||
- Fix checkout with an orphan master branch
|
||||
`#669 <https://github.com/libgit2/pygit2/issues/669>`_
|
||||
`#685 <https://github.com/libgit2/pygit2/pull/685>`_
|
||||
|
||||
- Better error messages for opening repositories
|
||||
`#645 <https://github.com/libgit2/pygit2/issues/645>`_
|
||||
`#698 <https://github.com/libgit2/pygit2/pull/698>`_
|
||||
|
||||
|
||||
0.25.0 (2016-12-26)
|
||||
-------------------------
|
||||
|
||||
- Upgrade to libgit2 0.25
|
||||
`#670 <https://github.com/libgit2/pygit2/pull/670>`_
|
||||
|
||||
- Now Commit.tree raises an error if tree is not found
|
||||
`#682 <https://github.com/libgit2/pygit2/pull/682>`_
|
||||
|
||||
- New settings.mwindow_mapped_limit, cached_memory, enable_caching,
|
||||
cache_max_size and cache_object_limit
|
||||
`#677 <https://github.com/libgit2/pygit2/pull/677>`_
|
||||
|
||||
|
||||
0.24.2 (2016-11-01)
|
||||
-------------------------
|
||||
|
||||
- Unit tests pass on Windows, integration with AppVeyor
|
||||
`#641 <https://github.com/libgit2/pygit2/pull/641>`_
|
||||
`#655 <https://github.com/libgit2/pygit2/issues/655>`_
|
||||
`#657 <https://github.com/libgit2/pygit2/pull/657>`_
|
||||
`#659 <https://github.com/libgit2/pygit2/pull/659>`_
|
||||
`#660 <https://github.com/libgit2/pygit2/pull/660>`_
|
||||
`#661 <https://github.com/libgit2/pygit2/pull/661>`_
|
||||
`#667 <https://github.com/libgit2/pygit2/pull/667>`_
|
||||
|
||||
- Fix when libgit2 error messages have non-ascii chars
|
||||
`#651 <https://github.com/libgit2/pygit2/pull/651>`_
|
||||
|
||||
- Documentation improvements
|
||||
`#643 <https://github.com/libgit2/pygit2/pull/643>`_
|
||||
`#653 <https://github.com/libgit2/pygit2/pull/653>`_
|
||||
`#663 <https://github.com/libgit2/pygit2/pull/663>`_
|
||||
|
||||
|
||||
0.24.1 (2016-06-21)
|
||||
-------------------------
|
||||
|
||||
- New ``Repository.listall_reference_objects()``
|
||||
`#634 <https://github.com/libgit2/pygit2/pull/634>`_
|
||||
|
||||
- Fix ``Repository.write_archive(...)``
|
||||
`#619 <https://github.com/libgit2/pygit2/pull/619>`_
|
||||
`#621 <https://github.com/libgit2/pygit2/pull/621>`_
|
||||
|
||||
- Reproducible builds
|
||||
`#636 <https://github.com/libgit2/pygit2/pull/636>`_
|
||||
|
||||
- Documentation fixes
|
||||
`#606 <https://github.com/libgit2/pygit2/pull/606>`_
|
||||
`#607 <https://github.com/libgit2/pygit2/pull/607>`_
|
||||
`#609 <https://github.com/libgit2/pygit2/pull/609>`_
|
||||
`#623 <https://github.com/libgit2/pygit2/pull/623>`_
|
||||
|
||||
- Test updates
|
||||
`#629 <https://github.com/libgit2/pygit2/pull/629>`_
|
||||
|
||||
|
||||
0.24.0 (2016-03-05)
|
||||
-------------------------
|
||||
|
||||
- Update to libgit2 v0.24
|
||||
`#594 <https://github.com/libgit2/pygit2/pull/594>`_
|
||||
|
||||
- Support Python 3.5
|
||||
|
||||
- New dependency, `six <https://pypi.python.org/pypi/six/>`_
|
||||
|
||||
- New ``Repository.path_is_ignored(path)``
|
||||
`#589 <https://github.com/libgit2/pygit2/pull/589>`_
|
||||
|
||||
- Fix error in ``Repository(path)`` when path is a bytes string
|
||||
`#588 <https://github.com/libgit2/pygit2/issues/588>`_
|
||||
`#593 <https://github.com/libgit2/pygit2/pull/593>`_
|
||||
|
||||
- Fix memory issue in ``Repository.describe(...)``
|
||||
`#592 <https://github.com/libgit2/pygit2/issues/592>`_
|
||||
`#597 <https://github.com/libgit2/pygit2/issues/597>`_
|
||||
`#599 <https://github.com/libgit2/pygit2/pull/599>`_
|
||||
|
||||
- Allow testing with `tox <https://pypi.python.org/pypi/tox/>`_
|
||||
`#600 <https://github.com/libgit2/pygit2/pull/600>`_
|
||||
|
||||
|
||||
0.23.3 (2016-01-01)
|
||||
-------------------------
|
||||
|
||||
- New ``Repository.create_blob_fromiobase(...)``
|
||||
`#490 <https://github.com/libgit2/pygit2/pull/490>`_
|
||||
`#577 <https://github.com/libgit2/pygit2/pull/577>`_
|
||||
|
||||
- New ``Repository.describe(...)``
|
||||
`#585 <https://github.com/libgit2/pygit2/pull/585>`_
|
||||
|
||||
- Fix ``Signature`` default encoding, UTF-8 now
|
||||
`#581 <https://github.com/libgit2/pygit2/issues/581>`_
|
||||
|
||||
- Fixing ``pip install pygit2``, should install cffi first
|
||||
|
||||
- Unit tests, fix binary diff test
|
||||
`#586 <https://github.com/libgit2/pygit2/pull/586>`_
|
||||
|
||||
- Document that ``Diff.patch`` can be ``None``
|
||||
`#587 <https://github.com/libgit2/pygit2/pull/587>`_
|
||||
|
||||
|
||||
0.23.2 (2015-10-11)
|
||||
-------------------------
|
||||
|
||||
- Unify callbacks system for remotes and clone
|
||||
`#568 <https://github.com/libgit2/pygit2/pull/568>`_
|
||||
|
||||
- New ``TreeEntry._name``
|
||||
`#570 <https://github.com/libgit2/pygit2/pull/570>`_
|
||||
|
||||
- Fix segfault in ``Tag._message``
|
||||
`#572 <https://github.com/libgit2/pygit2/pull/572>`_
|
||||
|
||||
- Documentation improvements
|
||||
`#569 <https://github.com/libgit2/pygit2/pull/569>`_
|
||||
`#574 <https://github.com/libgit2/pygit2/pull/574>`_
|
||||
|
||||
API changes to clone::
|
||||
|
||||
# Before
|
||||
clone_repository(..., credentials, certificate)
|
||||
|
||||
# Now
|
||||
callbacks = RemoteCallbacks(credentials, certificate)
|
||||
clone_repository(..., callbacks)
|
||||
|
||||
API changes to remote::
|
||||
|
||||
# Before
|
||||
def transfer_progress(stats):
|
||||
...
|
||||
|
||||
remote.credentials = credentials
|
||||
remote.transfer_progress = transfer_progress
|
||||
remote.fetch()
|
||||
remote.push(specs)
|
||||
|
||||
# Now
|
||||
class MyCallbacks(RemoteCallbacks):
|
||||
def transfer_progress(self, stats):
|
||||
...
|
||||
|
||||
callbacks = MyCallbacks(credentials)
|
||||
remote.fetch(callbacks=callbacks)
|
||||
remote.push(specs, callbacks=callbacks)
|
||||
|
||||
|
||||
0.23.1 (2015-09-26)
|
||||
-------------------------
|
||||
|
||||
- Improve support for cffi 1.0+
|
||||
`#529 <https://github.com/libgit2/pygit2/pull/529>`_
|
||||
`#561 <https://github.com/libgit2/pygit2/pull/561>`_
|
||||
|
||||
- Fix ``Remote.push``
|
||||
`#557 <https://github.com/libgit2/pygit2/pull/557>`_
|
||||
|
||||
- New ``TreeEntry.type``
|
||||
`#560 <https://github.com/libgit2/pygit2/pull/560>`_
|
||||
|
||||
- New ``pygit2.GIT_DIFF_SHOW_BINARY``
|
||||
`#566 <https://github.com/libgit2/pygit2/pull/566>`_
|
||||
|
||||
|
||||
0.23.0 (2015-08-14)
|
||||
-------------------------
|
||||
|
||||
- Update to libgit2 v0.23
|
||||
`#540 <https://github.com/libgit2/pygit2/pull/540>`_
|
||||
|
||||
- Now ``Repository.merge_base(...)`` returns ``None`` if no merge base is found
|
||||
`#550 <https://github.com/libgit2/pygit2/pull/550>`_
|
||||
|
||||
- Documentation updates
|
||||
`#547 <https://github.com/libgit2/pygit2/pull/547>`_
|
||||
|
||||
API changes:
|
||||
|
||||
- How to set identity (aka signature) in a reflog has changed::
|
||||
|
||||
# Before
|
||||
signature = Signature('foo', 'bar')
|
||||
...
|
||||
reference.set_target(target, signature=signature, message=message)
|
||||
repo.set_head(target, signature=signature)
|
||||
remote.fetch(signature=signature)
|
||||
remote.push(signature=signature)
|
||||
|
||||
# Now
|
||||
repo.set_ident('foo', 'bar')
|
||||
...
|
||||
reference.set_target(target, message=message)
|
||||
repo.set_head(target)
|
||||
remote.push()
|
||||
|
||||
# The current identity can be get with
|
||||
repo.ident
|
||||
|
||||
- Some remote setters have been replaced by methods::
|
||||
|
||||
# Before # Now
|
||||
Remote.url = url Repository.remotes.set_url(name, url)
|
||||
Remote.push_url = url Repository.remotes.set_push_url(name, url)
|
||||
|
||||
Remote.add_fetch(refspec) Repository.remotes.add_fetch(name, refspec)
|
||||
Remote.add_push(refspec) Repository.remotes.add_push(name, refspec)
|
||||
|
||||
Remote.fetch_refspecs = [...] removed, use the config API instead
|
||||
Remote.push_refspecs = [...] removed, use the config API instead
|
||||
|
||||
|
||||
0.22.1 (2015-07-12)
|
||||
-------------------------
|
||||
|
||||
Diff interface refactoring
|
||||
`#346 <https://github.com/libgit2/pygit2/pull/346>`_
|
||||
(in progress):
|
||||
|
||||
- New ``iter(pygit2.Blame)``
|
||||
|
||||
- New ``pygit2.DiffDelta``, ``pygit2.DiffFile`` and ``pygit.DiffLine``
|
||||
|
||||
- API changes, translation table::
|
||||
|
||||
Hunk => DiffHunk
|
||||
Patch.old_file_path => Patch.delta.old_file.path
|
||||
Patch.new_file_path => Patch.delta.new_file.path
|
||||
Patch.old_id => Patch.delta.old_file.id
|
||||
Patch.new_id => Patch.delta.new_file.id
|
||||
Patch.status => Patch.delta.status
|
||||
Patch.similarity => Patch.delta.similarity
|
||||
Patch.is_binary => Patch.delta.is_binary
|
||||
Patch.additions => Patch.line_stats[1]
|
||||
Patch.deletions => Patch.line_stats[2]
|
||||
|
||||
- ``DiffHunk.lines`` is now a list of ``DiffLine`` objects, not tuples
|
||||
|
||||
New features:
|
||||
|
||||
- New ``Repository.expand_id(...)`` and ``Repository.ahead_behind(...)``
|
||||
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
|
||||
|
||||
- New ``prefix`` parameter in ``Repository.write_archive``
|
||||
`#481 <https://github.com/libgit2/pygit2/pull/481>`_
|
||||
|
||||
- New ``Repository.merge_trees(...)``
|
||||
`#489 <https://github.com/libgit2/pygit2/pull/489>`_
|
||||
|
||||
- New ``Repository.cherrypick(...)``
|
||||
`#436 <https://github.com/libgit2/pygit2/issues/436>`_
|
||||
`#492 <https://github.com/libgit2/pygit2/pull/492>`_
|
||||
|
||||
- New support for submodules
|
||||
`#499 <https://github.com/libgit2/pygit2/pull/499>`_
|
||||
`#514 <https://github.com/libgit2/pygit2/pull/514>`_
|
||||
|
||||
- New ``Repository.merge_file_from_index(...)``
|
||||
`#503 <https://github.com/libgit2/pygit2/pull/503>`_
|
||||
|
||||
- Now ``Repository.diff`` supports diffing two blobs
|
||||
`#508 <https://github.com/libgit2/pygit2/pull/508>`_
|
||||
|
||||
- New optional ``fetch`` parameter in ``Remote.create``
|
||||
`#526 <https://github.com/libgit2/pygit2/pull/526>`_
|
||||
|
||||
- New ``pygit2.DiffStats``
|
||||
`#406 <https://github.com/libgit2/pygit2/issues/406>`_
|
||||
`#525 <https://github.com/libgit2/pygit2/pull/525>`_
|
||||
|
||||
- New ``Repository.get_attr(...)``
|
||||
`#528 <https://github.com/libgit2/pygit2/pull/528>`_
|
||||
|
||||
- New ``level`` optional parameter in ``Index.remove``
|
||||
`#533 <https://github.com/libgit2/pygit2/pull/533>`_
|
||||
|
||||
- New ``repr(TreeEntry)``
|
||||
`#543 <https://github.com/libgit2/pygit2/pull/543>`_
|
||||
|
||||
Build and install improvements:
|
||||
|
||||
- Make pygit work in a frozen environment
|
||||
`#453 <https://github.com/libgit2/pygit2/pull/453>`_
|
||||
|
||||
- Make pygit2 work with pyinstaller
|
||||
`#510 <https://github.com/libgit2/pygit2/pull/510>`_
|
||||
|
||||
Bugs fixed:
|
||||
|
||||
- Fix memory issues
|
||||
`#477 <https://github.com/libgit2/pygit2/issues/477>`_
|
||||
`#487 <https://github.com/libgit2/pygit2/pull/487>`_
|
||||
`#520 <https://github.com/libgit2/pygit2/pull/520>`_
|
||||
|
||||
- Fix TreeEntry equality testing
|
||||
`#458 <https://github.com/libgit2/pygit2/issues/458>`_
|
||||
`#488 <https://github.com/libgit2/pygit2/pull/488>`_
|
||||
|
||||
- ``Repository.write_archive`` fix handling of symlinks
|
||||
`#480 <https://github.com/libgit2/pygit2/pull/480>`_
|
||||
|
||||
- Fix type check in ``Diff[...]``
|
||||
`#495 <https://github.com/libgit2/pygit2/issues/495>`_
|
||||
|
||||
- Fix error when merging files with unicode content
|
||||
`#505 <https://github.com/libgit2/pygit2/pull/505>`_
|
||||
|
||||
Other:
|
||||
|
||||
- Documentation improvements and fixes
|
||||
`#448 <https://github.com/libgit2/pygit2/pull/448>`_
|
||||
`#491 <https://github.com/libgit2/pygit2/pull/491>`_
|
||||
`#497 <https://github.com/libgit2/pygit2/pull/497>`_
|
||||
`#507 <https://github.com/libgit2/pygit2/pull/507>`_
|
||||
`#517 <https://github.com/libgit2/pygit2/pull/517>`_
|
||||
`#518 <https://github.com/libgit2/pygit2/pull/518>`_
|
||||
`#519 <https://github.com/libgit2/pygit2/pull/519>`_
|
||||
`#521 <https://github.com/libgit2/pygit2/pull/521>`_
|
||||
`#523 <https://github.com/libgit2/pygit2/pull/523>`_
|
||||
`#527 <https://github.com/libgit2/pygit2/pull/527>`_
|
||||
`#536 <https://github.com/libgit2/pygit2/pull/536>`_
|
||||
|
||||
- Expose the ``pygit2.GIT_REPOSITORY_INIT_*`` constants
|
||||
`#483 <https://github.com/libgit2/pygit2/issues/483>`_
|
||||
|
||||
|
||||
0.22.0 (2015-01-16)
|
||||
-------------------
|
||||
|
||||
New:
|
||||
|
||||
- Update to libgit2 v0.22
|
||||
`#459 <https://github.com/libgit2/pygit2/pull/459>`_
|
||||
|
||||
- Add support for libgit2 feature detection
|
||||
(new ``pygit2.features`` and ``pygit2.GIT_FEATURE_*``)
|
||||
`#475 <https://github.com/libgit2/pygit2/pull/475>`_
|
||||
|
||||
- New ``Repository.remotes`` (``RemoteCollection``)
|
||||
`#447 <https://github.com/libgit2/pygit2/pull/447>`_
|
||||
|
||||
API Changes:
|
||||
|
||||
- Prototype of ``clone_repository`` changed, check documentation
|
||||
|
||||
- Removed ``clone_into``, use ``clone_repository`` with callbacks instead
|
||||
|
||||
- Use ``Repository.remotes.rename(name, new_name)`` instead of
|
||||
``Remote.rename(new_name)``
|
||||
|
||||
- Use ``Repository.remotes.delete(name)`` instead of ``Remote.delete()``
|
||||
|
||||
- Now ``Remote.push(...)`` takes a list of refspecs instead of just one
|
||||
|
||||
- Change ``Patch.old_id``, ``Patch.new_id``, ``Note.annotated_id``,
|
||||
``RefLogEntry.oid_old`` and ``RefLogEntry.oid_new`` to be ``Oid`` objects
|
||||
instead of strings
|
||||
`#449 <https://github.com/libgit2/pygit2/pull/449>`_
|
||||
|
||||
Other:
|
||||
|
||||
- Fix ``init_repository`` when passing optional parameters ``workdir_path``,
|
||||
``description``, ``template_path``, ``initial_head`` or ``origin_url``
|
||||
`#466 <https://github.com/libgit2/pygit2/issues/466>`_
|
||||
`#471 <https://github.com/libgit2/pygit2/pull/471>`_
|
||||
|
||||
- Fix use-after-free when patch outlives diff
|
||||
`#457 <https://github.com/libgit2/pygit2/issues/457>`_
|
||||
`#461 <https://github.com/libgit2/pygit2/pull/461>`_
|
||||
`#474 <https://github.com/libgit2/pygit2/pull/474>`_
|
||||
|
||||
- Documentation improvements
|
||||
`#456 <https://github.com/libgit2/pygit2/issues/456>`_
|
||||
`#462 <https://github.com/libgit2/pygit2/pull/462>`_
|
||||
`#465 <https://github.com/libgit2/pygit2/pull/465>`_
|
||||
`#472 <https://github.com/libgit2/pygit2/pull/472>`_
|
||||
`#473 <https://github.com/libgit2/pygit2/pull/473>`_
|
||||
|
||||
- Make the GPL exception explicit in setup.py
|
||||
`#450 <https://github.com/libgit2/pygit2/pull/450>`_
|
||||
|
||||
|
||||
0.21.4 (2014-11-04)
|
||||
-------------------
|
||||
|
||||
- Fix credentials callback not set when pushing
|
||||
`#431 <https://github.com/libgit2/pygit2/pull/431>`_
|
||||
`#435 <https://github.com/libgit2/pygit2/issues/435>`_
|
||||
`#437 <https://github.com/libgit2/pygit2/issues/437>`_
|
||||
`#438 <https://github.com/libgit2/pygit2/pull/438>`_
|
||||
|
||||
- Fix ``Repository.diff(...)`` when treeish is "empty"
|
||||
`#432 <https://github.com/libgit2/pygit2/issues/432>`_
|
||||
|
||||
- New ``Reference.peel(...)`` renders ``Reference.get_object()`` obsolete
|
||||
`#434 <https://github.com/libgit2/pygit2/pull/434>`_
|
||||
|
||||
- New, authenticate using ssh agent
|
||||
`#424 <https://github.com/libgit2/pygit2/pull/424>`_
|
||||
|
||||
- New ``Repository.merge_commits(...)``
|
||||
`#445 <https://github.com/libgit2/pygit2/pull/445>`_
|
||||
|
||||
- Make it easier to run when libgit2 not in a standard location
|
||||
`#441 <https://github.com/libgit2/pygit2/issues/441>`_
|
||||
|
||||
- Documentation: review install chapter
|
||||
|
||||
- Documentation: many corrections
|
||||
`#427 <https://github.com/libgit2/pygit2/pull/427>`_
|
||||
`#429 <https://github.com/libgit2/pygit2/pull/429>`_
|
||||
`#439 <https://github.com/libgit2/pygit2/pull/439>`_
|
||||
`#440 <https://github.com/libgit2/pygit2/pull/440>`_
|
||||
`#442 <https://github.com/libgit2/pygit2/pull/442>`_
|
||||
`#443 <https://github.com/libgit2/pygit2/pull/443>`_
|
||||
`#444 <https://github.com/libgit2/pygit2/pull/444>`_
|
||||
|
||||
|
||||
0.21.3 (2014-09-15)
|
||||
-------------------
|
||||
|
||||
Breaking changes:
|
||||
|
||||
- Now ``Repository.blame(...)`` returns ``Oid`` instead of string
|
||||
`#413 <https://github.com/libgit2/pygit2/pull/413>`_
|
||||
|
||||
- New ``Reference.set_target(...)`` replaces the ``Reference.target`` setter
|
||||
and ``Reference.log_append(...)``
|
||||
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
|
||||
|
||||
- New ``Repository.set_head(...)`` replaces the ``Repository.head`` setter
|
||||
`#414 <https://github.com/libgit2/pygit2/pull/414>`_
|
||||
|
||||
- ``Repository.merge(...)`` now uses the ``SAFE_CREATE`` strategy by default
|
||||
`#417 <https://github.com/libgit2/pygit2/pull/417>`_
|
||||
|
||||
Other changes:
|
||||
|
||||
- New ``Remote.delete()``
|
||||
`#418 <https://github.com/libgit2/pygit2/issues/418>`_
|
||||
`#420 <https://github.com/libgit2/pygit2/pull/420>`_
|
||||
|
||||
- New ``Repository.write_archive(...)``
|
||||
`#421 <https://github.com/libgit2/pygit2/pull/421>`_
|
||||
|
||||
- Now ``Repository.checkout(...)`` accepts branch objects
|
||||
`#408 <https://github.com/libgit2/pygit2/pull/408>`_
|
||||
|
||||
- Fix refcount leak in remotes
|
||||
`#403 <https://github.com/libgit2/pygit2/issues/403>`_
|
||||
`#404 <https://github.com/libgit2/pygit2/pull/404>`_
|
||||
`#419 <https://github.com/libgit2/pygit2/pull/419>`_
|
||||
|
||||
- Various fixes to ``clone_repository(...)``
|
||||
`#399 <https://github.com/libgit2/pygit2/issues/399>`_
|
||||
`#411 <https://github.com/libgit2/pygit2/pull/411>`_
|
||||
`#425 <https://github.com/libgit2/pygit2/issues/425>`_
|
||||
`#426 <https://github.com/libgit2/pygit2/pull/426>`_
|
||||
|
||||
- Fix build error in Python 3
|
||||
`#401 <https://github.com/libgit2/pygit2/pull/401>`_
|
||||
|
||||
- Now ``pip install pygit2`` installs cffi first
|
||||
`#380 <https://github.com/libgit2/pygit2/issues/380>`_
|
||||
`#407 <https://github.com/libgit2/pygit2/pull/407>`_
|
||||
|
||||
- Add support for PyPy3
|
||||
`#422 <https://github.com/libgit2/pygit2/pull/422>`_
|
||||
|
||||
- Documentation improvements
|
||||
`#398 <https://github.com/libgit2/pygit2/pull/398>`_
|
||||
`#409 <https://github.com/libgit2/pygit2/pull/409>`_
|
||||
|
||||
|
||||
0.21.2 (2014-08-09)
|
||||
-------------------
|
||||
|
||||
- Fix regression with Python 2, ``IndexEntry.path`` returns str
|
||||
(bytes in Python 2 and unicode in Python 3)
|
||||
|
||||
- Get back ``IndexEntry.oid`` for backwards compatibility
|
||||
|
||||
- Config, iterate over the keys (instead of the key/value pairs)
|
||||
`#395 <https://github.com/libgit2/pygit2/pull/395>`_
|
||||
|
||||
- ``Diff.find_similar`` supports new threshold arguments
|
||||
`#396 <https://github.com/libgit2/pygit2/pull/396>`_
|
||||
|
||||
- Optimization, do not load the object when expanding an oid prefix
|
||||
`#397 <https://github.com/libgit2/pygit2/pull/397>`_
|
||||
|
||||
|
||||
0.21.1 (2014-07-22)
|
||||
-------------------
|
||||
|
||||
- Install fix
|
||||
`#382 <https://github.com/libgit2/pygit2/pull/382>`_
|
||||
|
||||
- Documentation improved, including
|
||||
`#383 <https://github.com/libgit2/pygit2/pull/383>`_
|
||||
`#385 <https://github.com/libgit2/pygit2/pull/385>`_
|
||||
`#388 <https://github.com/libgit2/pygit2/pull/388>`_
|
||||
|
||||
- Documentation, use the read-the-docs theme
|
||||
`#387 <https://github.com/libgit2/pygit2/pull/387>`_
|
||||
|
||||
- Coding style improvements
|
||||
`#392 <https://github.com/libgit2/pygit2/pull/392>`_
|
||||
|
||||
- New ``Repository.state_cleanup()``
|
||||
`#386 <https://github.com/libgit2/pygit2/pull/386>`_
|
||||
|
||||
- New ``Index.conflicts``
|
||||
`#345 <https://github.com/libgit2/pygit2/issues/345>`_
|
||||
`#389 <https://github.com/libgit2/pygit2/pull/389>`_
|
||||
|
||||
- New checkout option to define the target directory
|
||||
`#390 <https://github.com/libgit2/pygit2/pull/390>`_
|
||||
|
||||
|
||||
Backward incompatible changes:
|
||||
|
||||
- Now the checkout strategy must be a keyword argument.
|
||||
|
||||
Change ``Repository.checkout(refname, strategy)`` to
|
||||
``Repository.checkout(refname, strategy=strategy)``
|
||||
|
||||
Idem for ``checkout_head``, ``checkout_index`` and ``checkout_tree``
|
||||
|
||||
|
||||
0.21.0 (2014-06-27)
|
||||
-------------------
|
||||
|
||||
Highlights:
|
||||
|
||||
- Drop official support for Python 2.6, and add support for Python 3.4
|
||||
`#376 <https://github.com/libgit2/pygit2/pull/376>`_
|
||||
|
||||
- Upgrade to libgit2 v0.21.0
|
||||
`#374 <https://github.com/libgit2/pygit2/pull/374>`_
|
||||
|
||||
- Start using cffi
|
||||
`#360 <https://github.com/libgit2/pygit2/pull/360>`_
|
||||
`#361 <https://github.com/libgit2/pygit2/pull/361>`_
|
||||
|
||||
Backward incompatible changes:
|
||||
|
||||
- Replace ``oid`` by ``id`` through the API to follow libgit2 conventions.
|
||||
- Merge API overhaul following changes in libgit2.
|
||||
- New ``Remote.rename(...)`` replaces ``Remote.name = ...``
|
||||
- Now ``Remote.fetch()`` returns a ``TransferProgress`` object.
|
||||
- Now ``Config.get_multivar(...)`` returns an iterator instead of a list.
|
||||
|
||||
New features:
|
||||
|
||||
- New ``Config.snapshot()`` and ``Repository.config_snapshot()``
|
||||
|
||||
- New ``Config`` methods: ``get_bool(...)``, ``get_int(...)``,
|
||||
``parse_bool(...)`` and ``parse_int(...)``
|
||||
`#357 <https://github.com/libgit2/pygit2/pull/357>`_
|
||||
|
||||
- Blob: implement the memory buffer interface
|
||||
`#362 <https://github.com/libgit2/pygit2/pull/362>`_
|
||||
|
||||
- New ``clone_into(...)`` function
|
||||
`#368 <https://github.com/libgit2/pygit2/pull/368>`_
|
||||
|
||||
- Now ``Index`` can be used alone, without a repository
|
||||
`#372 <https://github.com/libgit2/pygit2/pull/372>`_
|
||||
|
||||
- Add more options to ``init_repository``
|
||||
`#347 <https://github.com/libgit2/pygit2/pull/347>`_
|
||||
|
||||
- Support ``Repository.workdir = ...`` and
|
||||
support setting detached heads ``Repository.head = <Oid>``
|
||||
`#377 <https://github.com/libgit2/pygit2/pull/377>`_
|
||||
|
||||
Other:
|
||||
|
||||
- Fix again build with VS2008
|
||||
`#364 <https://github.com/libgit2/pygit2/pull/364>`_
|
||||
|
||||
- Fix ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)`` arguments passing
|
||||
`#366 <https://github.com/libgit2/pygit2/pull/366>`_
|
||||
|
||||
- Fail gracefully when compiling against the wrong version of libgit2
|
||||
`#365 <https://github.com/libgit2/pygit2/pull/365>`_
|
||||
|
||||
- Several documentation improvements and updates
|
||||
`#359 <https://github.com/libgit2/pygit2/pull/359>`_
|
||||
`#375 <https://github.com/libgit2/pygit2/pull/375>`_
|
||||
`#378 <https://github.com/libgit2/pygit2/pull/378>`_
|
||||
|
||||
|
||||
|
||||
0.20.3 (2014-04-02)
|
||||
-------------------
|
||||
|
||||
- A number of memory issues fixed
|
||||
`#328 <https://github.com/libgit2/pygit2/pull/328>`_
|
||||
`#348 <https://github.com/libgit2/pygit2/pull/348>`_
|
||||
`#353 <https://github.com/libgit2/pygit2/pull/353>`_
|
||||
`#355 <https://github.com/libgit2/pygit2/pull/355>`_
|
||||
`#356 <https://github.com/libgit2/pygit2/pull/356>`_
|
||||
- Compatibility fixes for
|
||||
PyPy (`#338 <https://github.com/libgit2/pygit2/pull/338>`_),
|
||||
Visual Studio 2008 (`#343 <https://github.com/libgit2/pygit2/pull/343>`_)
|
||||
and Python 3.3 (`#351 <https://github.com/libgit2/pygit2/pull/351>`_)
|
||||
- Make the sort mode parameter in ``Repository.walk(...)`` optional
|
||||
`#337 <https://github.com/libgit2/pygit2/pull/337>`_
|
||||
- New ``Object.peel(...)``
|
||||
`#342 <https://github.com/libgit2/pygit2/pull/342>`_
|
||||
- New ``Index.add_all(...)``
|
||||
`#344 <https://github.com/libgit2/pygit2/pull/344>`_
|
||||
- Introduce support for libgit2 options
|
||||
`#350 <https://github.com/libgit2/pygit2/pull/350>`_
|
||||
- More informative repr for ``Repository`` objects
|
||||
`#352 <https://github.com/libgit2/pygit2/pull/352>`_
|
||||
- Introduce support for credentials
|
||||
`#354 <https://github.com/libgit2/pygit2/pull/354>`_
|
||||
- Several documentation fixes
|
||||
`#302 <https://github.com/libgit2/pygit2/issues/302>`_
|
||||
`#336 <https://github.com/libgit2/pygit2/issues/336>`_
|
||||
- Tests, remove temporary files
|
||||
`#341 <https://github.com/libgit2/pygit2/pull/341>`_
|
||||
|
||||
|
||||
0.20.2 (2014-02-04)
|
||||
-------------------
|
||||
|
||||
- Support PyPy
|
||||
`#209 <https://github.com/libgit2/pygit2/issues/209>`_
|
||||
`#327 <https://github.com/libgit2/pygit2/pull/327>`_
|
||||
`#333 <https://github.com/libgit2/pygit2/pull/333>`_
|
||||
|
||||
Repository:
|
||||
|
||||
- New ``Repository.default_signature``
|
||||
`#310 <https://github.com/libgit2/pygit2/pull/310>`_
|
||||
|
||||
Oid:
|
||||
|
||||
- New ``str(Oid)`` deprecates ``Oid.hex``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
Object:
|
||||
|
||||
- New ``Object.id`` deprecates ``Object.oid``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
- New ``TreeEntry.id`` deprecates ``TreeEntry.oid``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
- New ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)``
|
||||
`#307 <https://github.com/libgit2/pygit2/pull/307>`_
|
||||
|
||||
- New ``Commit.tree_id`` and ``Commit.parent_ids``
|
||||
`#73 <https://github.com/libgit2/pygit2/issues/73>`_
|
||||
`#311 <https://github.com/libgit2/pygit2/pull/311>`_
|
||||
|
||||
- New rich comparison between tree entries
|
||||
`#305 <https://github.com/libgit2/pygit2/issues/305>`_
|
||||
`#313 <https://github.com/libgit2/pygit2/pull/313>`_
|
||||
|
||||
- Now ``Tree.__contains__(key)`` supports paths
|
||||
`#306 <https://github.com/libgit2/pygit2/issues/306>`_
|
||||
`#316 <https://github.com/libgit2/pygit2/pull/316>`_
|
||||
|
||||
Index:
|
||||
|
||||
- Now possible to create ``IndexEntry(...)``
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``IndexEntry.path``, ``IndexEntry.oid`` and ``IndexEntry.mode`` are
|
||||
writable
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``Index.add(...)`` accepts an ``IndexEntry`` too
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``Index.write_tree(...)`` is able to write to a different repository
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Fix memory leak in ``IndexEntry.path`` setter
|
||||
`#335 <https://github.com/libgit2/pygit2/pull/335>`_
|
||||
|
||||
Config:
|
||||
|
||||
- New ``Config`` iterator replaces ``Config.foreach``
|
||||
`#183 <https://github.com/libgit2/pygit2/issues/183>`_
|
||||
`#312 <https://github.com/libgit2/pygit2/pull/312>`_
|
||||
|
||||
Remote:
|
||||
|
||||
- New type ``Refspec``
|
||||
`#314 <https://github.com/libgit2/pygit2/pull/314>`_
|
||||
|
||||
- New ``Remote.push_url``
|
||||
`#315 <https://github.com/libgit2/pygit2/pull/314>`_
|
||||
|
||||
- New ``Remote.add_push`` and ``Remote.add_fetch``
|
||||
`#255 <https://github.com/libgit2/pygit2/issues/255>`_
|
||||
`#318 <https://github.com/libgit2/pygit2/pull/318>`_
|
||||
|
||||
- New ``Remote.fetch_refspecs`` replaces ``Remote.get_fetch_refspecs()`` and
|
||||
``Remote.set_fetch_refspecs(...)``
|
||||
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
|
||||
|
||||
- New ``Remote.push_refspecs`` replaces ``Remote.get_push_refspecs()`` and
|
||||
``Remote.set_push_refspecs(...)``
|
||||
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
|
||||
|
||||
- New ``Remote.progress``, ``Remote.transfer_progress`` and
|
||||
``Remote.update_tips``
|
||||
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
|
||||
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
|
||||
|
||||
- New type ``TransferProgress``
|
||||
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
|
||||
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
|
||||
|
||||
- Fix refcount leak in ``Repository.remotes``
|
||||
`#321 <https://github.com/libgit2/pygit2/issues/321>`_
|
||||
`#332 <https://github.com/libgit2/pygit2/pull/332>`_
|
||||
|
||||
Other: `#331 <https://github.com/libgit2/pygit2/pull/331>`_
|
||||
|
||||
|
||||
0.20.1 (2013-12-24)
|
||||
-------------------
|
||||
|
||||
- New remote ref-specs API:
|
||||
`#290 <https://github.com/libgit2/pygit2/pull/290>`_
|
||||
|
||||
- New ``Repository.reset(...)``:
|
||||
`#292 <https://github.com/libgit2/pygit2/pull/292>`_,
|
||||
`#294 <https://github.com/libgit2/pygit2/pull/294>`_
|
||||
|
||||
- Export ``GIT_DIFF_MINIMAL``:
|
||||
`#293 <https://github.com/libgit2/pygit2/pull/293>`_
|
||||
|
||||
- New ``Repository.merge(...)``:
|
||||
`#295 <https://github.com/libgit2/pygit2/pull/295>`_
|
||||
|
||||
- Fix ``Repository.blame`` argument handling:
|
||||
`#297 <https://github.com/libgit2/pygit2/pull/297>`_
|
||||
|
||||
- Fix build error on Windows:
|
||||
`#298 <https://github.com/libgit2/pygit2/pull/298>`_
|
||||
|
||||
- Fix typo in the README file, Blog → Blob:
|
||||
`#301 <https://github.com/libgit2/pygit2/pull/301>`_
|
||||
|
||||
- Now ``Diff.patch`` returns ``None`` if no patch:
|
||||
`#232 <https://github.com/libgit2/pygit2/pull/232>`_,
|
||||
`#303 <https://github.com/libgit2/pygit2/pull/303>`_
|
||||
|
||||
- New ``Walker.simplify_first_parent()``:
|
||||
`#304 <https://github.com/libgit2/pygit2/pull/304>`_
|
||||
|
||||
0.20.0 (2013-11-24)
|
||||
-------------------
|
||||
|
||||
- Upgrade to libgit2 v0.20.0:
|
||||
`#288 <https://github.com/libgit2/pygit2/pull/288>`_
|
||||
|
||||
- New ``Repository.head_is_unborn`` replaces ``Repository.head_is_orphaned``
|
||||
|
||||
- Changed ``pygit2.clone_repository(...)``. Drop ``push_url``, ``fetch_spec``
|
||||
and ``push_spec`` parameters. Add ``ignore_cert_errors``.
|
||||
|
||||
- New ``Patch.additions`` and ``Patch.deletions``:
|
||||
`#275 <https://github.com/libgit2/pygit2/pull/275>`_
|
||||
|
||||
- New ``Patch.is_binary``:
|
||||
`#276 <https://github.com/libgit2/pygit2/pull/276>`_
|
||||
|
||||
- New ``Reference.log_append(...)``:
|
||||
`#277 <https://github.com/libgit2/pygit2/pull/277>`_
|
||||
|
||||
- New ``Blob.is_binary``:
|
||||
`#278 <https://github.com/libgit2/pygit2/pull/278>`_
|
||||
|
||||
- New ``len(Diff)`` shows the number of patches:
|
||||
`#281 <https://github.com/libgit2/pygit2/pull/281>`_
|
||||
|
||||
- Rewrite ``Repository.status()``:
|
||||
`#283 <https://github.com/libgit2/pygit2/pull/283>`_
|
||||
|
||||
- New ``Reference.shorthand``:
|
||||
`#284 <https://github.com/libgit2/pygit2/pull/284>`_
|
||||
|
||||
- New ``Repository.blame(...)``:
|
||||
`#285 <https://github.com/libgit2/pygit2/pull/285>`_
|
||||
|
||||
- Now ``Repository.listall_references()`` and
|
||||
``Repository.listall_branches()`` return a list, not a tuple:
|
||||
`#289 <https://github.com/libgit2/pygit2/pull/289>`_
|
408
README.rst
408
README.rst
@ -2,19 +2,22 @@
|
||||
pygit2 - libgit2 bindings in Python
|
||||
######################################################################
|
||||
|
||||
.. image:: https://secure.travis-ci.org/libgit2/pygit2.png
|
||||
.. image:: https://travis-ci.org/libgit2/pygit2.svg?branch=master
|
||||
:target: http://travis-ci.org/libgit2/pygit2
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/edmwc0dctk5nacx0/branch/master?svg=true
|
||||
:target: https://ci.appveyor.com/project/jdavid/pygit2/branch/master
|
||||
|
||||
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
||||
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
|
||||
pypy.
|
||||
implements Git plumbing. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5, 3.6
|
||||
and PyPy 2.6
|
||||
|
||||
Links:
|
||||
|
||||
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
|
||||
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
|
||||
- http://www.pygit2.org/ -- Documentation
|
||||
- http://pypi.python.org/pypi/pygit2 -- Download
|
||||
|
||||
- https://pypi.python.org/pypi/pygit2 -- Download
|
||||
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
|
||||
|
||||
How to install
|
||||
==============
|
||||
@ -22,363 +25,50 @@ How to install
|
||||
- Check http://www.pygit2.org/install.html
|
||||
|
||||
|
||||
Changelog
|
||||
==============
|
||||
|
||||
0.21.2 (2014-08-09)
|
||||
-------------------
|
||||
|
||||
- Fix regression with Python 2, ``IndexEntry.path`` returns str
|
||||
(bytes in Python 2 and unicode in Python 3)
|
||||
|
||||
- Get back ``IndexEntry.oid`` for backwards compatibility
|
||||
|
||||
- Config, iterate over the keys (instead of the key/value pairs)
|
||||
`#395 <https://github.com/libgit2/pygit2/pull/395>`_
|
||||
|
||||
- ``Diff.find_similar`` supports new threshold arguments
|
||||
`#396 <https://github.com/libgit2/pygit2/pull/396>`_
|
||||
|
||||
- Optimization, do not load the object when expanding an oid prefix
|
||||
`#397 <https://github.com/libgit2/pygit2/pull/397>`_
|
||||
|
||||
|
||||
0.21.1 (2014-07-22)
|
||||
-------------------
|
||||
|
||||
- Install fix
|
||||
`#382 <https://github.com/libgit2/pygit2/pull/382>`_
|
||||
|
||||
- Documentation improved, including
|
||||
`#383 <https://github.com/libgit2/pygit2/pull/383>`_
|
||||
`#385 <https://github.com/libgit2/pygit2/pull/385>`_
|
||||
`#388 <https://github.com/libgit2/pygit2/pull/388>`_
|
||||
|
||||
- Documentation, use the read-the-docs theme
|
||||
`#387 <https://github.com/libgit2/pygit2/pull/387>`_
|
||||
|
||||
- Coding style improvements
|
||||
`#392 <https://github.com/libgit2/pygit2/pull/392>`_
|
||||
|
||||
- New ``Repository.state_cleanup()``
|
||||
`#386 <https://github.com/libgit2/pygit2/pull/386>`_
|
||||
|
||||
- New ``Index.conflicts``
|
||||
`#345 <https://github.com/libgit2/pygit2/issues/345>`_
|
||||
`#389 <https://github.com/libgit2/pygit2/pull/389>`_
|
||||
|
||||
- New checkout option to define the target directory
|
||||
`#390 <https://github.com/libgit2/pygit2/pull/390>`_
|
||||
|
||||
|
||||
Backward incompatible changes:
|
||||
|
||||
- Now the checkout strategy must be a keyword argument.
|
||||
|
||||
Change ``Repository.checkout(refname, strategy)`` to
|
||||
``Repository.checkout(refname, strategy=strategy)``
|
||||
|
||||
Idem for ``checkout_head``, ``checkout_index`` and ``checkout_tree``
|
||||
|
||||
|
||||
0.21.0 (2014-06-27)
|
||||
-------------------
|
||||
|
||||
Highlights:
|
||||
|
||||
- Drop official support for Python 2.6, and add support for Python 3.4
|
||||
`#376 <https://github.com/libgit2/pygit2/pull/376>`_
|
||||
|
||||
- Upgrade to libgit2 v0.21.0
|
||||
`#374 <https://github.com/libgit2/pygit2/pull/374>`_
|
||||
|
||||
- Start using cffi
|
||||
`#360 <https://github.com/libgit2/pygit2/pull/360>`_
|
||||
`#361 <https://github.com/libgit2/pygit2/pull/361>`_
|
||||
|
||||
Backward incompatible changes:
|
||||
|
||||
- Replace ``oid`` by ``id`` through the API to follow libgit2 conventions.
|
||||
- Merge API overhaul following changes in libgit2.
|
||||
- New ``Remote.rename(...)`` replaces ``Remote.name = ...``
|
||||
- Now ``Remote.fetch()`` returns a ``TransferProgress`` object.
|
||||
- Now ``Config.get_multivar(...)`` returns an iterator instead of a list.
|
||||
|
||||
New features:
|
||||
|
||||
- New ``Config.snapshot()`` and ``Repository.config_snapshot()``
|
||||
|
||||
- New ``Config`` methods: ``get_bool(...)``, ``get_int(...)``,
|
||||
``parse_bool(...)`` and ``parse_int(...)``
|
||||
`#357 <https://github.com/libgit2/pygit2/pull/357>`_
|
||||
|
||||
- Blob: implement the memory buffer interface
|
||||
`#362 <https://github.com/libgit2/pygit2/pull/362>`_
|
||||
|
||||
- New ``clone_into(...)`` function
|
||||
`#368 <https://github.com/libgit2/pygit2/pull/368>`_
|
||||
|
||||
- Now ``Index`` can be used alone, without a repository
|
||||
`#372 <https://github.com/libgit2/pygit2/pull/372>`_
|
||||
|
||||
- Add more options to ``init_repository``
|
||||
`#347 <https://github.com/libgit2/pygit2/pull/347>`_
|
||||
|
||||
- Support ``Repository.workdir = ...`` and
|
||||
support setting detached heads ``Repository.head = <Oid>``
|
||||
`#377 <https://github.com/libgit2/pygit2/pull/377>`_
|
||||
|
||||
Other:
|
||||
|
||||
- Fix again build with VS2008
|
||||
`#364 <https://github.com/libgit2/pygit2/pull/364>`_
|
||||
|
||||
- Fix ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)`` arguments passing
|
||||
`#366 <https://github.com/libgit2/pygit2/pull/366>`_
|
||||
|
||||
- Fail gracefully when compiling against the wrong version of libgit2
|
||||
`#365 <https://github.com/libgit2/pygit2/pull/365>`_
|
||||
|
||||
- Several documentation improvements and updates
|
||||
`#359 <https://github.com/libgit2/pygit2/pull/359>`_
|
||||
`#375 <https://github.com/libgit2/pygit2/pull/375>`_
|
||||
`#378 <https://github.com/libgit2/pygit2/pull/378>`_
|
||||
|
||||
|
||||
|
||||
0.20.3 (2014-04-02)
|
||||
-------------------
|
||||
|
||||
- A number of memory issues fixed
|
||||
`#328 <https://github.com/libgit2/pygit2/pull/328>`_
|
||||
`#348 <https://github.com/libgit2/pygit2/pull/348>`_
|
||||
`#353 <https://github.com/libgit2/pygit2/pull/353>`_
|
||||
`#355 <https://github.com/libgit2/pygit2/pull/355>`_
|
||||
`#356 <https://github.com/libgit2/pygit2/pull/356>`_
|
||||
- Compatibility fixes for
|
||||
PyPy (`#338 <https://github.com/libgit2/pygit2/pull/338>`_),
|
||||
Visual Studio 2008 (`#343 <https://github.com/libgit2/pygit2/pull/343>`_)
|
||||
and Python 3.3 (`#351 <https://github.com/libgit2/pygit2/pull/351>`_)
|
||||
- Make the sort mode parameter in ``Repository.walk(...)`` optional
|
||||
`#337 <https://github.com/libgit2/pygit2/pull/337>`_
|
||||
- New ``Object.peel(...)``
|
||||
`#342 <https://github.com/libgit2/pygit2/pull/342>`_
|
||||
- New ``Index.add_all(...)``
|
||||
`#344 <https://github.com/libgit2/pygit2/pull/344>`_
|
||||
- Introduce support for libgit2 options
|
||||
`#350 <https://github.com/libgit2/pygit2/pull/350>`_
|
||||
- More informative repr for ``Repository`` objects
|
||||
`#352 <https://github.com/libgit2/pygit2/pull/352>`_
|
||||
- Introduce support for credentials
|
||||
`#354 <https://github.com/libgit2/pygit2/pull/354>`_
|
||||
- Several documentation fixes
|
||||
`#302 <https://github.com/libgit2/pygit2/issues/302>`_
|
||||
`#336 <https://github.com/libgit2/pygit2/issues/336>`_
|
||||
- Tests, remove temporary files
|
||||
`#341 <https://github.com/libgit2/pygit2/pull/341>`_
|
||||
|
||||
|
||||
0.20.2 (2014-02-04)
|
||||
-------------------
|
||||
|
||||
- Support pypy
|
||||
`#209 <https://github.com/libgit2/pygit2/issues/209>`_
|
||||
`#327 <https://github.com/libgit2/pygit2/pull/327>`_
|
||||
`#333 <https://github.com/libgit2/pygit2/pull/333>`_
|
||||
|
||||
Repository:
|
||||
|
||||
- New ``Repository.default_signature``
|
||||
`#310 <https://github.com/libgit2/pygit2/pull/310>`_
|
||||
|
||||
Oid:
|
||||
|
||||
- New ``str(Oid)`` deprecates ``Oid.hex``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
Object:
|
||||
|
||||
- New ``Object.id`` deprecates ``Object.oid``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
- New ``TreeEntry.id`` deprecates ``TreeEntry.oid``
|
||||
`#322 <https://github.com/libgit2/pygit2/pull/322>`_
|
||||
|
||||
- New ``Blob.diff(...)`` and ``Blob.diff_to_buffer(...)``
|
||||
`#307 <https://github.com/libgit2/pygit2/pull/307>`_
|
||||
|
||||
- New ``Commit.tree_id`` and ``Commit.parent_ids``
|
||||
`#73 <https://github.com/libgit2/pygit2/issues/73>`_
|
||||
`#311 <https://github.com/libgit2/pygit2/pull/311>`_
|
||||
|
||||
- New rich comparison between tree entries
|
||||
`#305 <https://github.com/libgit2/pygit2/issues/305>`_
|
||||
`#313 <https://github.com/libgit2/pygit2/pull/313>`_
|
||||
|
||||
- Now ``Tree.__contains__(key)`` supports paths
|
||||
`#306 <https://github.com/libgit2/pygit2/issues/306>`_
|
||||
`#316 <https://github.com/libgit2/pygit2/pull/316>`_
|
||||
|
||||
Index:
|
||||
|
||||
- Now possible to create ``IndexEntry(...)``
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``IndexEntry.path``, ``IndexEntry.oid`` and ``IndexEntry.mode`` are
|
||||
writable
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``Index.add(...)`` accepts an ``IndexEntry`` too
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Now ``Index.write_tree(...)`` is able to write to a different repository
|
||||
`#325 <https://github.com/libgit2/pygit2/pull/325>`_
|
||||
|
||||
- Fix memory leak in ``IndexEntry.path`` setter
|
||||
`#335 <https://github.com/libgit2/pygit2/pull/335>`_
|
||||
|
||||
Config:
|
||||
|
||||
- New ``Config`` iterator replaces ``Config.foreach``
|
||||
`#183 <https://github.com/libgit2/pygit2/issues/183>`_
|
||||
`#312 <https://github.com/libgit2/pygit2/pull/312>`_
|
||||
|
||||
Remote:
|
||||
|
||||
- New type ``Refspec``
|
||||
`#314 <https://github.com/libgit2/pygit2/pull/314>`_
|
||||
|
||||
- New ``Remote.push_url``
|
||||
`#315 <https://github.com/libgit2/pygit2/pull/314>`_
|
||||
|
||||
- New ``Remote.add_push`` and ``Remote.add_fetch``
|
||||
`#255 <https://github.com/libgit2/pygit2/issues/255>`_
|
||||
`#318 <https://github.com/libgit2/pygit2/pull/318>`_
|
||||
|
||||
- New ``Remote.fetch_refspecs`` replaces ``Remote.get_fetch_refspecs()`` and
|
||||
``Remote.set_fetch_refspecs(...)``
|
||||
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
|
||||
|
||||
- New ``Remote.push_refspecs`` replaces ``Remote.get_push_refspecs()`` and
|
||||
``Remote.set_push_refspecs(...)``
|
||||
`#319 <https://github.com/libgit2/pygit2/pull/319>`_
|
||||
|
||||
- New ``Remote.progress``, ``Remote.transfer_progress`` and
|
||||
``Remote.update_tips``
|
||||
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
|
||||
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
|
||||
|
||||
- New type ``TransferProgress``
|
||||
`#274 <https://github.com/libgit2/pygit2/issues/274>`_
|
||||
`#324 <https://github.com/libgit2/pygit2/pull/324>`_
|
||||
|
||||
- Fix refcount leak in ``Repository.remotes``
|
||||
`#321 <https://github.com/libgit2/pygit2/issues/321>`_
|
||||
`#332 <https://github.com/libgit2/pygit2/pull/332>`_
|
||||
|
||||
Other: `#331 <https://github.com/libgit2/pygit2/pull/331>`_
|
||||
|
||||
|
||||
0.20.1 (2013-12-24)
|
||||
-------------------
|
||||
|
||||
- New remote ref-specs API:
|
||||
`#290 <https://github.com/libgit2/pygit2/pull/290>`_
|
||||
|
||||
- New ``Repository.reset(...)``:
|
||||
`#292 <https://github.com/libgit2/pygit2/pull/292>`_,
|
||||
`#294 <https://github.com/libgit2/pygit2/pull/294>`_
|
||||
|
||||
- Export ``GIT_DIFF_MINIMAL``:
|
||||
`#293 <https://github.com/libgit2/pygit2/pull/293>`_
|
||||
|
||||
- New ``Repository.merge(...)``:
|
||||
`#295 <https://github.com/libgit2/pygit2/pull/295>`_
|
||||
|
||||
- Fix ``Repository.blame`` argument handling:
|
||||
`#297 <https://github.com/libgit2/pygit2/pull/297>`_
|
||||
|
||||
- Fix build error on Windows:
|
||||
`#298 <https://github.com/libgit2/pygit2/pull/298>`_
|
||||
|
||||
- Fix typo in the README file, Blog → Blob:
|
||||
`#301 <https://github.com/libgit2/pygit2/pull/301>`_
|
||||
|
||||
- Now ``Diff.patch`` returns ``None`` if no patch:
|
||||
`#232 <https://github.com/libgit2/pygit2/pull/232>`_,
|
||||
`#303 <https://github.com/libgit2/pygit2/pull/303>`_
|
||||
|
||||
- New ``Walker.simplify_first_parent()``:
|
||||
`#304 <https://github.com/libgit2/pygit2/pull/304>`_
|
||||
|
||||
0.20.0 (2013-11-24)
|
||||
-------------------
|
||||
|
||||
- Upgrade to libgit2 v0.20.0:
|
||||
`#288 <https://github.com/libgit2/pygit2/pull/288>`_
|
||||
|
||||
- New ``Repository.head_is_unborn`` replaces ``Repository.head_is_orphaned``
|
||||
|
||||
- Changed ``pygit2.clone_repository(...)``. Drop ``push_url``, ``fetch_spec``
|
||||
and ``push_spec`` parameters. Add ``ignore_cert_errors``.
|
||||
|
||||
- New ``Patch.additions`` and ``Patch.deletions``:
|
||||
`#275 <https://github.com/libgit2/pygit2/pull/275>`_
|
||||
|
||||
- New ``Patch.is_binary``:
|
||||
`#276 <https://github.com/libgit2/pygit2/pull/276>`_
|
||||
|
||||
- New ``Reference.log_append(...)``:
|
||||
`#277 <https://github.com/libgit2/pygit2/pull/277>`_
|
||||
|
||||
- New ``Blob.is_binary``:
|
||||
`#278 <https://github.com/libgit2/pygit2/pull/278>`_
|
||||
|
||||
- New ``len(Diff)`` shows the number of patches:
|
||||
`#281 <https://github.com/libgit2/pygit2/pull/281>`_
|
||||
|
||||
- Rewrite ``Repository.status()``:
|
||||
`#283 <https://github.com/libgit2/pygit2/pull/283>`_
|
||||
|
||||
- New ``Reference.shorthand``:
|
||||
`#284 <https://github.com/libgit2/pygit2/pull/284>`_
|
||||
|
||||
- New ``Repository.blame(...)``:
|
||||
`#285 <https://github.com/libgit2/pygit2/pull/285>`_
|
||||
|
||||
- Now ``Repository.listall_references()`` and
|
||||
``Repository.listall_branches()`` return a list, not a tuple:
|
||||
`#289 <https://github.com/libgit2/pygit2/pull/289>`_
|
||||
|
||||
|
||||
Authors
|
||||
==============
|
||||
|
||||
69 developers have contributed at least 1 commit to pygit2::
|
||||
117 developers have contributed at least 1 commit to pygit2::
|
||||
|
||||
J. David Ibáñez Rémi Duraffort Adam Spiers
|
||||
Nico von Geyso Sebastian Thiel Alexander Bayandin
|
||||
Carlos Martín Nieto Fraser Tweedale Andrew Chin
|
||||
W. Trevor King Han-Wen Nienhuys András Veres-Szentkirályi
|
||||
Dave Borowitz Leonardo Rhodes Benjamin Kircher
|
||||
Daniel Rodríguez Troitiño Petr Viktorin Benjamin Pollack
|
||||
Richo Healey Thomas Kluyver Bryan O'Sullivan
|
||||
Christian Boos Alex Chamberlain Daniel Bruce
|
||||
Julien Miotte Amit Bakshi David Fischer
|
||||
Xu Tao Andrey Devyatkin David Sanders
|
||||
Jose Plana Arno van Lumig Devaev Maxim
|
||||
Martin Lenders Ben Davis Eric Davis
|
||||
Petr Hosek Eric Schrijver Erik Meusel
|
||||
Victor Garcia Hervé Cauwelier Erik van Zijst
|
||||
Xavier Delannoy Huang Huang Ferengee
|
||||
Yonggang Luo Ian P. McCullough Gustavo Di Pietro
|
||||
Valentin Haenel Jack O'Connor Hugh Cole-Baker
|
||||
Michael Jones Jared Flatow Jasper Lievisse Adriaanse
|
||||
Bernardo Heynemann Jiunn Haur Lim Josh Bleecher Snyder
|
||||
John Szakmeister Jun Omae Óscar San José
|
||||
Brodie Rao Sarath Lakshman Ridge Kennedy
|
||||
Vlad Temian Vicent Marti Rui Abreu Ferreira
|
||||
David Versmisse Zoran Zaric earl
|
||||
J. David Ibáñez Carlos Martín Nieto Nico von Geyso
|
||||
W. Trevor King Dave Borowitz Matthias Bartelmeß
|
||||
Daniel Rodríguez Troitiño Richo Healey Christian Boos
|
||||
Julien Miotte Richard Möhn Xu Tao
|
||||
Jose Plana Matthew Duggan Matthew Gamble
|
||||
Martin Lenders Nick Hynes Petr Hosek
|
||||
Victor Garcia Xavier Delannoy Yonggang Luo
|
||||
Patrick Steinhardt Tamir Bahar Valentin Haenel
|
||||
Michael Jones Bernardo Heynemann Brodie Rao
|
||||
John Szakmeister Vlad Temian Lukas Fleischer
|
||||
Nicolas Dandrimont David Versmisse Rémi Duraffort
|
||||
Santiago Perez De Rosso Sebastian Thiel Thom Wiggers
|
||||
Alok Singhal Anatoly Techtonik Fraser Tweedale
|
||||
Han-Wen Nienhuys Jason Ziglar Leonardo Rhodes
|
||||
Petr Viktorin Robert Hölzl Ron Cohen
|
||||
Thomas Kluyver Alex Chamberlain Alexander Bayandin
|
||||
Amit Bakshi Andrey Devyatkin Arno van Lumig
|
||||
Ben Davis Dustin Raimondi Eric Schrijver
|
||||
Greg Fitzgerald Guillermo Pérez Hervé Cauwelier
|
||||
Huang Huang Ian P. McCullough Igor Gnatenko
|
||||
Jack O'Connor Jared Flatow Jiunn Haur Lim
|
||||
Jun Omae Kaarel Kitsemets Kevin KIN-FOO
|
||||
Mark Adams Masud Rahman Michael Sondergaard
|
||||
Ondřej Nový Sarath Lakshman Szucs Krisztian
|
||||
Vicent Marti Zoran Zaric Adam Spiers
|
||||
Andrew Chin András Veres-Szentkirályi Ash Berlin
|
||||
Benjamin Kircher Benjamin Pollack Bryan O'Sullivan
|
||||
Cam Cope Chason Chaffin Chris Rebert
|
||||
Colin Watson Daniel Bruce David Fischer
|
||||
David Sanders David Six Devaev Maxim
|
||||
Eric Davis Erik Meusel Erik van Zijst
|
||||
Ferengee Gustavo Di Pietrou Holger Frey
|
||||
Hugh Cole-Baker Jasper Lievisse Adriaanse Josh Bleecher Snyder
|
||||
Justin Clift Kyriakos Oikonomakos Mathieu Bridon
|
||||
Matthaus Woolard Nicolás Sanguinetti Noah Fontes
|
||||
Óscar San José Peter Dave Hello Philippe Ombredanne
|
||||
Ridge Kennedy Ross Nicoll Rui Abreu Ferreira
|
||||
Sheeo Soasme Vladimir Rutsky
|
||||
Yu Jianjian chengyuhang earl
|
||||
|
||||
|
||||
License
|
||||
|
53
appveyor.yml
Normal file
53
appveyor.yml
Normal file
@ -0,0 +1,53 @@
|
||||
version: 1.0.{build}
|
||||
image: Visual Studio 2015
|
||||
configuration: Release
|
||||
environment:
|
||||
matrix:
|
||||
- GENERATOR: 'Visual Studio 10'
|
||||
PYTHON: 'C:\Python27\python.exe'
|
||||
- GENERATOR: 'Visual Studio 10 Win64'
|
||||
PYTHON: 'C:\Python27-x64\python.exe'
|
||||
- GENERATOR: 'Visual Studio 10'
|
||||
PYTHON: 'C:\Python33\python.exe'
|
||||
- GENERATOR: 'Visual Studio 10 Win64'
|
||||
PYTHON: 'C:\Python33-x64\python.exe'
|
||||
- GENERATOR: 'Visual Studio 10'
|
||||
PYTHON: 'C:\Python34\python.exe'
|
||||
- GENERATOR: 'Visual Studio 10 Win64'
|
||||
PYTHON: 'C:\Python34-x64\python.exe'
|
||||
- GENERATOR: 'Visual Studio 14'
|
||||
PYTHON: 'C:\Python35\python.exe'
|
||||
- GENERATOR: 'Visual Studio 14 Win64'
|
||||
PYTHON: 'C:\Python35-x64\python.exe'
|
||||
- GENERATOR: 'Visual Studio 14'
|
||||
PYTHON: 'C:\Python36\python.exe'
|
||||
- GENERATOR: 'Visual Studio 14 Win64'
|
||||
PYTHON: 'C:\Python36-x64\python.exe'
|
||||
|
||||
init:
|
||||
- cmd: '%PYTHON% -m pip install -U nose wheel'
|
||||
build_script:
|
||||
- cmd: |
|
||||
set LIBGIT2=%APPVEYOR_BUILD_FOLDER%\build\libgit2
|
||||
git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git libgit2
|
||||
mkdir build
|
||||
|
||||
cd build
|
||||
cmake -DSTDCALL=OFF -DBUILD_CLAR=OFF -DCMAKE_INSTALL_PREFIX="%LIBGIT2%" ../libgit2 -G "%GENERATOR%"
|
||||
cmake --build . --config Release --target install
|
||||
cd ..
|
||||
|
||||
IF "%GENERATOR%"=="Visual Studio 10 Win64" ( call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\SetEnv.cmd" )
|
||||
|
||||
"%PYTHON%" setup.py bdist_wheel
|
||||
test_script:
|
||||
- ps: |
|
||||
cp build\Release\git2.dll .
|
||||
&$env:PYTHON setup.py nosetests --with-xunit
|
||||
if ($LastExitCode -ne 0) { $host.SetShouldExit($LastExitCode) }
|
||||
# upload results to AppVeyor
|
||||
$wc = New-Object 'System.Net.WebClient'
|
||||
$wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\nosetests.xml))
|
||||
|
||||
artifacts:
|
||||
- path: dist\*.whl
|
8
docs/backends.rst
Normal file
8
docs/backends.rst
Normal file
@ -0,0 +1,8 @@
|
||||
**********************************************************************
|
||||
Custom backends
|
||||
**********************************************************************
|
||||
|
||||
There is some support for custom backends, but undocumented. See
|
||||
`<https://github.com/libgit2/pygit2/pull/690/commits>`_
|
||||
|
||||
Documentation contributions are very welcome.
|
12
docs/conf.py
12
docs/conf.py
@ -11,12 +11,14 @@
|
||||
# All configuration values have a default; values that are commented out
|
||||
# serve to show the default.
|
||||
|
||||
import sys, os
|
||||
import sys, os, platform
|
||||
from string import digits
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
sys.path.insert(0, os.path.abspath('../build/lib.linux-x86_64-2.7'))
|
||||
version_string = sys.platform.rstrip(digits) + "-" + os.uname()[4] + "-" + ".".join(platform.python_version_tuple()[0:2])
|
||||
sys.path.insert(0, os.path.abspath('../build/lib.' + version_string))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
@ -41,16 +43,16 @@ master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'pygit2'
|
||||
copyright = u'2010-2014 The pygit2 contributors'
|
||||
copyright = u'2010-2015 The pygit2 contributors'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.21'
|
||||
version = '0.26'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.21.2'
|
||||
release = '0.26.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
@ -2,9 +2,12 @@
|
||||
The development version
|
||||
**********************************************************************
|
||||
|
||||
.. image:: https://secure.travis-ci.org/libgit2/pygit2.png
|
||||
.. image:: https://travis-ci.org/libgit2/pygit2.svg?branch=master
|
||||
:target: http://travis-ci.org/libgit2/pygit2
|
||||
|
||||
.. image:: https://ci.appveyor.com/api/projects/status/edmwc0dctk5nacx0/branch/master?svg=true
|
||||
:target: https://ci.appveyor.com/project/jdavid/pygit2/branch/master
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ git clone git://github.com/libgit2/pygit2.git
|
||||
|
@ -23,6 +23,10 @@ Examples
|
||||
>>> diff = repo.diff('HEAD^', 'HEAD~3')
|
||||
>>> patches = [p for p in diff]
|
||||
|
||||
# Get the stats for a diff
|
||||
>>> diff = repo.diff('HEAD^', 'HEAD~3')
|
||||
>>> diff.stats
|
||||
|
||||
# Diffing the empty tree
|
||||
>>> tree = revparse_single('HEAD').tree
|
||||
>>> tree.diff_to_tree()
|
||||
@ -35,6 +39,10 @@ The Diff type
|
||||
====================
|
||||
|
||||
.. autoattribute:: pygit2.Diff.patch
|
||||
.. method:: Diff.__iter__()
|
||||
|
||||
Returns an iterator over the deltas/patches in this diff.
|
||||
|
||||
.. method:: Diff.__len__()
|
||||
|
||||
Returns the number of deltas/patches in this diff.
|
||||
@ -48,26 +56,60 @@ The Patch type
|
||||
|
||||
Attributes:
|
||||
|
||||
.. autoattribute:: pygit2.Patch.old_file_path
|
||||
.. autoattribute:: pygit2.Patch.new_file_path
|
||||
.. autoattribute:: pygit2.Patch.old_id
|
||||
.. autoattribute:: pygit2.Patch.new_id
|
||||
.. autoattribute:: pygit2.Patch.status
|
||||
.. autoattribute:: pygit2.Patch.similarity
|
||||
.. autoattribute:: pygit2.Patch.delta
|
||||
.. autoattribute:: pygit2.Patch.hunks
|
||||
.. autoattribute:: pygit2.Patch.additions
|
||||
.. autoattribute:: pygit2.Patch.deletions
|
||||
.. autoattribute:: pygit2.Patch.line_stats
|
||||
|
||||
|
||||
The DiffDelta type
|
||||
====================
|
||||
|
||||
Attributes:
|
||||
|
||||
.. autoattribute:: pygit2.DiffDelta.old_file
|
||||
.. autoattribute:: pygit2.DiffDelta.new_file
|
||||
.. autoattribute:: pygit2.DiffDelta.status
|
||||
.. autoattribute:: pygit2.DiffDelta.similarity
|
||||
|
||||
Getters:
|
||||
|
||||
.. autoattribute:: pygit2.Patch.is_binary
|
||||
.. autoattribute:: pygit2.DiffDelta.is_binary
|
||||
|
||||
|
||||
The Hunk type
|
||||
The DiffFile type
|
||||
====================
|
||||
|
||||
.. autoattribute:: pygit2.Hunk.old_start
|
||||
.. autoattribute:: pygit2.Hunk.old_lines
|
||||
.. autoattribute:: pygit2.Hunk.new_start
|
||||
.. autoattribute:: pygit2.Hunk.new_lines
|
||||
.. autoattribute:: pygit2.Hunk.lines
|
||||
Attributes:
|
||||
|
||||
.. autoattribute:: pygit2.DiffFile.path
|
||||
.. autoattribute:: pygit2.DiffFile.id
|
||||
.. autoattribute:: pygit2.DiffFile.size
|
||||
.. autoattribute:: pygit2.DiffFile.flags
|
||||
.. autoattribute:: pygit2.DiffFile.mode
|
||||
|
||||
|
||||
The DiffHunk type
|
||||
====================
|
||||
|
||||
.. autoattribute:: pygit2.DiffHunk.old_start
|
||||
.. autoattribute:: pygit2.DiffHunk.old_lines
|
||||
.. autoattribute:: pygit2.DiffHunk.new_start
|
||||
.. autoattribute:: pygit2.DiffHunk.new_lines
|
||||
.. autoattribute:: pygit2.DiffHunk.lines
|
||||
|
||||
The DiffStats type
|
||||
====================
|
||||
|
||||
.. autoattribute :: pygit2.DiffStats.insertions
|
||||
.. autoattribute :: pygit2.DiffStats.deletions
|
||||
.. autoattribute :: pygit2.DiffStats.files_changed
|
||||
.. automethod :: pygit2.DiffStats.format
|
||||
|
||||
The DiffLine type
|
||||
====================
|
||||
|
||||
.. autoattribute :: pygit2.DiffLine.origin
|
||||
.. autoattribute :: pygit2.DiffLine.content
|
||||
.. autoattribute :: pygit2.DiffLine.old_lineno
|
||||
.. autoattribute :: pygit2.DiffLine.new_lineno
|
||||
.. autoattribute :: pygit2.DiffLine.num_lines
|
||||
|
8
docs/features.rst
Normal file
8
docs/features.rst
Normal file
@ -0,0 +1,8 @@
|
||||
**********************************************************************
|
||||
Feature detection
|
||||
**********************************************************************
|
||||
|
||||
.. py:data:: pygit2.features
|
||||
|
||||
This variable contains a combination of `GIT_FEATURE_*` flags,
|
||||
indicating which features a particular build of libgit2 supports.
|
@ -18,7 +18,7 @@ library that has been built against. The version number has a
|
||||
.. py:data:: LIBGIT2_VER_MAJOR
|
||||
|
||||
Integer value of the major version number. For example, for the version
|
||||
``0.21.1``::
|
||||
``0.26.0``::
|
||||
|
||||
>>> print LIBGIT2_VER_MAJOR
|
||||
0
|
||||
@ -26,25 +26,25 @@ library that has been built against. The version number has a
|
||||
.. py:data:: LIBGIT2_VER_MINOR
|
||||
|
||||
Integer value of the minor version number. For example, for the version
|
||||
``0.21.1``::
|
||||
``0.26.0``::
|
||||
|
||||
>>> print LIBGIT2_VER_MINOR
|
||||
21
|
||||
26
|
||||
|
||||
.. py:data:: LIBGIT2_VER_REVISION
|
||||
|
||||
Integer value of the revision version number. For example, for the version
|
||||
``0.21.1``::
|
||||
``0.26.0``::
|
||||
|
||||
>>> print LIBGIT2_VER_REVISION
|
||||
1
|
||||
0
|
||||
|
||||
.. py:data:: LIBGIT2_VERSION
|
||||
|
||||
The libgit2 version number as a string::
|
||||
|
||||
>>> print LIBGIT2_VERSION
|
||||
'0.21.1'
|
||||
'0.26.0'
|
||||
|
||||
Errors
|
||||
======
|
||||
|
@ -7,17 +7,18 @@ Welcome to pygit2's documentation!
|
||||
==================================
|
||||
|
||||
Pygit2 is a set of Python bindings to the libgit2 shared library, libgit2
|
||||
implements the core of Git. Pygit2 works with Python 2.7, 3.2, 3.3, 3.4 and
|
||||
pypy.
|
||||
implements the core of Git. Pygit2 works with Python 2.7, 3.3, 3.4, 3.5,
|
||||
3.6 and pypy.
|
||||
|
||||
It is likely to work with Python 2.6 and 3.1, but these versions are not
|
||||
officially supported.
|
||||
|
||||
Pygit2 links:
|
||||
Links:
|
||||
|
||||
- http://github.com/libgit2/pygit2 -- Source code and issue tracker
|
||||
- https://github.com/libgit2/pygit2 -- Source code and issue tracker
|
||||
- http://www.pygit2.org/ -- Documentation
|
||||
- http://pypi.python.org/pypi/pygit2 -- Download
|
||||
- https://pypi.python.org/pypi/pygit2 -- Download
|
||||
- https://github.com/libgit2/pygit2/blob/master/CHANGELOG.rst -- Changelog
|
||||
|
||||
Start:
|
||||
|
||||
@ -45,8 +46,11 @@ Usage guide:
|
||||
merge
|
||||
config
|
||||
remotes
|
||||
submodule
|
||||
blame
|
||||
settings
|
||||
features
|
||||
backends
|
||||
|
||||
|
||||
Indices and tables
|
||||
|
242
docs/install.rst
242
docs/install.rst
@ -13,68 +13,83 @@ Installation
|
||||
Requirements
|
||||
============
|
||||
|
||||
- Python 2.7, 3.2, 3.3, 3.4 or pypy.
|
||||
Including the development headers.
|
||||
- Python 2.7, 3.3+ or PyPy 2.6+ (including the development headers)
|
||||
- Libgit2 v0.26.x
|
||||
- cffi 1.0+
|
||||
- six
|
||||
- tox (optional)
|
||||
|
||||
- Libgit2 v0.21.1
|
||||
Optional libgit2 dependecies to support ssh and https:
|
||||
|
||||
- cffi 0.8.1+
|
||||
- https: WinHTTP (Windows), SecureTransport (OS X) or OpenSSL.
|
||||
- ssh: libssh2, pkg-config
|
||||
|
||||
It should work with older versions of cffi and PyPy, but using cffi 1.0+
|
||||
(and PyPy 2.6+) is strongly encouraged.
|
||||
|
||||
One common mistake users do is to choose incompatible versions of libgit2 and
|
||||
pygit2. Be sure to use the latest release of both, double check the versions do
|
||||
match before filling un bug report.
|
||||
.. warning::
|
||||
|
||||
.. note::
|
||||
One common mistake users do is to choose incompatible versions of libgit2
|
||||
and pygit2. See below for a reference table of compatible versions. Double
|
||||
check the versions do match before filing a bug report.
|
||||
|
||||
The version of pygit2 is composed of three numbers separated by dots
|
||||
|lq| *major.minor.micro* |rq|, where the first two numbers
|
||||
|lq| *major.minor* |rq| match the first two numbers of the libgit2 version,
|
||||
while the last number |lq| *.micro* |rq| auto-increments independently.
|
||||
Version numbers
|
||||
---------------
|
||||
|
||||
As illustration see this table of compatible releases:
|
||||
The version number of pygit2 is composed of three numbers separated by dots
|
||||
|lq| *major.minor.micro* |rq|, where the first two numbers
|
||||
|lq| *major.minor* |rq| match the first two numbers of the libgit2 version,
|
||||
while the last number |lq| *.micro* |rq| auto-increments independently.
|
||||
|
||||
+-----------+-----------------------+------------------------------+
|
||||
|**libgit2**|0.21.1 |0.20.0 |
|
||||
+-----------+-----------------------+------------------------------+
|
||||
|**pygit2** |0.21.0, 0.21.1, 0.21.2 |0.20.0, 0.20.1, 0.20.2, 0.20.3|
|
||||
+-----------+-----------------------+------------------------------+
|
||||
As illustration see this table of compatible releases:
|
||||
|
||||
**Warning!** Backwards compatibility is not guaranteed even between micro
|
||||
releases. Please check the release notes for incompatible changes before
|
||||
upgrading to a new release.
|
||||
+-----------+--------+----------------+------------------------+
|
||||
|**libgit2**| 0.26.0 | 0.25.0, 0.25.1 | 0.24.0, 0.24.1, 0.24.2 |
|
||||
+-----------+--------+----------------+------------------------+
|
||||
|**pygit2** | 0.26.0 | 0.25.0, 0.25.1 | 0.24.0, 0.24.1, 0.24.2 |
|
||||
+-----------+--------+----------------+------------------------+
|
||||
|
||||
.. warning::
|
||||
|
||||
Backwards compatibility is not guaranteed even between micro releases.
|
||||
Please check the release notes for incompatible changes before upgrading to
|
||||
a new release.
|
||||
|
||||
|
||||
Quick install
|
||||
=============
|
||||
|
||||
This works for me, it may work for you:
|
||||
To install the latest version of libgit2 system wide, in the ``/usr/local``
|
||||
directory, do:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ wget https://github.com/libgit2/libgit2/archive/v0.21.1.tar.gz
|
||||
$ tar xzf v0.21.1.tar.gz
|
||||
$ cd libgit2-0.21.1/
|
||||
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
|
||||
$ tar xzf v0.26.0.tar.gz
|
||||
$ cd libgit2-0.26.0/
|
||||
$ cmake .
|
||||
$ make
|
||||
$ sudo make install
|
||||
|
||||
If this does not work for you, check the detailed instructions on building
|
||||
libgit2 in various platforms, see
|
||||
https://libgit2.github.com/docs/guides/build-and-link/
|
||||
.. seealso::
|
||||
|
||||
Once libgit2 is instaleld, deploying pygit2 should be a snap:
|
||||
For detailed instructions on building libgit2 check
|
||||
https://libgit2.github.com/docs/guides/build-and-link/
|
||||
|
||||
Now install pygit2, and then verify it is correctly installed:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pìp install cffi
|
||||
$ pip install pygit2
|
||||
...
|
||||
$ python -c 'import pygit2'
|
||||
|
||||
|
||||
Troobleshooting
|
||||
===============
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
You may get an error like this one:
|
||||
The verification step may fail if the dynamic linker does not find the libgit2
|
||||
library:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
@ -85,71 +100,40 @@ You may get an error like this one:
|
||||
from _pygit2 import *
|
||||
ImportError: libgit2.so.0: cannot open shared object file: No such file or directory
|
||||
|
||||
It means the linker is not able to find the libgit2 library.
|
||||
|
||||
This happens for instance in Ubuntu: the libgit2 library is installed within
|
||||
This happens for instance in Ubuntu, the libgit2 library is installed within
|
||||
the ``/usr/local/lib`` directory, but the linker does not look for it there. To
|
||||
fix this call ``ldconfig`` between the installation of libgit2 and the
|
||||
installation of pygit2:
|
||||
fix this call ``ldconfig``:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
...
|
||||
$ cmake .
|
||||
$ make
|
||||
$ sudo make install
|
||||
...
|
||||
$ sudo ldconfig
|
||||
...
|
||||
$ pip install cffi
|
||||
$ pip install pygit2
|
||||
$ python -c 'import pygit2'
|
||||
|
||||
Now it should work. If it does not...
|
||||
|
||||
Advanced: the runpath
|
||||
---------------------
|
||||
|
||||
If it does not work yet, you can always instruct pygit2 to search for libraries
|
||||
in some extra paths:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ export LIBGIT2="/usr/local"
|
||||
$ export LDFLAGS="-Wl,-rpath='$LIBGIT2/lib',--enable-new-dtags $LDFLAGS"
|
||||
$ pip install pygit2
|
||||
|
||||
This compiles the pygit2 libraries with a ``RUNPATH``, which bakes extra
|
||||
library search paths directly into the binaries (see the `ld man page`_ for
|
||||
details). With ``RUNPATH`` compiled in, you won't have to use
|
||||
``LD_LIBRARY_PATH``. You can check to ensure ``RUNPATH`` was set with
|
||||
readelf_:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ readelf --dynamic build/lib.linux-x86_64-3.2/_pygit2.cpython-32.so | grep PATH
|
||||
0x000000000000000f (RPATH) Library rpath: [/usr/local/lib]
|
||||
0x000000000000001d (RUNPATH) Library runpath: [/usr/local/lib]
|
||||
|
||||
.. _Shared libraries: http://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html
|
||||
.. _ld man page: http://linux.die.net/man/1/ld
|
||||
.. _readelf: http://www.gnu.org/software/binutils/
|
||||
If it still does not work, please open an issue at
|
||||
https://github.com/libgit2/pygit2/issues, I would like to know about it.
|
||||
|
||||
|
||||
The LIBGIT2 environment variable
|
||||
================================
|
||||
Build options
|
||||
=============
|
||||
|
||||
If libgit2 is installed in some non standard location, you will have to set the
|
||||
``LIBGIT2`` environment variable before installing pygit2. This variables tells
|
||||
pygit2 where libgit2 is installed.
|
||||
``LIBGIT2`` -- If you install libgit2 in an unusual place, you will need to set
|
||||
the ``LIBGIT2`` environment variable before installing pygit2. This variable
|
||||
tells pygit2 where libgit2 is installed. We will see a concrete example later,
|
||||
when explaining how to install libgit2 within a virtual environment.
|
||||
|
||||
``LIBGIT2_LIB`` -- This is a more rarely used build option, it allows to
|
||||
override the library directory where libgit2 is installed, useful if different
|
||||
from from ``$LIBGIT2/lib``.
|
||||
|
||||
|
||||
Use case: libgit2 within a Virtualenv
|
||||
-------------------------------------
|
||||
libgit2 within a virtual environment
|
||||
====================================
|
||||
|
||||
A use case for this is if you want to install libgit2 inside a virtualenv, so
|
||||
you may have several virtualenvs with different versions of libgit2/pygit2,
|
||||
isolated from each other. Or maybe you just don't have root access to install
|
||||
libgit2 in the system.
|
||||
This is how to install both libgit2 and pygit2 within a virtual environment.
|
||||
|
||||
This is useful if you don't have root acces to install libgit2 system wide.
|
||||
Or if you wish to have different versions of libgit2/pygit2 installed in
|
||||
different virtual environments, isolated from each other.
|
||||
|
||||
Create the virtualenv, activate it, and set the ``LIBGIT2`` environment
|
||||
variable:
|
||||
@ -164,9 +148,9 @@ Install libgit2 (see we define the installation prefix):
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ wget https://github.com/libgit2/libgit2/archive/v0.21.1.tar.gz
|
||||
$ tar xzf v0.21.1.tar.gz
|
||||
$ cd libgit2-0.21.1/
|
||||
$ wget https://github.com/libgit2/libgit2/archive/v0.26.0.tar.gz
|
||||
$ tar xzf v0.26.0.tar.gz
|
||||
$ cd libgit2-0.26.0/
|
||||
$ cmake . -DCMAKE_INSTALL_PREFIX=$LIBGIT2
|
||||
$ make
|
||||
$ make install
|
||||
@ -175,31 +159,81 @@ Install pygit2:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ pìp install cffi
|
||||
$ export LDFLAGS="-Wl,-rpath='$LIBGIT2/lib',--enable-new-dtags $LDFLAGS"
|
||||
$ pip install pygit2
|
||||
$ python -c 'import pygit2'
|
||||
|
||||
|
||||
Building on Windows
|
||||
The run-path
|
||||
------------------------------------------
|
||||
|
||||
Did you notice we set the `rpath <http://en.wikipedia.org/wiki/Rpath>`_ before
|
||||
installing pygit2? Since libgit2 is installed in a non standard location, the
|
||||
dynamic linker will not find it at run-time, and ``lddconfig`` will not help
|
||||
this time.
|
||||
|
||||
So you need to either set ``LD_LIBRARY_PATH`` before using pygit2, like:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ export LD_LIBRARY_PATH=$LIBGIT2/lib
|
||||
$ python -c 'import pygit2'
|
||||
|
||||
Or, like we have done in the instructions above, use the `rpath
|
||||
<http://en.wikipedia.org/wiki/Rpath>`_, it hard-codes extra search paths within
|
||||
the pygit2 extension modules, so you don't need to set ``LD_LIBRARY_PATH``
|
||||
everytime. Verify yourself if curious:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ readelf --dynamic lib/python2.7/site-packages/pygit2-0.26.0-py2.7-linux-x86_64.egg/_pygit2.so | grep PATH
|
||||
0x000000000000001d (RUNPATH) Library runpath: [/tmp/venv/lib]
|
||||
|
||||
|
||||
Installing on Windows
|
||||
===================================
|
||||
|
||||
pygit2 expects to find the libgit2 installed files in the directory specified
|
||||
in the ``LIBGIT2`` environment variable.
|
||||
`pygit2` for Windows is packaged into wheels and can be easily
|
||||
installed with `pip`:
|
||||
|
||||
In addition, make sure that libgit2 is build in "__cdecl" mode.
|
||||
The following recipe shows you how to do it, assuming you're working
|
||||
from a bash shell:
|
||||
pip install pygit2
|
||||
|
||||
For development it is also possible to build `pygit2` with `libgit2`
|
||||
from sources. `libgit2` location is specified by the ``LIBGIT2``
|
||||
environment variable. `libgit2` should be built in "__cdecl" mode.
|
||||
The following recipe shows you how to do it from a bash shell:
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ export LIBGIT2=C:/Dev/libgit2
|
||||
$ wget https://github.com/libgit2/libgit2/archive/v0.21.1.tar.gz
|
||||
$ tar xzf v0.21.1.tar.gz
|
||||
$ cd libgit2-0.21.1/
|
||||
$ mkdir build
|
||||
$ cd build
|
||||
$ cmake .. -DSTDCALL=OFF -DCMAKE_INSTALL_PREFIX=$LIBGIT2 -G "Visual Studio 9 2008"
|
||||
$ git clone --depth=1 -b maint/v0.26 https://github.com/libgit2/libgit2.git
|
||||
$ cd libgit2
|
||||
$ cmake . -DSTDCALL=OFF -DCMAKE_INSTALL_PREFIX=$LIBGIT2 -G "Visual Studio 9 2008"
|
||||
$ cmake --build . --config release --target install
|
||||
$ ctest -v
|
||||
|
||||
At this point, you're ready to execute the generic pygit2 installation
|
||||
steps described above.
|
||||
At this point, you're ready to execute the generic `pygit2`
|
||||
installation steps described at the start of this page.
|
||||
|
||||
|
||||
Installing on OS X
|
||||
===================================
|
||||
|
||||
.. note::
|
||||
|
||||
You will need the `XCode <https://developer.apple.com/xcode/>`_ Developer
|
||||
Tools from Apple. This free download from the Mac App Store will provide the
|
||||
clang compiler needed for the installation of pygit2.
|
||||
|
||||
This section was tested on OS X 10.9 Mavericks and OS X 10.10 Yosemite with
|
||||
Python 3.3 in a virtual environment.
|
||||
|
||||
The easiest way is to first install libgit2 with the `Homebrew <http://brew.sh>`_
|
||||
package manager and then use pip3 for pygit2. The following example assumes that
|
||||
XCode and Hombrew are already installed.
|
||||
|
||||
.. code-block:: sh
|
||||
|
||||
$ brew update
|
||||
$ brew install libgit2
|
||||
$ pip3 install pygit2
|
||||
|
@ -1,5 +1,5 @@
|
||||
**********************************************************************
|
||||
Merge
|
||||
Merge & Cherrypick
|
||||
**********************************************************************
|
||||
|
||||
.. contents::
|
||||
@ -29,7 +29,28 @@ You can now inspect the index file for conflicts and get back to the
|
||||
user to resolve if there are. Once there are no conflicts left, you
|
||||
can create a commit with these two parents.
|
||||
|
||||
>>> user = repo.default_signature()
|
||||
>>> user = repo.default_signature
|
||||
>>> tree = repo.index.write_tree()
|
||||
>>> new_commit = repo.create_commit('HEAD', user, user, tree,
|
||||
[repo.head.target, other_branch_tip])
|
||||
|
||||
|
||||
Cherrypick
|
||||
===================
|
||||
|
||||
.. automethod:: pygit2.Repository.cherrypick
|
||||
|
||||
Note that after a successful cherrypick you have to run
|
||||
:py:meth:`.Repository.state_cleanup` in order to get the repository out
|
||||
of cherrypicking mode.
|
||||
|
||||
|
||||
Lower-level methods
|
||||
===================
|
||||
|
||||
These methods allow more direct control over how to perform the
|
||||
merging. They do not modify the working directory and return an
|
||||
in-memory Index representing the result of the merge.
|
||||
|
||||
.. automethod:: pygit2.Repository.merge_commits
|
||||
.. automethod:: pygit2.Repository.merge_trees
|
||||
|
@ -132,6 +132,7 @@ them to the Git object database:
|
||||
|
||||
.. automethod:: pygit2.Repository.create_blob_fromworkdir
|
||||
.. automethod:: pygit2.Repository.create_blob_fromdisk
|
||||
.. automethod:: pygit2.Repository.create_blob_fromiobase
|
||||
|
||||
There are also some functions to calculate the id for a byte string without
|
||||
creating the blob object:
|
||||
@ -176,6 +177,7 @@ Tree entries
|
||||
.. autoattribute:: pygit2.TreeEntry.id
|
||||
.. autoattribute:: pygit2.TreeEntry.hex
|
||||
.. autoattribute:: pygit2.TreeEntry.filemode
|
||||
.. autoattribute:: pygit2.TreeEntry.type
|
||||
|
||||
.. method:: TreeEntry.__cmp__(TreeEntry)
|
||||
|
||||
@ -188,14 +190,14 @@ Example::
|
||||
6
|
||||
|
||||
>>> for entry in tree: # Iteration
|
||||
... print(entry.id, entry.name)
|
||||
... print(entry.id, entry.type, entry.name)
|
||||
...
|
||||
7151ca7cd3e59f3eab19c485cfbf3cb30928d7fa .gitignore
|
||||
c36f4cf1e38ec1bb9d9ad146ed572b89ecfc9f18 COPYING
|
||||
32b30b90b062f66957d6790c3c155c289c34424e README.md
|
||||
c87dae4094b3a6d10e08bc6c5ef1f55a7e448659 pygit2.c
|
||||
85a67270a49ef16cdd3d328f06a3e4b459f09b27 setup.py
|
||||
3d8985bbec338eb4d47c5b01b863ee89d044bd53 test
|
||||
7151ca7cd3e59f3eab19c485cfbf3cb30928d7fa blob .gitignore
|
||||
c36f4cf1e38ec1bb9d9ad146ed572b89ecfc9f18 blob COPYING
|
||||
32b30b90b062f66957d6790c3c155c289c34424e blob README.md
|
||||
c87dae4094b3a6d10e08bc6c5ef1f55a7e448659 blob pygit2.c
|
||||
85a67270a49ef16cdd3d328f06a3e4b459f09b27 blob setup.py
|
||||
3d8985bbec338eb4d47c5b01b863ee89d044bd53 tree test
|
||||
|
||||
>>> entry = tree['pygit2.c'] # Get an entry by name
|
||||
>>> entry
|
||||
|
@ -17,10 +17,11 @@ Main porcelain commands
|
||||
.. toctree::
|
||||
:maxdepth: 1
|
||||
|
||||
git-branch (List, create, or delete branches.) <recipes/git-branch>
|
||||
git-cherry-pick (Apply the changes introduced by some existing commits.) <recipes/git-cherry-pick>
|
||||
git-init (Create an empty git repository or reinitialize an existing one.) <recipes/git-init>
|
||||
git-log (Show commit logs.) <recipes/git-log>
|
||||
git-show (Show various types of objects.) <recipes/git-show>
|
||||
git-tag (Create, list, delete or verify a tag object signed with GPG.) <recipes/git-tag>
|
||||
git clone --mirror (Clone with a mirroring configuration) <recipes/git-clone-mirror>
|
||||
|
||||
.. _git man page: https://www.kernel.org/pub/software/scm/git/docs/git.html
|
||||
|
@ -1,30 +0,0 @@
|
||||
**********************************************************************
|
||||
git-branch
|
||||
**********************************************************************
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Listing branches
|
||||
----------------------------------------------------------------------
|
||||
|
||||
======================================================================
|
||||
List all branches
|
||||
======================================================================
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$> git branch
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> regex = re.compile('^refs/heads/')
|
||||
>>> branches = filter(lambda r: regex.match(r), repo.listall_references())
|
||||
|
||||
`Note that the next release will probably allow` ``repo.listall_branches()``.
|
||||
|
||||
----------------------------------------------------------------------
|
||||
References
|
||||
----------------------------------------------------------------------
|
||||
|
||||
- git-branch_.
|
||||
|
||||
.. _git-branch: https://www.kernel.org/pub/software/scm/git/docs/git-branch.html
|
73
docs/recipes/git-cherry-pick.rst
Normal file
73
docs/recipes/git-cherry-pick.rst
Normal file
@ -0,0 +1,73 @@
|
||||
**********************************************************************
|
||||
git-cherry-pick
|
||||
**********************************************************************
|
||||
|
||||
The convenient way to cherry-pick a commit is to use
|
||||
:py:meth:`.Repository.cherrypick()`. It is limited to cherry-picking with a
|
||||
working copy and on-disk index.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$> cd /path/to/repo
|
||||
$> git checkout basket
|
||||
$> git cherry-pick 9e044d03c
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
repo = pygit2.Repository('/path/to/repo')
|
||||
repo.checkout('basket')
|
||||
|
||||
cherry_id = pygit2.Oid('9e044d03c')
|
||||
repo.cherrypick(cherry_id)
|
||||
|
||||
if repo.index.conflicts is None:
|
||||
tree_id = repo.index.write_tree()
|
||||
|
||||
cherry = repo.get(cherry_id)
|
||||
committer = pygit2.Signature('Archimedes', 'archy@jpl-classics.org')
|
||||
|
||||
repo.create_commit(basket.name, cherry.author, committer,
|
||||
cherry.message, tree_id, [basket.target])
|
||||
del basket # outdated, prevent from accidentally using it
|
||||
|
||||
repo.state_cleanup()
|
||||
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Cherry-picking a commit without a working copy
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This way of cherry-picking gives you more control over the process and works
|
||||
on bare repositories as well as repositories with a working copy.
|
||||
:py:meth:`~.Repository.merge_trees()` can also be used for other tasks, for
|
||||
example `three-argument rebases`_.
|
||||
|
||||
.. _`three-argument rebases`: https://www.kernel.org/pub/software/scm/git/docs/git-rebase.html
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
repo = pygit2.Repository('/path/to/repo')
|
||||
|
||||
cherry = repo.revparse_single('9e044d03c')
|
||||
basket = repo.branches.get('basket')
|
||||
|
||||
base = repo.merge_base(cherry.oid, basket.target)
|
||||
base_tree = cherry.parents[0].tree
|
||||
|
||||
index = repo.merge_trees(base_tree, basket, cherry)
|
||||
tree_id = index.write_tree(repo)
|
||||
|
||||
author = cherry.author
|
||||
committer = pygit2.Signature('Archimedes', 'archy@jpl-classics.org')
|
||||
|
||||
repo.create_commit(basket.name, author, committer, cherry.message,
|
||||
tree_id, [basket.target])
|
||||
del None # outdated, prevent from accidentally using it
|
||||
|
||||
----------------------------------------------------------------------
|
||||
References
|
||||
----------------------------------------------------------------------
|
||||
|
||||
- git-cherry-pick_.
|
||||
|
||||
.. _git-cherry-pick: https://www.kernel.org/pub/software/scm/git/docs/git-cherry-pick.html
|
26
docs/recipes/git-clone-mirror.rst
Normal file
26
docs/recipes/git-clone-mirror.rst
Normal file
@ -0,0 +1,26 @@
|
||||
**********************************************************************
|
||||
git-clone --mirror
|
||||
**********************************************************************
|
||||
|
||||
git provides an argument to set up the repository as a mirror, which
|
||||
involves setting the refspec to one which copies all refs and a mirror
|
||||
option for push in the remote.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$> git clone --mirror https://github.com/libgit2/pygit2
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def init_remote(repo, name, url):
|
||||
# Create the remote with a mirroring url
|
||||
remote = repo.remotes.create(name, url, "+refs/*:refs/*")
|
||||
# And set the configuration option to true for the push command
|
||||
mirror_var = "remote.{}.mirror".format(name)
|
||||
repo.config[mirror_var] = True
|
||||
# Return the remote, which pygit2 will use to perform the clone
|
||||
return remote
|
||||
|
||||
print("Cloning pygit2 as mirror")
|
||||
pygit2.clone_repository("https://github.com/libgit2/pygit2", "pygit2.git", bare=True,
|
||||
remote=init_remote)
|
@ -31,7 +31,7 @@ Show SHA hash
|
||||
Show diff
|
||||
======================================================================
|
||||
|
||||
>>> diff = commit.tree.diff()
|
||||
>>> diff = repo.diff(commit.parents[0], commit)
|
||||
|
||||
======================================================================
|
||||
Show all files in commit
|
||||
@ -40,6 +40,52 @@ Show all files in commit
|
||||
>>> for e in commit.tree:
|
||||
>>> print(e.name)
|
||||
|
||||
======================================================================
|
||||
Produce something like a ``git show`` message
|
||||
======================================================================
|
||||
|
||||
In order to display time zone information you have to create a subclass
|
||||
of tzinfo. In Python 3.2+ you can do this fairly directly. In older
|
||||
versions you have to make your own class as described in the `Python
|
||||
datetime documentation`_::
|
||||
|
||||
from datetime import tzinfo, timedelta
|
||||
class FixedOffset(tzinfo):
|
||||
"""Fixed offset in minutes east from UTC."""
|
||||
|
||||
def __init__(self, offset):
|
||||
self.__offset = timedelta(minutes = offset)
|
||||
|
||||
def utcoffset(self, dt):
|
||||
return self.__offset
|
||||
|
||||
def tzname(self, dt):
|
||||
return None # we don't know the time zone's name
|
||||
|
||||
def dst(self, dt):
|
||||
return timedelta(0) # we don't know about DST
|
||||
|
||||
.. _Python datetime documentation: https://docs.python.org/2/library/datetime.html#tzinfo-objects
|
||||
|
||||
Then you can make your message:
|
||||
|
||||
>>> # Until Python 2.7.9:
|
||||
>>> from __future__ import unicode_literals
|
||||
>>> from datetime import datetime
|
||||
>>> tzinfo = FixedOffset(commit.author.offset)
|
||||
|
||||
>>> # From Python 3.2:
|
||||
>>> from datetime import datetime, timezone, timedelta
|
||||
>>> tzinfo = timezone( timedelta(minutes=commit.author.offset) )
|
||||
>>>
|
||||
>>> dt = datetime.fromtimestamp(float(commit.author.time), tzinfo)
|
||||
>>> timestr = dt.strftime('%c %z')
|
||||
>>> msg = '\n'.join(['commit {}'.format(commit.tree_id.hex),
|
||||
... 'Author: {} <{}>'.format(commit.author.name, commit.author.email),
|
||||
... 'Date: {}'.format(timestr),
|
||||
... '',
|
||||
... commit.message])
|
||||
|
||||
----------------------------------------------------------------------
|
||||
References
|
||||
----------------------------------------------------------------------
|
||||
|
@ -4,29 +4,42 @@ References
|
||||
|
||||
.. contents::
|
||||
|
||||
.. automethod:: pygit2.Repository.listall_references
|
||||
.. automethod:: pygit2.Repository.lookup_reference
|
||||
.. autoclass:: pygit2.repository.References
|
||||
:members:
|
||||
:undoc-members:
|
||||
:special-members: __getitem__, __iter__, __contains__
|
||||
|
||||
|
||||
Example::
|
||||
|
||||
>>> all_refs = repo.listall_references()
|
||||
>>> all_refs = list(repo.references)
|
||||
|
||||
>>> master_ref = repo.lookup_reference("refs/heads/master")
|
||||
>>> commit = master_ref.get_object() # or repo[master_ref.target]
|
||||
|
||||
# Create a reference
|
||||
>>> ref = repo.references.create('refs/tags/version1', LAST_COMMIT)
|
||||
|
||||
# Delete a reference
|
||||
>>> repo.references.delete('refs/tags/version1')
|
||||
|
||||
|
||||
The Reference type
|
||||
====================
|
||||
|
||||
.. autoclass:: pygit2.Reference
|
||||
|
||||
.. autoattribute:: pygit2.Reference.name
|
||||
.. autoattribute:: pygit2.Reference.shorthand
|
||||
.. autoattribute:: pygit2.Reference.target
|
||||
.. autoattribute:: pygit2.Reference.type
|
||||
|
||||
.. automethod:: pygit2.Reference.set_target
|
||||
.. automethod:: pygit2.Reference.delete
|
||||
.. automethod:: pygit2.Reference.rename
|
||||
.. automethod:: pygit2.Reference.resolve
|
||||
.. automethod:: pygit2.Reference.peel
|
||||
.. automethod:: pygit2.Reference.log
|
||||
.. automethod:: pygit2.Reference.log_append
|
||||
|
||||
Example::
|
||||
|
||||
@ -65,28 +78,33 @@ Branches
|
||||
Branches inherit from References, and additionally provide specialized
|
||||
accessors for some unique features.
|
||||
|
||||
.. automethod:: pygit2.Repository.listall_branches
|
||||
.. automethod:: pygit2.Repository.lookup_branch
|
||||
.. automethod:: pygit2.Repository.create_branch
|
||||
.. autoclass:: pygit2.repository.Branches
|
||||
:members:
|
||||
:undoc-members:
|
||||
:special-members: __getitem__, __iter__, __contains__
|
||||
|
||||
Example::
|
||||
|
||||
>>> local_branches = repo.listall_branches()
|
||||
>>> # equivalent to
|
||||
>>> local_branches = repo.listall_branches(pygit2.GIT_BRANCH_LOCAL)
|
||||
>>> # Listing all branches
|
||||
>>> branches_list = list(repo.branches)
|
||||
>>> # Local only
|
||||
>>> local_branches = list(repo.branches.local)
|
||||
>>> # Remote only
|
||||
>>> remote_branches = list(repo.branches.remote)
|
||||
|
||||
>>> remote_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE)
|
||||
>>> # Get a branch
|
||||
>>> branch = repo.branches['master']
|
||||
>>> other_branch = repo.branches['does-not-exist'] # Will raise a KeyError
|
||||
>>> other_branch = repo.branches.get('does-not-exist') # Returns None
|
||||
|
||||
>>> all_branches = repo.listall_branches(pygit2.GIT_BRANCH_REMOTE |
|
||||
pygit2.GIT_BRANCH_LOCAL)
|
||||
>>> remote_branch = repo.branches.remote['upstream/feature']
|
||||
|
||||
>>> master_branch = repo.lookup_branch('master')
|
||||
>>> # equivalent to
|
||||
>>> master_branch = repo.lookup_branch('master',
|
||||
pygit2.GIT_BRANCH_LOCAL)
|
||||
>>> # Create a local branch
|
||||
>>> new_branch = repo.branches.local.create('new-branch')
|
||||
|
||||
>>> And delete it
|
||||
>>> repo.branches.delete('new-branch')
|
||||
|
||||
>>> remote_branch = repo.lookup_branch('upstream/feature',
|
||||
pygit2.GIT_BRANCH_REMOTE)
|
||||
|
||||
The Branch type
|
||||
====================
|
||||
@ -95,17 +113,19 @@ The Branch type
|
||||
.. autoattribute:: pygit2.Branch.remote_name
|
||||
.. autoattribute:: pygit2.Branch.upstream
|
||||
.. autoattribute:: pygit2.Branch.upstream_name
|
||||
|
||||
.. automethod:: pygit2.Branch.rename
|
||||
.. automethod:: pygit2.Branch.delete
|
||||
.. automethod:: pygit2.Branch.is_head
|
||||
.. automethod:: pygit2.Branch.is_checked_out
|
||||
|
||||
The reference log
|
||||
====================
|
||||
|
||||
Example::
|
||||
|
||||
>>> head = repo.lookup_reference('refs/heads/master')
|
||||
>>> head = repo.references.get('refs/heads/master') # Returns None if not found
|
||||
>>> # Almost equivalent to
|
||||
>>> head = repo.references['refs/heads/master'] # Raises KeyError if not found
|
||||
>>> for entry in head.log():
|
||||
... print(entry.message)
|
||||
|
||||
|
@ -2,10 +2,18 @@
|
||||
Remotes
|
||||
**********************************************************************
|
||||
|
||||
.. py:attribute:: Repository.remotes
|
||||
|
||||
The collection of configured remotes, an instance of
|
||||
:py:class:`pygit2.remote.RemoteCollection`
|
||||
|
||||
.. autoattribute:: pygit2.Repository.remotes
|
||||
.. automethod:: pygit2.Repository.create_remote
|
||||
|
||||
The remote collection
|
||||
==========================
|
||||
|
||||
.. autoclass:: pygit2.remote.RemoteCollection
|
||||
:members:
|
||||
|
||||
The Remote type
|
||||
====================
|
||||
@ -13,6 +21,12 @@ The Remote type
|
||||
.. autoclass:: pygit2.Remote
|
||||
:members:
|
||||
|
||||
The RemoteCallbacks type
|
||||
========================
|
||||
|
||||
.. autoclass:: pygit2.RemoteCallbacks
|
||||
:members:
|
||||
|
||||
The TransferProgress type
|
||||
===========================
|
||||
|
||||
@ -24,14 +38,16 @@ This class contains the data which is available to us during a fetch.
|
||||
The Refspec type
|
||||
===================
|
||||
|
||||
Refspecs objects are not constructed directly, but returned by
|
||||
:meth:`pygit2.Remote.get_refspec`. To create a new a refspec on a Remote, use
|
||||
:meth:`pygit2.Remote.add_fetch` or :meth:`pygit2.Remote.add_push`.
|
||||
|
||||
.. autoclass:: pygit2.refspec.Refspec
|
||||
:members:
|
||||
|
||||
Credentials
|
||||
================
|
||||
|
||||
.. automethod:: pygit2.Remote.credentials
|
||||
|
||||
There are two types of credentials: username/password and SSH key
|
||||
pairs. Both :py:class:`pygit2.UserPass` and :py:class:`pygit2.Keypair`
|
||||
are callable objects, with the appropriate signature for the
|
||||
|
@ -67,5 +67,11 @@ Below there are some general attributes and methods:
|
||||
.. autoattribute:: pygit2.Repository.default_signature
|
||||
.. automethod:: pygit2.Repository.read
|
||||
.. automethod:: pygit2.Repository.write
|
||||
.. automethod:: pygit2.Repository.ahead_behind
|
||||
.. automethod:: pygit2.Repository.create_reference
|
||||
.. automethod:: pygit2.Repository.describe
|
||||
.. automethod:: pygit2.Repository.path_is_ignored
|
||||
.. automethod:: pygit2.Repository.reset
|
||||
.. automethod:: pygit2.Repository.revert_commit
|
||||
.. automethod:: pygit2.Repository.state_cleanup
|
||||
.. automethod:: pygit2.Repository.write_archive
|
||||
|
21
docs/submodule.rst
Normal file
21
docs/submodule.rst
Normal file
@ -0,0 +1,21 @@
|
||||
**********************************************************************
|
||||
Submodules
|
||||
**********************************************************************
|
||||
|
||||
A submodule is a foreign repository that is embedded within a
|
||||
dedicated subdirectory of the repositories tree.
|
||||
|
||||
.. automethod:: pygit2.Repository.init_submodules
|
||||
.. automethod:: pygit2.Repository.update_submodules
|
||||
.. automethod:: pygit2.Repository.lookup_submodule
|
||||
.. automethod:: pygit2.Repository.listall_submodules
|
||||
|
||||
The Submodule type
|
||||
====================
|
||||
|
||||
.. automethod:: pygit2.Submodule.open
|
||||
|
||||
.. autoattribute:: pygit2.Submodule.name
|
||||
.. autoattribute:: pygit2.Submodule.path
|
||||
.. autoattribute:: pygit2.Submodule.url
|
||||
.. autoattribute:: pygit2.Submodule.branch
|
@ -19,7 +19,7 @@ Iterate over all entries of the index::
|
||||
Index write::
|
||||
|
||||
>>> index.add('path/to/file') # git add
|
||||
>>> del index['path/to/file'] # git rm
|
||||
>>> index.remove('path/to/file') # git rm
|
||||
>>> index.write() # don't forget to save the changes
|
||||
|
||||
Custom entries::
|
||||
@ -71,3 +71,11 @@ Lower level API:
|
||||
.. automethod:: pygit2.Repository.checkout_head
|
||||
.. automethod:: pygit2.Repository.checkout_tree
|
||||
.. automethod:: pygit2.Repository.checkout_index
|
||||
|
||||
Stash
|
||||
====================
|
||||
|
||||
.. automethod:: pygit2.Repository.stash
|
||||
.. automethod:: pygit2.Repository.stash_apply
|
||||
.. automethod:: pygit2.Repository.stash_drop
|
||||
.. automethod:: pygit2.Repository.stash_pop
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -32,20 +32,48 @@ from __future__ import absolute_import
|
||||
from _pygit2 import *
|
||||
|
||||
# High level API
|
||||
from .blame import Blame, BlameHunk
|
||||
from .config import Config
|
||||
from .credentials import *
|
||||
from .errors import check_error
|
||||
from .errors import check_error, Passthrough
|
||||
from .ffi import ffi, C
|
||||
from .index import Index, IndexEntry
|
||||
from .remote import Remote, get_credentials
|
||||
from .remote import Remote, RemoteCallbacks, get_credentials
|
||||
from .repository import Repository
|
||||
from .settings import Settings
|
||||
from .utils import to_bytes
|
||||
from .version import __version__
|
||||
from .submodule import Submodule
|
||||
from .utils import to_bytes, to_str
|
||||
from ._build import __version__
|
||||
|
||||
|
||||
# Features
|
||||
features = C.git_libgit2_features()
|
||||
GIT_FEATURE_THREADS = C.GIT_FEATURE_THREADS
|
||||
GIT_FEATURE_HTTPS = C.GIT_FEATURE_HTTPS
|
||||
GIT_FEATURE_SSH = C.GIT_FEATURE_SSH
|
||||
|
||||
# GIT_REPOSITORY_INIT_*
|
||||
GIT_REPOSITORY_INIT_OPTIONS_VERSION = C.GIT_REPOSITORY_INIT_OPTIONS_VERSION
|
||||
GIT_REPOSITORY_INIT_BARE = C.GIT_REPOSITORY_INIT_BARE
|
||||
GIT_REPOSITORY_INIT_NO_REINIT = C.GIT_REPOSITORY_INIT_NO_REINIT
|
||||
GIT_REPOSITORY_INIT_NO_DOTGIT_DIR = C.GIT_REPOSITORY_INIT_NO_DOTGIT_DIR
|
||||
GIT_REPOSITORY_INIT_MKDIR = C.GIT_REPOSITORY_INIT_MKDIR
|
||||
GIT_REPOSITORY_INIT_MKPATH = C.GIT_REPOSITORY_INIT_MKPATH
|
||||
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE = C.GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK = C.GIT_REPOSITORY_INIT_RELATIVE_GITLINK
|
||||
GIT_REPOSITORY_INIT_SHARED_UMASK = C.GIT_REPOSITORY_INIT_SHARED_UMASK
|
||||
GIT_REPOSITORY_INIT_SHARED_GROUP = C.GIT_REPOSITORY_INIT_SHARED_GROUP
|
||||
GIT_REPOSITORY_INIT_SHARED_ALL = C.GIT_REPOSITORY_INIT_SHARED_ALL
|
||||
|
||||
# GIT_ATTR_CHECK_*
|
||||
GIT_ATTR_CHECK_FILE_THEN_INDEX = C.GIT_ATTR_CHECK_FILE_THEN_INDEX
|
||||
GIT_ATTR_CHECK_INDEX_THEN_FILE = C.GIT_ATTR_CHECK_INDEX_THEN_FILE
|
||||
GIT_ATTR_CHECK_INDEX_ONLY = C.GIT_ATTR_CHECK_INDEX_ONLY
|
||||
GIT_ATTR_CHECK_NO_SYSTEM = C.GIT_ATTR_CHECK_NO_SYSTEM
|
||||
|
||||
|
||||
def init_repository(path, bare=False,
|
||||
flags=C.GIT_REPOSITORY_INIT_MKPATH,
|
||||
flags=GIT_REPOSITORY_INIT_MKPATH,
|
||||
mode=0,
|
||||
workdir_path=None,
|
||||
description=None,
|
||||
@ -77,19 +105,38 @@ def init_repository(path, bare=False,
|
||||
See libgit2's documentation on git_repository_init_ext for further details.
|
||||
"""
|
||||
# Pre-process input parameters
|
||||
if path is None:
|
||||
raise TypeError('Expected string type for path, found None.')
|
||||
|
||||
if bare:
|
||||
flags |= C.GIT_REPOSITORY_INIT_BARE
|
||||
flags |= GIT_REPOSITORY_INIT_BARE
|
||||
|
||||
# Options
|
||||
options = ffi.new('git_repository_init_options *')
|
||||
options.version = 1
|
||||
C.git_repository_init_init_options(options,
|
||||
GIT_REPOSITORY_INIT_OPTIONS_VERSION)
|
||||
options.flags = flags
|
||||
options.mode = mode
|
||||
options.workdir_path = to_bytes(workdir_path)
|
||||
options.description = to_bytes(description)
|
||||
options.template_path = to_bytes(template_path)
|
||||
options.initial_head = to_bytes(initial_head)
|
||||
options.origin_url = to_bytes(origin_url)
|
||||
|
||||
if workdir_path:
|
||||
workdir_path_ref = ffi.new('char []', to_bytes(workdir_path))
|
||||
options.workdir_path = workdir_path_ref
|
||||
|
||||
if description:
|
||||
description_ref = ffi.new('char []', to_bytes(description))
|
||||
options.description = description_ref
|
||||
|
||||
if template_path:
|
||||
template_path_ref = ffi.new('char []', to_bytes(template_path))
|
||||
options.template_path = template_path_ref
|
||||
|
||||
if initial_head:
|
||||
initial_head_ref = ffi.new('char []', to_bytes(initial_head))
|
||||
options.initial_head = initial_head_ref
|
||||
|
||||
if origin_url:
|
||||
origin_url_ref = ffi.new('char []', to_bytes(origin_url))
|
||||
options.origin_url = origin_url_ref
|
||||
|
||||
# Call
|
||||
crepository = ffi.new('git_repository **')
|
||||
@ -97,28 +144,41 @@ def init_repository(path, bare=False,
|
||||
check_error(err)
|
||||
|
||||
# Ok
|
||||
return Repository(path)
|
||||
return Repository(to_str(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):
|
||||
@ffi.callback('int (*git_repository_create_cb)(git_repository **out,'
|
||||
'const char *path, int bare, void *payload)')
|
||||
def _repository_create_cb(repo_out, path, bare, data):
|
||||
d = ffi.from_handle(data)
|
||||
|
||||
try:
|
||||
ccred = get_credentials(d['callback'], url, username_from_url, allowed)
|
||||
cred_out[0] = ccred[0]
|
||||
repository = d['repository_cb'](ffi.string(path), bare != 0)
|
||||
# we no longer own the C object
|
||||
repository._disown()
|
||||
repo_out[0] = repository._repo
|
||||
except Exception as e:
|
||||
d['exception'] = e
|
||||
return C.GIT_EUSER
|
||||
|
||||
return 0
|
||||
|
||||
@ffi.callback('int (*git_remote_create_cb)(git_remote **out, git_repository *repo,'
|
||||
'const char *name, const char *url, void *payload)')
|
||||
def _remote_create_cb(remote_out, repo, name, url, data):
|
||||
d = ffi.from_handle(data)
|
||||
try:
|
||||
remote = d['remote_cb'](Repository._from_c(repo, False), ffi.string(name), ffi.string(url))
|
||||
remote_out[0] = remote._remote
|
||||
# we no longer own the C object
|
||||
remote._remote = ffi.NULL
|
||||
except Exception as e:
|
||||
d['exception'] = e
|
||||
return C.GIT_EUSER
|
||||
|
||||
return 0
|
||||
|
||||
def clone_repository(
|
||||
url, path, bare=False, ignore_cert_errors=False,
|
||||
remote_name="origin", checkout_branch=None, credentials=None):
|
||||
url, path, bare=False, repository=None, remote=None,
|
||||
checkout_branch=None, callbacks=None):
|
||||
"""Clones a new Git repository from *url* in the given *path*.
|
||||
|
||||
Returns a Repository class pointing to the newly cloned repository.
|
||||
@ -129,16 +189,29 @@ def clone_repository(
|
||||
|
||||
:param bool bare: Whether the local repository should be bare
|
||||
|
||||
:param str remote_name: Name to give the remote at *url*.
|
||||
:param callable remote: Callback for the remote to use.
|
||||
|
||||
:param callable repository: Callback for the repository to use.
|
||||
|
||||
:param str checkout_branch: Branch to checkout after the
|
||||
clone. The default is to use the remote's default branch.
|
||||
|
||||
:param callable credentials: authentication to use if the remote
|
||||
requires it
|
||||
:param RemoteCallbacks callbacks: object which implements the
|
||||
callbacks as methods.
|
||||
|
||||
:rtype: Repository
|
||||
|
||||
The repository callback has `(path, bare) -> Repository` as a
|
||||
signature. The Repository it returns will be used instead of
|
||||
creating a new one.
|
||||
|
||||
The remote callback has `(Repository, name, url) -> Remote` as a
|
||||
signature. The Remote it returns will be used instead of the default
|
||||
one.
|
||||
|
||||
The callbacks should be an object which inherits from
|
||||
`pyclass:RemoteCallbacks`.
|
||||
|
||||
"""
|
||||
|
||||
opts = ffi.new('git_clone_options *')
|
||||
@ -148,60 +221,42 @@ def clone_repository(
|
||||
|
||||
# Data, let's use a dict as we don't really want much more
|
||||
d = {}
|
||||
d['callback'] = credentials
|
||||
d['repository_cb'] = repository
|
||||
d['remote_cb'] = remote
|
||||
d_handle = ffi.new_handle(d)
|
||||
|
||||
# Perform the initialization with the version we compiled
|
||||
C.git_clone_init_options(opts, C.GIT_CLONE_OPTIONS_VERSION)
|
||||
|
||||
# We need to keep the ref alive ourselves
|
||||
checkout_branch_ref = None
|
||||
if branch:
|
||||
checkout_branch_ref = ffi.new('char []', branch)
|
||||
checkout_branch_ref = ffi.new('char []', to_bytes(branch))
|
||||
opts.checkout_branch = checkout_branch_ref
|
||||
|
||||
remote_name_ref = ffi.new('char []', to_bytes(remote_name))
|
||||
opts.remote_name = remote_name_ref
|
||||
if repository:
|
||||
opts.repository_cb = _repository_create_cb
|
||||
opts.repository_cb_payload = d_handle
|
||||
|
||||
if remote:
|
||||
opts.remote_cb = _remote_create_cb
|
||||
opts.remote_cb_payload = d_handle
|
||||
|
||||
|
||||
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
|
||||
|
||||
if callbacks is None:
|
||||
callbacks = RemoteCallbacks()
|
||||
|
||||
callbacks._fill_fetch_options(opts.fetch_opts)
|
||||
|
||||
err = C.git_clone(crepo, to_bytes(url), to_bytes(path), opts)
|
||||
C.git_repository_free(crepo[0])
|
||||
|
||||
if 'exception' in d:
|
||||
raise d['exception']
|
||||
|
||||
check_error(err)
|
||||
|
||||
return Repository(path)
|
||||
|
||||
|
||||
def clone_into(repo, remote, branch=None):
|
||||
"""Clone into an empty repository from the specified remote
|
||||
|
||||
:param Repository repo: The empty repository into which to clone
|
||||
|
||||
:param Remote remote: The remote from which to clone
|
||||
|
||||
:param str branch: Branch to checkout after the clone. Pass None
|
||||
to use the remotes's default branch.
|
||||
|
||||
This allows you specify arbitrary repository and remote configurations
|
||||
before performing the clone step itself. E.g. you can replicate git-clone's
|
||||
'--mirror' option by setting a refspec of '+refs/*:refs/*', 'core.mirror'
|
||||
to true and calling this function.
|
||||
"""
|
||||
|
||||
err = C.git_clone_into(repo._repo, remote._remote, ffi.NULL,
|
||||
to_bytes(branch), ffi.NULL)
|
||||
|
||||
if remote._stored_exception:
|
||||
raise remote._stored_exception
|
||||
|
||||
check_error(err)
|
||||
return Repository._from_c(crepo[0], owned=True)
|
||||
|
||||
settings = Settings()
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -25,20 +25,40 @@
|
||||
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
"""Tests for reference log."""
|
||||
"""
|
||||
This is an special module, it provides stuff used by setup.py at build time.
|
||||
But also used by pygit2 at run time.
|
||||
"""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
# Import from the Standard Library
|
||||
import os
|
||||
from os import getenv
|
||||
|
||||
from pygit2 import Signature
|
||||
from . import utils
|
||||
#
|
||||
# The version number of pygit2
|
||||
#
|
||||
__version__ = '0.26.0'
|
||||
|
||||
|
||||
class ReflogTest(utils.RepoTestCase):
|
||||
#
|
||||
# Utility functions to get the paths required for bulding extensions
|
||||
#
|
||||
def _get_libgit2_path():
|
||||
# LIBGIT2 environment variable takes precedence
|
||||
libgit2_path = getenv("LIBGIT2")
|
||||
if libgit2_path is not None:
|
||||
return libgit2_path
|
||||
|
||||
def test_log_append(self):
|
||||
repo = self.repo
|
||||
master = repo.lookup_reference("refs/heads/master")
|
||||
signature = Signature('xtao', 'xutao@douban.com')
|
||||
master.log_append(None, signature, 'reflog')
|
||||
self.assertTrue('reflog' in [entry.message for entry in master.log()])
|
||||
# Default
|
||||
if os.name == 'nt':
|
||||
return '%s\libgit2' % getenv("ProgramFiles")
|
||||
return '/usr/local'
|
||||
|
||||
|
||||
def get_libgit2_paths():
|
||||
libgit2_path = _get_libgit2_path()
|
||||
return (
|
||||
os.path.join(libgit2_path, 'bin'),
|
||||
os.path.join(libgit2_path, 'include'),
|
||||
getenv('LIBGIT2_LIB', os.path.join(libgit2_path, 'lib')),
|
||||
)
|
76
pygit2/_run.py
Normal file
76
pygit2/_run.py
Normal file
@ -0,0 +1,76 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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.
|
||||
|
||||
"""
|
||||
This is an special module, it provides stuff used by by pygit2 at run-time.
|
||||
"""
|
||||
|
||||
# Import from the Standard Library
|
||||
import codecs
|
||||
import os
|
||||
from os.path import abspath, dirname
|
||||
import sys
|
||||
|
||||
# Import from cffi
|
||||
from cffi import FFI
|
||||
|
||||
# Import from pygit2
|
||||
from _build import get_libgit2_paths
|
||||
|
||||
|
||||
# C_HEADER_SRC
|
||||
if getattr(sys, 'frozen', False):
|
||||
dir_path = getattr(sys, '_MEIPASS', None)
|
||||
if dir_path is None:
|
||||
dir_path = dirname(abspath(sys.executable))
|
||||
else:
|
||||
dir_path = dirname(abspath(__file__))
|
||||
|
||||
decl_path = os.path.join(dir_path, 'decl.h')
|
||||
with codecs.open(decl_path, 'r', 'utf-8') as header:
|
||||
C_HEADER_SRC = header.read()
|
||||
|
||||
# C_KEYWORDS
|
||||
libgit2_bin, libgit2_include, libgit2_lib = get_libgit2_paths()
|
||||
C_KEYWORDS = dict(libraries=['git2'],
|
||||
library_dirs=[libgit2_lib],
|
||||
include_dirs=[libgit2_include])
|
||||
|
||||
# preamble
|
||||
preamble = "#include <git2.h>"
|
||||
|
||||
# ffi
|
||||
ffi = FFI()
|
||||
set_source = getattr(ffi, 'set_source', None)
|
||||
if set_source is not None:
|
||||
set_source("pygit2._libgit2", preamble, **C_KEYWORDS)
|
||||
|
||||
ffi.cdef(C_HEADER_SRC)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ffi.compile()
|
146
pygit2/blame.py
Normal file
146
pygit2/blame.py
Normal file
@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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
|
||||
|
||||
# Import from pygit2
|
||||
from .errors import check_error
|
||||
from .ffi import ffi, C
|
||||
from .utils import to_bytes, is_string, to_str
|
||||
from .utils import GenericIterator
|
||||
from _pygit2 import Signature, Oid
|
||||
|
||||
|
||||
def wrap_signature(csig):
|
||||
if not csig:
|
||||
return None
|
||||
|
||||
return Signature(ffi.string(csig.name).decode('utf-8'),
|
||||
ffi.string(csig.email).decode('utf-8'),
|
||||
csig.when.time, csig.when.offset, 'utf-8')
|
||||
|
||||
class BlameHunk(object):
|
||||
|
||||
@classmethod
|
||||
def _from_c(cls, blame, ptr):
|
||||
hunk = cls.__new__(cls)
|
||||
hunk._blame = blame
|
||||
hunk._hunk = ptr
|
||||
return hunk
|
||||
|
||||
@property
|
||||
def lines_in_hunk(self):
|
||||
"""Number of lines"""
|
||||
return self._hunk.lines_in_hunk
|
||||
|
||||
@property
|
||||
def boundary(self):
|
||||
"""Tracked to a boundary commit"""
|
||||
# Casting directly to bool via cffi does not seem to work
|
||||
return int(ffi.cast('int', self._hunk.boundary)) != 0
|
||||
|
||||
@property
|
||||
def final_start_line_number(self):
|
||||
"""Final start line number"""
|
||||
return self._hunk.final_start_line_number
|
||||
|
||||
@property
|
||||
def final_committer(self):
|
||||
"""Final committer"""
|
||||
return wrap_signature(self._hunk.final_signature)
|
||||
|
||||
@property
|
||||
def final_commit_id(self):
|
||||
return Oid(raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'final_commit_id'))[:]))
|
||||
|
||||
@property
|
||||
def orig_start_line_number(self):
|
||||
"""Origin start line number"""
|
||||
return self._hunk.orig_start_line_number
|
||||
|
||||
@property
|
||||
def orig_committer(self):
|
||||
"""Original committer"""
|
||||
return wrap_signature(self._hunk.orig_signature)
|
||||
|
||||
@property
|
||||
def orig_commit_id(self):
|
||||
return Oid(raw=bytes(ffi.buffer(ffi.addressof(self._hunk, 'orig_commit_id'))[:]))
|
||||
|
||||
@property
|
||||
def orig_path(self):
|
||||
"""Original path"""
|
||||
path = self._hunk.orig_path
|
||||
if not path:
|
||||
return None
|
||||
|
||||
return ffi.string(path).decode()
|
||||
|
||||
|
||||
class Blame(object):
|
||||
|
||||
@classmethod
|
||||
def _from_c(cls, repo, ptr):
|
||||
blame = cls.__new__(cls)
|
||||
blame._repo = repo
|
||||
blame._blame = ptr
|
||||
return blame
|
||||
|
||||
def __del__(self):
|
||||
C.git_blame_free(self._blame)
|
||||
|
||||
def __len__(self):
|
||||
return C.git_blame_get_hunk_count(self._blame)
|
||||
|
||||
def __getitem__(self, index):
|
||||
chunk = C.git_blame_get_hunk_byindex(self._blame, index)
|
||||
if not chunk:
|
||||
raise IndexError
|
||||
|
||||
return BlameHunk._from_c(self, chunk)
|
||||
|
||||
def for_line(self, line_no):
|
||||
"""Returns the <BlameHunk> object for a given line given its number
|
||||
in the current Blame.
|
||||
|
||||
Arguments:
|
||||
|
||||
line_no
|
||||
Line number, starts at 1.
|
||||
"""
|
||||
if line_no < 0:
|
||||
raise IndexError
|
||||
|
||||
chunk = C.git_blame_get_hunk_byline(self._blame, line_no)
|
||||
if not chunk:
|
||||
raise IndexError
|
||||
|
||||
return BlameHunk._from_c(self, chunk)
|
||||
|
||||
def __iter__(self):
|
||||
return GenericIterator(self)
|
110
pygit2/config.py
110
pygit2/config.py
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -63,15 +63,12 @@ class ConfigIterator(object):
|
||||
|
||||
def __next__(self):
|
||||
entry = self._next_entry()
|
||||
name = ffi.string(entry.name).decode('utf-8')
|
||||
|
||||
return name
|
||||
return ffi.string(entry.name).decode('utf-8')
|
||||
|
||||
|
||||
class ConfigMultivarIterator(ConfigIterator):
|
||||
def __next__(self):
|
||||
entry = self._next_entry()
|
||||
|
||||
return ffi.string(entry.value).decode('utf-8')
|
||||
|
||||
|
||||
@ -104,19 +101,19 @@ class Config(object):
|
||||
def _get(self, key):
|
||||
assert_string(key, "key")
|
||||
|
||||
cstr = ffi.new('char **')
|
||||
err = C.git_config_get_string(cstr, self._config, to_bytes(key))
|
||||
entry = ffi.new('git_config_entry **')
|
||||
err = C.git_config_get_entry(entry, self._config, to_bytes(key))
|
||||
|
||||
return err, cstr
|
||||
return err, ConfigEntry._from_c(entry[0])
|
||||
|
||||
def _get_string(self, key):
|
||||
err, cstr = self._get(key)
|
||||
def _get_entry(self, key):
|
||||
err, entry = self._get(key)
|
||||
|
||||
if err == C.GIT_ENOTFOUND:
|
||||
raise KeyError(key)
|
||||
|
||||
check_error(err)
|
||||
return cstr[0]
|
||||
return entry
|
||||
|
||||
def __contains__(self, key):
|
||||
err, cstr = self._get(key)
|
||||
@ -129,9 +126,9 @@ class Config(object):
|
||||
return True
|
||||
|
||||
def __getitem__(self, key):
|
||||
val = self._get_string(key)
|
||||
entry = self._get_entry(key)
|
||||
|
||||
return ffi.string(val).decode('utf-8')
|
||||
return ffi.string(entry.value).decode('utf-8')
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
assert_string(key, "key")
|
||||
@ -161,12 +158,11 @@ class Config(object):
|
||||
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."""
|
||||
"""Get each value of a multivar ''name'' as a list of strings.
|
||||
|
||||
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 **')
|
||||
@ -178,11 +174,9 @@ class Config(object):
|
||||
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"""
|
||||
|
||||
"""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")
|
||||
@ -192,53 +186,48 @@ class Config(object):
|
||||
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
|
||||
"""Look up *key* and parse its value as a boolean as per the git-config
|
||||
rules. Return a boolean value (True or False).
|
||||
|
||||
Truthy values are: 'true', 1, 'on' or 'yes'. Falsy values are: 'false',
|
||||
0, 'off' and 'no'"""
|
||||
0, 'off' and 'no'
|
||||
"""
|
||||
|
||||
val = self._get_string(key)
|
||||
entry = self._get_entry(key)
|
||||
res = ffi.new('int *')
|
||||
err = C.git_config_parse_bool(res, val)
|
||||
err = C.git_config_parse_bool(res, entry.value)
|
||||
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.
|
||||
"""Look up *key* and parse its value as an integer as per the git-config
|
||||
rules. Return an integer.
|
||||
|
||||
A value can have a suffix 'k', 'm' or 'g' which stand for 'kilo',
|
||||
'mega' and 'giga' respectively"""
|
||||
'mega' and 'giga' respectively.
|
||||
"""
|
||||
|
||||
val = self._get_string(key)
|
||||
entry = self._get_entry(key)
|
||||
res = ffi.new('int64_t *')
|
||||
err = C.git_config_parse_int64(res, val)
|
||||
err = C.git_config_parse_int64(res, entry.value)
|
||||
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."""
|
||||
"""Add a config file instance to an existing config."""
|
||||
|
||||
err = C.git_config_add_file_ondisk(self._config, to_bytes(path), level,
|
||||
force)
|
||||
check_error(err)
|
||||
|
||||
def snapshot(self):
|
||||
"""Create a snapshot from this Config object
|
||||
"""Create a snapshot from this Config object.
|
||||
|
||||
This means that looking up multiple values will use the same version
|
||||
of the configuration files
|
||||
of the configuration files.
|
||||
"""
|
||||
|
||||
ccfg = ffi.new('git_config **')
|
||||
err = C.git_config_snapshot(ccfg, self._config)
|
||||
check_error(err)
|
||||
@ -281,24 +270,35 @@ class Config(object):
|
||||
|
||||
@staticmethod
|
||||
def get_system_config():
|
||||
"""get_system_config() -> Config
|
||||
|
||||
Return an object representing the system configuration file."""
|
||||
|
||||
"""Return a <Config> 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 a <Config> 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 a <Config> object representing the global configuration file.
|
||||
"""
|
||||
return Config._from_found_config(C.git_config_find_xdg)
|
||||
|
||||
class ConfigEntry(object):
|
||||
"""An entry in a configuation object
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def _from_c(cls, ptr):
|
||||
entry = cls.__new__(cls)
|
||||
entry._entry = ptr
|
||||
return entry
|
||||
|
||||
def __del__(self):
|
||||
C.git_config_entry_free(self._entry)
|
||||
|
||||
@property
|
||||
def value(self):
|
||||
return self._entry.value
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -36,7 +36,6 @@ class UserPass(object):
|
||||
|
||||
This is an object suitable for passing to a remote's credentials
|
||||
callback and for returning from said callback.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, username, password):
|
||||
@ -61,6 +60,12 @@ class Keypair(object):
|
||||
This is an object suitable for passing to a remote's credentials
|
||||
callback and for returning from said callback.
|
||||
|
||||
:param str username: the username being used to authenticate with the
|
||||
remote server
|
||||
:param str pubkey: the path to the user's public key file
|
||||
:param str privkey: the path to the user's private key file
|
||||
:param str passphrase: the password used to decrypt the private key file,
|
||||
or empty string if no passphrase is required.
|
||||
"""
|
||||
|
||||
def __init__(self, username, pubkey, privkey, passphrase):
|
||||
@ -79,3 +84,8 @@ class Keypair(object):
|
||||
|
||||
def __call__(self, _url, _username, _allowed):
|
||||
return self
|
||||
|
||||
|
||||
class KeypairFromAgent(Keypair):
|
||||
def __init__(self, username):
|
||||
super(KeypairFromAgent, self).__init__(username, None, None, None)
|
||||
|
591
pygit2/decl.h
591
pygit2/decl.h
@ -1,11 +1,12 @@
|
||||
typedef ... git_repository;
|
||||
typedef ... git_submodule;
|
||||
typedef ... git_remote;
|
||||
typedef ... git_transport;
|
||||
typedef ... git_refspec;
|
||||
typedef ... git_push;
|
||||
typedef ... git_cred;
|
||||
typedef ... git_object;
|
||||
typedef ... git_tree;
|
||||
typedef ... git_signature;
|
||||
typedef ... git_commit;
|
||||
typedef ... git_index;
|
||||
typedef ... git_diff;
|
||||
typedef ... git_index_conflict_iterator;
|
||||
@ -29,6 +30,14 @@ typedef struct git_strarray {
|
||||
} git_strarray;
|
||||
|
||||
typedef int64_t git_off_t;
|
||||
typedef int64_t git_time_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_REF_INVALID = 0,
|
||||
GIT_REF_OID = 1,
|
||||
GIT_REF_SYMBOLIC = 2,
|
||||
GIT_REF_LISTALL = 3,
|
||||
} git_ref_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_OK = 0,
|
||||
@ -43,8 +52,18 @@ typedef enum {
|
||||
GIT_EUNMERGED = -10,
|
||||
GIT_ENONFASTFORWARD = -11,
|
||||
GIT_EINVALIDSPEC = -12,
|
||||
GIT_EMERGECONFLICT = -13,
|
||||
GIT_ECONFLICT = -13,
|
||||
GIT_ELOCKED = -14,
|
||||
GIT_EMODIFIED = -15,
|
||||
GIT_EAUTH = -16,
|
||||
GIT_ECERTIFICATE = -17,
|
||||
GIT_EAPPLIED = -18,
|
||||
GIT_EPEEL = -19,
|
||||
GIT_EEOF = -20,
|
||||
GIT_EINVALID = -21,
|
||||
GIT_EUNCOMMITTED = -22,
|
||||
GIT_EDIRECTORY = -23,
|
||||
GIT_EMERGECONFLICT = -24,
|
||||
|
||||
GIT_PASSTHROUGH = -30,
|
||||
GIT_ITEROVER = -31,
|
||||
@ -55,6 +74,23 @@ typedef struct {
|
||||
int klass;
|
||||
} git_error;
|
||||
|
||||
typedef struct git_time {
|
||||
git_time_t time;
|
||||
int offset;
|
||||
} git_time;
|
||||
|
||||
typedef struct git_signature {
|
||||
char *name;
|
||||
char *email;
|
||||
git_time when;
|
||||
} git_signature;
|
||||
|
||||
#define GIT_FEATURE_THREADS ...
|
||||
#define GIT_FEATURE_HTTPS ...
|
||||
#define GIT_FEATURE_SSH ...
|
||||
|
||||
int git_libgit2_features(void);
|
||||
|
||||
const git_error * giterr_last(void);
|
||||
|
||||
void git_strarray_free(git_strarray *array);
|
||||
@ -87,9 +123,39 @@ typedef enum {
|
||||
GIT_CREDTYPE_SSH_KEY,
|
||||
GIT_CREDTYPE_SSH_CUSTOM,
|
||||
GIT_CREDTYPE_DEFAULT,
|
||||
GIT_CREDTYPE_SSH_INTERACTIVE,
|
||||
GIT_CREDTYPE_USERNAME,
|
||||
...
|
||||
} git_credtype_t;
|
||||
|
||||
typedef enum git_cert_t {
|
||||
GIT_CERT_NONE,
|
||||
GIT_CERT_X509,
|
||||
GIT_CERT_HOSTKEY_LIBSSH2,
|
||||
} git_cert_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_CERT_SSH_MD5 = 1,
|
||||
GIT_CERT_SSH_SHA1 = 2,
|
||||
} git_cert_ssh_t;
|
||||
|
||||
typedef struct {
|
||||
git_cert_t cert_type;
|
||||
} git_cert;
|
||||
|
||||
typedef struct {
|
||||
git_cert parent;
|
||||
git_cert_ssh_t type;
|
||||
unsigned char hash_md5[16];
|
||||
unsigned char hash_sha1[20];
|
||||
} git_cert_hostkey;
|
||||
|
||||
typedef struct {
|
||||
git_cert parent;
|
||||
void *data;
|
||||
size_t len;
|
||||
} git_cert_x509;
|
||||
|
||||
typedef int (*git_transport_message_cb)(const char *str, int len, void *data);
|
||||
typedef int (*git_cred_acquire_cb)(
|
||||
git_cred **cred,
|
||||
@ -98,70 +164,136 @@ typedef int (*git_cred_acquire_cb)(
|
||||
unsigned int allowed_types,
|
||||
void *payload);
|
||||
typedef int (*git_transfer_progress_cb)(const git_transfer_progress *stats, void *payload);
|
||||
typedef int (*git_transport_certificate_check_cb)(git_cert *cert, int valid, const char *host, void *payload);
|
||||
|
||||
typedef int (*git_packbuilder_progress)(
|
||||
int stage,
|
||||
unsigned int current,
|
||||
unsigned int total,
|
||||
void *payload);
|
||||
typedef int (*git_push_transfer_progress)(
|
||||
unsigned int current,
|
||||
unsigned int total,
|
||||
size_t bytes,
|
||||
void* payload);
|
||||
|
||||
typedef struct {
|
||||
char *src_refname;
|
||||
char *dst_refname;
|
||||
git_oid src;
|
||||
git_oid dst;
|
||||
} git_push_update;
|
||||
|
||||
typedef int (*git_push_negotiation)(const git_push_update **updates, size_t len, void *payload);
|
||||
typedef int (*git_transport_cb)(git_transport **out, git_remote *owner, void *param);
|
||||
|
||||
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_transport_certificate_check_cb certificate_check;
|
||||
git_transfer_progress_cb transfer_progress;
|
||||
int (*update_tips)(const char *refname, const git_oid *a, const git_oid *b, void *data);
|
||||
git_packbuilder_progress pack_progress;
|
||||
git_push_transfer_progress push_transfer_progress;
|
||||
int (*push_update_reference)(const char *refname, const char *status, void *data);
|
||||
git_push_negotiation push_negotiation;
|
||||
git_transport_cb transport;
|
||||
void *payload;
|
||||
};
|
||||
|
||||
#define GIT_REMOTE_CALLBACKS_VERSION ...
|
||||
|
||||
typedef struct git_remote_callbacks git_remote_callbacks;
|
||||
|
||||
typedef enum {
|
||||
GIT_PROXY_NONE,
|
||||
GIT_PROXY_AUTO,
|
||||
GIT_PROXY_SPECIFIED,
|
||||
} git_proxy_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
git_proxy_t type;
|
||||
const char *url;
|
||||
git_cred_acquire_cb credentials;
|
||||
git_transport_certificate_check_cb certificate_check;
|
||||
void *payload;
|
||||
} git_proxy_options;
|
||||
|
||||
#define GIT_PROXY_OPTIONS_VERSION ...
|
||||
int git_proxy_init_options(git_proxy_options *opts, unsigned int version);
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
unsigned int pb_parallelism;
|
||||
git_remote_callbacks callbacks;
|
||||
git_proxy_options proxy_opts;
|
||||
git_strarray custom_headers;
|
||||
} git_push_options;
|
||||
|
||||
#define GIT_PUSH_OPTIONS_VERSION ...
|
||||
int git_push_init_options(git_push_options *opts, unsigned int version);
|
||||
|
||||
typedef enum {
|
||||
GIT_FETCH_PRUNE_UNSPECIFIED,
|
||||
GIT_FETCH_PRUNE,
|
||||
GIT_FETCH_NO_PRUNE,
|
||||
} git_fetch_prune_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED = 0,
|
||||
GIT_REMOTE_DOWNLOAD_TAGS_AUTO,
|
||||
GIT_REMOTE_DOWNLOAD_TAGS_NONE,
|
||||
GIT_REMOTE_DOWNLOAD_TAGS_ALL,
|
||||
} git_remote_autotag_option_t;
|
||||
|
||||
typedef struct {
|
||||
int version;
|
||||
git_remote_callbacks callbacks;
|
||||
git_fetch_prune_t prune;
|
||||
int update_fetchhead;
|
||||
git_remote_autotag_option_t download_tags;
|
||||
git_proxy_options proxy_opts;
|
||||
git_strarray custom_headers;
|
||||
} git_fetch_options;
|
||||
|
||||
#define GIT_FETCH_OPTIONS_VERSION ...
|
||||
int git_fetch_init_options(git_fetch_options *opts, unsigned int version);
|
||||
|
||||
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_lookup(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);
|
||||
int git_remote_create_with_fetchspec(git_remote **out, git_repository *repo, const char *name, const char *url, const char *fetch);
|
||||
int git_remote_delete(git_repository *repo, const char *name);
|
||||
int git_repository_state_cleanup(git_repository *repo);
|
||||
|
||||
const char * git_remote_name(const git_remote *remote);
|
||||
|
||||
int git_remote_rename(
|
||||
git_strarray *problems,
|
||||
git_remote *remote,
|
||||
const char *new_name);
|
||||
int git_remote_rename(git_strarray *problems, git_repository *repo, const char *name, const char *new_name);
|
||||
const char * git_remote_url(const git_remote *remote);
|
||||
int git_remote_set_url(git_remote *remote, const char* url);
|
||||
int git_remote_set_url(git_repository *repo, const char *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);
|
||||
int git_remote_set_pushurl(git_repository *repo, const char *remote, const char* url);
|
||||
int git_remote_fetch(git_remote *remote, const git_strarray *refspecs, const git_fetch_options *opts, const char *reflog_message);
|
||||
int git_remote_push(git_remote *remote, const git_strarray *refspecs, const git_push_options *opts);
|
||||
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);
|
||||
int git_remote_add_push(git_repository *repo, const char *remote, const char *refspec);
|
||||
int git_remote_add_fetch(git_repository *repo, const char *remote, const char *refspec);
|
||||
int git_remote_init_callbacks(git_remote_callbacks *opts, unsigned int version);
|
||||
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);
|
||||
@ -184,19 +316,21 @@ int git_cred_ssh_key_new(
|
||||
const char *publickey,
|
||||
const char *privatekey,
|
||||
const char *passphrase);
|
||||
int git_cred_ssh_key_from_agent(
|
||||
git_cred **out,
|
||||
const char *username);
|
||||
|
||||
/*
|
||||
* git_diff
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
GIT_SUBMODULE_IGNORE_RESET = -1,
|
||||
GIT_SUBMODULE_IGNORE_UNSPECIFIED = -1,
|
||||
|
||||
GIT_SUBMODULE_IGNORE_NONE = 1,
|
||||
GIT_SUBMODULE_IGNORE_UNTRACKED = 2,
|
||||
GIT_SUBMODULE_IGNORE_DIRTY = 3,
|
||||
GIT_SUBMODULE_IGNORE_ALL = 4,
|
||||
GIT_SUBMODULE_IGNORE_DEFAULT = 0
|
||||
} git_submodule_ignore_t;
|
||||
|
||||
typedef enum {
|
||||
@ -234,23 +368,40 @@ typedef int (*git_diff_notify_cb)(
|
||||
const char *matched_pathspec,
|
||||
void *payload);
|
||||
|
||||
typedef int (*git_diff_progress_cb)(
|
||||
const git_diff *diff_so_far,
|
||||
const char *old_path,
|
||||
const char *new_path,
|
||||
void *payload);
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
uint32_t flags;
|
||||
|
||||
git_submodule_ignore_t ignore_submodules;
|
||||
git_strarray pathspec;
|
||||
git_diff_notify_cb notify_cb;
|
||||
void *notify_payload;
|
||||
|
||||
uint16_t context_lines;
|
||||
uint16_t interhunk_lines;
|
||||
git_diff_notify_cb notify_cb;
|
||||
git_diff_progress_cb progress_cb;
|
||||
void *payload;
|
||||
uint32_t context_lines;
|
||||
uint32_t interhunk_lines;
|
||||
uint16_t id_abbrev;
|
||||
git_off_t max_size;
|
||||
const char *old_prefix;
|
||||
const char *new_prefix;
|
||||
} git_diff_options;
|
||||
|
||||
typedef struct {
|
||||
int (*file_signature)(
|
||||
void **out, const git_diff_file *file,
|
||||
const char *fullpath, void *payload);
|
||||
int (*buffer_signature)(
|
||||
void **out, const git_diff_file *file,
|
||||
const char *buf, size_t buflen, void *payload);
|
||||
void (*free_signature)(void *sig, void *payload);
|
||||
int (*similarity)(int *score, void *siga, void *sigb, void *payload);
|
||||
void *payload;
|
||||
} git_diff_similarity_metric;
|
||||
|
||||
int git_diff_init_options(git_diff_options *opts, unsigned int version);
|
||||
int git_diff_index_to_workdir(git_diff **diff, git_repository *repo, git_index *index, const git_diff_options *opts);
|
||||
int git_diff_tree_to_index(git_diff **diff, git_repository *repo, git_tree *old_tree, git_index *index, const git_diff_options *opts);
|
||||
@ -259,7 +410,16 @@ int git_diff_tree_to_index(git_diff **diff, git_repository *repo, git_tree *old_
|
||||
* git_checkout
|
||||
*/
|
||||
|
||||
typedef enum { ... } git_checkout_notify_t;
|
||||
typedef enum {
|
||||
GIT_CHECKOUT_NOTIFY_NONE = 0,
|
||||
GIT_CHECKOUT_NOTIFY_CONFLICT = 1,
|
||||
GIT_CHECKOUT_NOTIFY_DIRTY = 2,
|
||||
GIT_CHECKOUT_NOTIFY_UPDATED = 4,
|
||||
GIT_CHECKOUT_NOTIFY_UNTRACKED = 8,
|
||||
GIT_CHECKOUT_NOTIFY_IGNORED = 16,
|
||||
|
||||
GIT_CHECKOUT_NOTIFY_ALL = 0x0FFFF
|
||||
} git_checkout_notify_t;
|
||||
|
||||
typedef int (*git_checkout_notify_cb)(
|
||||
git_checkout_notify_t why,
|
||||
@ -275,41 +435,39 @@ typedef void (*git_checkout_progress_cb)(
|
||||
size_t total_steps,
|
||||
void *payload);
|
||||
|
||||
typedef struct {
|
||||
size_t mkdir_calls;
|
||||
size_t stat_calls;
|
||||
size_t chmod_calls;
|
||||
} git_checkout_perfdata;
|
||||
|
||||
typedef void (*git_checkout_perfdata_cb)(
|
||||
const git_checkout_perfdata *perfdata,
|
||||
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;
|
||||
|
||||
git_index *baseline_index;
|
||||
const char *target_directory;
|
||||
|
||||
const char *ancestor_label;
|
||||
const char *our_label;
|
||||
const char *their_label;
|
||||
git_checkout_perfdata_cb perfdata_cb;
|
||||
void *perfdata_payload;
|
||||
} git_checkout_options;
|
||||
|
||||
typedef enum {
|
||||
GIT_CLONE_LOCAL_AUTO,
|
||||
GIT_CLONE_LOCAL,
|
||||
GIT_CLONE_NO_LOCAL,
|
||||
GIT_CLONE_LOCAL_NO_LINKS,
|
||||
} git_clone_local_t;
|
||||
|
||||
int git_checkout_init_options(git_checkout_options *opts, unsigned int version);
|
||||
int git_checkout_tree(git_repository *repo, const git_object *treeish, const git_checkout_options *opts);
|
||||
int git_checkout_head(git_repository *repo, const git_checkout_options *opts);
|
||||
@ -319,32 +477,47 @@ int git_checkout_index(git_repository *repo, git_index *index, const git_checkou
|
||||
* git_clone
|
||||
*/
|
||||
|
||||
typedef int (*git_remote_create_cb)(
|
||||
git_remote **out,
|
||||
git_repository *repo,
|
||||
const char *name,
|
||||
const char *url,
|
||||
void *payload);
|
||||
|
||||
typedef int (*git_repository_create_cb)(
|
||||
git_repository **out,
|
||||
const char *path,
|
||||
int bare,
|
||||
void *payload);
|
||||
|
||||
typedef enum {
|
||||
GIT_CLONE_LOCAL_AUTO,
|
||||
GIT_CLONE_LOCAL,
|
||||
GIT_CLONE_NO_LOCAL,
|
||||
GIT_CLONE_LOCAL_NO_LINKS,
|
||||
} git_clone_local_t;
|
||||
|
||||
typedef struct git_clone_options {
|
||||
unsigned int version;
|
||||
|
||||
git_checkout_options checkout_opts;
|
||||
git_remote_callbacks remote_callbacks;
|
||||
|
||||
git_fetch_options fetch_opts;
|
||||
int bare;
|
||||
int ignore_cert_errors;
|
||||
git_clone_local_t local;
|
||||
const char *remote_name;
|
||||
const char* checkout_branch;
|
||||
git_signature *signature;
|
||||
git_repository_create_cb repository_cb;
|
||||
void *repository_cb_payload;
|
||||
git_remote_create_cb remote_cb;
|
||||
void *remote_cb_payload;
|
||||
} git_clone_options;
|
||||
|
||||
#define GIT_CLONE_OPTIONS_VERSION ...
|
||||
int git_clone_init_options(git_clone_options *opts, unsigned int version);
|
||||
|
||||
int git_clone(git_repository **out,
|
||||
const char *url,
|
||||
const char *local_path,
|
||||
const git_clone_options *options);
|
||||
|
||||
int git_clone_into(
|
||||
git_repository *repo,
|
||||
git_remote *remote,
|
||||
const git_checkout_options *co_opts,
|
||||
const char *branch,
|
||||
const git_signature *signature);
|
||||
|
||||
/*
|
||||
* git_config
|
||||
*/
|
||||
@ -353,24 +526,30 @@ typedef ... git_config;
|
||||
typedef ... git_config_iterator;
|
||||
|
||||
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_LEVEL_PROGRAMDATA = 1,
|
||||
GIT_CONFIG_LEVEL_SYSTEM = 2,
|
||||
GIT_CONFIG_LEVEL_XDG = 3,
|
||||
GIT_CONFIG_LEVEL_GLOBAL = 4,
|
||||
GIT_CONFIG_LEVEL_LOCAL = 5,
|
||||
GIT_CONFIG_LEVEL_APP = 6,
|
||||
GIT_CONFIG_HIGHEST_LEVEL = -1,
|
||||
} git_config_level_t;
|
||||
|
||||
typedef struct {
|
||||
typedef struct git_config_entry {
|
||||
const char *name;
|
||||
const char *value;
|
||||
git_config_level_t level;
|
||||
void (*free)(struct git_config_entry *entry);
|
||||
void *payload;
|
||||
} git_config_entry;
|
||||
|
||||
void git_config_entry_free(git_config_entry *);
|
||||
|
||||
int git_repository_config(git_config **out, git_repository *repo);
|
||||
int git_repository_config_snapshot(git_config **out, git_repository *repo);
|
||||
void git_config_free(git_config *cfg);
|
||||
|
||||
int git_config_get_entry(git_config_entry **out, const git_config *cfg, const char *name);
|
||||
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);
|
||||
@ -418,6 +597,7 @@ typedef enum {
|
||||
GIT_REPOSITORY_INIT_MKDIR,
|
||||
GIT_REPOSITORY_INIT_MKPATH,
|
||||
GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE,
|
||||
GIT_REPOSITORY_INIT_RELATIVE_GITLINK,
|
||||
...
|
||||
} git_repository_init_flag_t;
|
||||
|
||||
@ -439,6 +619,9 @@ typedef struct {
|
||||
const char *origin_url;
|
||||
} git_repository_init_options;
|
||||
|
||||
#define GIT_REPOSITORY_INIT_OPTIONS_VERSION ...
|
||||
int git_repository_init_init_options(git_repository_init_options *opts, int version);
|
||||
|
||||
int git_repository_init(
|
||||
git_repository **out,
|
||||
const char *path,
|
||||
@ -449,31 +632,49 @@ int git_repository_init_ext(
|
||||
const char *repo_path,
|
||||
git_repository_init_options *opts);
|
||||
|
||||
int git_repository_set_head(git_repository *repo, const char *refname);
|
||||
int git_repository_set_head_detached(git_repository *repo, const git_oid *commitish);
|
||||
int git_repository_ident(const char **name, const char **email, const git_repository *repo);
|
||||
int git_repository_set_ident(git_repository *repo, const char *name, const char *email);
|
||||
int git_graph_ahead_behind(size_t *ahead, size_t *behind, git_repository *repo, const git_oid *local, const git_oid *upstream);
|
||||
|
||||
/*
|
||||
* git_submodule
|
||||
*/
|
||||
|
||||
int git_submodule_lookup(git_submodule **out, git_repository *repo, char *path);
|
||||
void git_submodule_free(git_submodule *subm);
|
||||
int git_submodule_open(git_repository **out, git_submodule *subm);
|
||||
const char *git_submodule_name(git_submodule *subm);
|
||||
const char *git_submodule_path(git_submodule *subm);
|
||||
const char *git_submodule_url(git_submodule *subm);
|
||||
const char *git_submodule_branch(git_submodule *subm);
|
||||
|
||||
/*
|
||||
* git_index
|
||||
*/
|
||||
typedef int64_t git_time_t;
|
||||
|
||||
typedef struct {
|
||||
git_time_t seconds;
|
||||
unsigned int nanoseconds;
|
||||
int32_t seconds;
|
||||
uint32_t nanoseconds;
|
||||
} git_index_time;
|
||||
|
||||
typedef struct git_index_entry {
|
||||
git_index_time ctime;
|
||||
git_index_time mtime;
|
||||
|
||||
unsigned int dev;
|
||||
unsigned int ino;
|
||||
unsigned int mode;
|
||||
unsigned int uid;
|
||||
unsigned int gid;
|
||||
git_off_t file_size;
|
||||
uint32_t dev;
|
||||
uint32_t ino;
|
||||
uint32_t mode;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t file_size;
|
||||
|
||||
git_oid id;
|
||||
|
||||
unsigned short flags;
|
||||
unsigned short flags_extended;
|
||||
uint16_t flags;
|
||||
uint16_t flags_extended;
|
||||
|
||||
const char *path;
|
||||
} git_index_entry;
|
||||
@ -505,3 +706,221 @@ int git_index_conflict_iterator_new(git_index_conflict_iterator **iterator_out,
|
||||
int git_index_conflict_get(const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index *index, const char *path);
|
||||
int git_index_conflict_next(const git_index_entry **ancestor_out, const git_index_entry **our_out, const git_index_entry **their_out, git_index_conflict_iterator *iterator);
|
||||
int git_index_conflict_remove(git_index *index, const char *path);
|
||||
|
||||
/*
|
||||
* git_blame
|
||||
*/
|
||||
|
||||
typedef ... git_blame;
|
||||
|
||||
typedef struct git_blame_options {
|
||||
unsigned int version;
|
||||
|
||||
uint32_t flags;
|
||||
uint16_t min_match_characters;
|
||||
git_oid newest_commit;
|
||||
git_oid oldest_commit;
|
||||
size_t min_line;
|
||||
size_t max_line;
|
||||
} git_blame_options;
|
||||
|
||||
#define GIT_BLAME_OPTIONS_VERSION ...
|
||||
|
||||
typedef struct git_blame_hunk {
|
||||
size_t lines_in_hunk;
|
||||
|
||||
git_oid final_commit_id;
|
||||
size_t final_start_line_number;
|
||||
git_signature *final_signature;
|
||||
|
||||
git_oid orig_commit_id;
|
||||
const char *orig_path;
|
||||
size_t orig_start_line_number;
|
||||
git_signature *orig_signature;
|
||||
|
||||
char boundary;
|
||||
} git_blame_hunk;
|
||||
|
||||
int git_blame_init_options(git_blame_options *opts, unsigned int version);
|
||||
uint32_t git_blame_get_hunk_count(git_blame *blame);
|
||||
const git_blame_hunk *git_blame_get_hunk_byindex(git_blame *blame, uint32_t index);
|
||||
const git_blame_hunk *git_blame_get_hunk_byline(git_blame *blame, size_t lineno);
|
||||
int git_blame_file(git_blame **out, git_repository *repo, const char *path, git_blame_options *options);
|
||||
void git_blame_free(git_blame *blame);
|
||||
|
||||
/*
|
||||
* Merging
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
GIT_MERGE_FIND_RENAMES = 1,
|
||||
GIT_MERGE_FAIL_ON_CONFLICT = 2,
|
||||
GIT_MERGE_SKIP_REUC = 4,
|
||||
GIT_MERGE_NO_RECURSIVE = 8,
|
||||
} git_merge_flag_t;
|
||||
|
||||
typedef enum {
|
||||
GIT_MERGE_FILE_FAVOR_NORMAL = 0,
|
||||
GIT_MERGE_FILE_FAVOR_OURS = 1,
|
||||
GIT_MERGE_FILE_FAVOR_THEIRS = 2,
|
||||
GIT_MERGE_FILE_FAVOR_UNION = 3,
|
||||
} git_merge_file_favor_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
git_merge_flag_t flags;
|
||||
unsigned int rename_threshold;
|
||||
unsigned int target_limit;
|
||||
git_diff_similarity_metric *metric;
|
||||
unsigned int recursion_limit;
|
||||
const char *default_driver;
|
||||
git_merge_file_favor_t file_favor;
|
||||
unsigned int file_flags;
|
||||
} git_merge_options;
|
||||
|
||||
#define GIT_MERGE_OPTIONS_VERSION 1
|
||||
|
||||
typedef struct {
|
||||
unsigned int automergeable;
|
||||
const char *path;
|
||||
unsigned int mode;
|
||||
const char *ptr;
|
||||
size_t len;
|
||||
} git_merge_file_result;
|
||||
|
||||
typedef enum {
|
||||
GIT_MERGE_FILE_DEFAULT = 0,
|
||||
GIT_MERGE_FILE_STYLE_MERGE = 1,
|
||||
GIT_MERGE_FILE_STYLE_DIFF3 = 2,
|
||||
GIT_MERGE_FILE_SIMPLIFY_ALNUM = 4,
|
||||
GIT_MERGE_FILE_IGNORE_WHITESPACE = 8,
|
||||
GIT_MERGE_FILE_IGNORE_WHITESPACE_CHANGE = 16,
|
||||
GIT_MERGE_FILE_IGNORE_WHITESPACE_EOL = 32,
|
||||
GIT_MERGE_FILE_DIFF_PATIENCE = 64,
|
||||
GIT_MERGE_FILE_DIFF_MINIMAL = 128,
|
||||
} git_merge_file_flag_t;
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
const char *ancestor_label;
|
||||
const char *our_label;
|
||||
const char *their_label;
|
||||
git_merge_file_favor_t favor;
|
||||
git_merge_file_flag_t flags;
|
||||
} git_merge_file_options;
|
||||
|
||||
#define GIT_MERGE_OPTIONS_VERSION ...
|
||||
|
||||
int git_merge_init_options(git_merge_options *opts, unsigned int version);
|
||||
int git_merge_commits(git_index **out, git_repository *repo, const git_commit *our_commit, const git_commit *their_commit, const git_merge_options *opts);
|
||||
int git_merge_trees(git_index **out, git_repository *repo, const git_tree *ancestor_tree, const git_tree *our_tree, const git_tree *their_tree, const git_merge_options *opts);
|
||||
int git_merge_file_from_index(git_merge_file_result *out, git_repository *repo, const git_index_entry *ancestor, const git_index_entry *ours, const git_index_entry *theirs, const git_merge_file_options *opts);
|
||||
void git_merge_file_result_free(git_merge_file_result *result);
|
||||
|
||||
/*
|
||||
* git_stash
|
||||
*/
|
||||
|
||||
typedef int (*git_stash_cb)(
|
||||
size_t index, const char* message, const git_oid *stash_id, void *payload);
|
||||
|
||||
typedef enum {
|
||||
GIT_STASH_APPLY_PROGRESS_NONE = 0,
|
||||
GIT_STASH_APPLY_PROGRESS_LOADING_STASH = 1,
|
||||
GIT_STASH_APPLY_PROGRESS_ANALYZE_INDEX = 2,
|
||||
GIT_STASH_APPLY_PROGRESS_ANALYZE_MODIFIED = 3,
|
||||
GIT_STASH_APPLY_PROGRESS_ANALYZE_UNTRACKED = 4,
|
||||
GIT_STASH_APPLY_PROGRESS_CHECKOUT_UNTRACKED = 5,
|
||||
GIT_STASH_APPLY_PROGRESS_CHECKOUT_MODIFIED = 6,
|
||||
GIT_STASH_APPLY_PROGRESS_DONE = 7,
|
||||
} git_stash_apply_progress_t;
|
||||
|
||||
typedef int (*git_stash_apply_progress_cb)(
|
||||
git_stash_apply_progress_t progress, void *payload);
|
||||
|
||||
typedef enum {
|
||||
GIT_STASH_DEFAULT = 0,
|
||||
GIT_STASH_KEEP_INDEX = 1,
|
||||
GIT_STASH_INCLUDE_UNTRACKED = 2,
|
||||
GIT_STASH_INCLUDE_IGNORED = 4,
|
||||
} git_stash_flags;
|
||||
|
||||
typedef enum {
|
||||
GIT_STASH_APPLY_DEFAULT = 0,
|
||||
GIT_STASH_APPLY_REINSTATE_INDEX = 1,
|
||||
} git_stash_apply_flags;
|
||||
|
||||
typedef struct git_stash_apply_options {
|
||||
unsigned int version;
|
||||
git_stash_apply_flags flags;
|
||||
git_checkout_options checkout_options;
|
||||
git_stash_apply_progress_cb progress_cb;
|
||||
void *progress_payload;
|
||||
} git_stash_apply_options;
|
||||
|
||||
#define GIT_STASH_APPLY_OPTIONS_VERSION ...
|
||||
|
||||
int git_stash_save(git_oid *out, git_repository *repo, const git_signature *stasher, const char *message, uint32_t flags);
|
||||
int git_stash_apply_init_options(git_stash_apply_options *opts, unsigned int version);
|
||||
int git_stash_apply(git_repository *repo, size_t index, const git_stash_apply_options *options);
|
||||
int git_stash_foreach(git_repository *repo, git_stash_cb callback, void *payload);
|
||||
int git_stash_drop(git_repository *repo, size_t index);
|
||||
int git_stash_pop(git_repository *repo, size_t index, const git_stash_apply_options *options);
|
||||
|
||||
/*
|
||||
* Describe
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
GIT_DESCRIBE_DEFAULT,
|
||||
GIT_DESCRIBE_TAGS,
|
||||
GIT_DESCRIBE_ALL,
|
||||
} git_describe_strategy_t;
|
||||
|
||||
typedef struct git_describe_options {
|
||||
unsigned int version;
|
||||
unsigned int max_candidates_tags;
|
||||
unsigned int describe_strategy;
|
||||
const char *pattern;
|
||||
int only_follow_first_parent;
|
||||
int show_commit_oid_as_fallback;
|
||||
} git_describe_options;
|
||||
|
||||
#define GIT_DESCRIBE_OPTIONS_VERSION ...
|
||||
|
||||
int git_describe_init_options(git_describe_options *opts, unsigned int version);
|
||||
|
||||
typedef struct {
|
||||
unsigned int version;
|
||||
unsigned int abbreviated_size;
|
||||
int always_use_long_format;
|
||||
const char *dirty_suffix;
|
||||
} git_describe_format_options;
|
||||
|
||||
#define GIT_DESCRIBE_FORMAT_OPTIONS_VERSION ...
|
||||
|
||||
int git_describe_init_format_options(git_describe_format_options *opts, unsigned int version);
|
||||
|
||||
typedef ... git_describe_result;
|
||||
|
||||
int git_describe_commit(git_describe_result **result, git_object *committish, git_describe_options *opts);
|
||||
int git_describe_workdir(git_describe_result **out, git_repository *repo, git_describe_options *opts);
|
||||
int git_describe_format(git_buf *out, const git_describe_result *result, const git_describe_format_options *opts);
|
||||
void git_describe_result_free(git_describe_result *result);
|
||||
|
||||
#define GIT_ATTR_CHECK_FILE_THEN_INDEX ...
|
||||
#define GIT_ATTR_CHECK_INDEX_THEN_FILE ...
|
||||
#define GIT_ATTR_CHECK_INDEX_ONLY ...
|
||||
#define GIT_ATTR_CHECK_NO_SYSTEM ...
|
||||
|
||||
typedef enum {
|
||||
GIT_ATTR_UNSPECIFIED_T = 0,
|
||||
GIT_ATTR_TRUE_T,
|
||||
GIT_ATTR_FALSE_T,
|
||||
GIT_ATTR_VALUE_T,
|
||||
} git_attr_t;
|
||||
|
||||
int git_attr_get(const char **value_out, git_repository *repo, uint32_t flags, const char *path, const char *name);
|
||||
git_attr_t git_attr_value(const char *attr);
|
||||
|
||||
int git_revert_commit(git_index **out, git_repository *repo, git_commit *revert_commit, git_commit *our_commit, unsigned int mainline, const git_merge_options *merge_options);
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -25,32 +25,45 @@
|
||||
# the Free Software Foundation, 51 Franklin Street, Fifth Floor,
|
||||
# Boston, MA 02110-1301, USA.
|
||||
|
||||
# ffi
|
||||
# Import from pygit2
|
||||
from .ffi import ffi, C
|
||||
|
||||
from _pygit2 import GitError
|
||||
|
||||
|
||||
value_errors = set([C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EEXISTS,
|
||||
C.GIT_EAMBIGUOUS])
|
||||
|
||||
def check_error(err, io=False):
|
||||
if err >= 0:
|
||||
return
|
||||
|
||||
message = "(no message provided)"
|
||||
# Error message
|
||||
giterr = C.giterr_last()
|
||||
if giterr != ffi.NULL:
|
||||
message = ffi.string(giterr.message).decode()
|
||||
message = ffi.string(giterr.message).decode('utf8')
|
||||
else:
|
||||
message = "err %d (no message provided)" % err
|
||||
|
||||
if err in [C.GIT_EEXISTS, C.GIT_EINVALIDSPEC, C.GIT_EEXISTS,
|
||||
C.GIT_EAMBIGUOUS]:
|
||||
# Translate to Python errors
|
||||
if err in value_errors:
|
||||
raise ValueError(message)
|
||||
elif err == C.GIT_ENOTFOUND:
|
||||
|
||||
if err == C.GIT_ENOTFOUND:
|
||||
if io:
|
||||
raise IOError(message)
|
||||
else:
|
||||
raise KeyError(message)
|
||||
elif err == C.GIT_EINVALIDSPEC:
|
||||
|
||||
raise KeyError(message)
|
||||
|
||||
if err == C.GIT_EINVALIDSPEC:
|
||||
raise ValueError(message)
|
||||
elif err == C.GIT_ITEROVER:
|
||||
|
||||
if err == C.GIT_ITEROVER:
|
||||
raise StopIteration()
|
||||
|
||||
# Generic Git error
|
||||
raise GitError(message)
|
||||
|
||||
# Indicate that we want libgit2 to pretend a function was not set
|
||||
class Passthrough(Exception):
|
||||
def __init__(self):
|
||||
super(Passthrough, self).__init__( "The function asked for pass-through")
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -28,32 +28,9 @@
|
||||
# Import from the future
|
||||
from __future__ import absolute_import
|
||||
|
||||
# Import from the Standard Library
|
||||
import inspect
|
||||
import codecs
|
||||
from os import path, getenv
|
||||
|
||||
# Import from cffi
|
||||
from cffi import FFI
|
||||
|
||||
|
||||
|
||||
ffi = FFI()
|
||||
|
||||
|
||||
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')
|
||||
if not libgit2_path:
|
||||
libgit2_path = '/usr/local'
|
||||
|
||||
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)
|
||||
# Import from pygit2
|
||||
try:
|
||||
from ._libgit2 import ffi, lib as C
|
||||
except ImportError:
|
||||
from ._run import ffi, preamble, C_KEYWORDS
|
||||
C = ffi.verify(preamble, **C_KEYWORDS)
|
||||
|
116
pygit2/index.py
116
pygit2/index.py
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -28,11 +28,14 @@
|
||||
# Import from the future
|
||||
from __future__ import absolute_import, unicode_literals
|
||||
|
||||
import weakref
|
||||
|
||||
# Import from pygit2
|
||||
from _pygit2 import Oid, Tree, Diff
|
||||
from .errors import check_error
|
||||
from .ffi import ffi, C
|
||||
from .utils import is_string, strings_to_strarray, to_bytes, to_str
|
||||
from .utils import is_string, to_bytes, to_str
|
||||
from .utils import GenericIterator, StrArray
|
||||
|
||||
|
||||
class Index(object):
|
||||
@ -47,6 +50,7 @@ class Index(object):
|
||||
err = C.git_index_open(cindex, to_bytes(path))
|
||||
check_error(err)
|
||||
|
||||
self._repo = None
|
||||
self._index = cindex[0]
|
||||
self._cindex = cindex
|
||||
|
||||
@ -92,7 +96,7 @@ class Index(object):
|
||||
return IndexEntry._from_c(centry)
|
||||
|
||||
def __iter__(self):
|
||||
return IndexIterator(self)
|
||||
return GenericIterator(self)
|
||||
|
||||
def read(self, force=True):
|
||||
"""Update the contents the Index
|
||||
@ -109,8 +113,7 @@ class Index(object):
|
||||
check_error(err, True)
|
||||
|
||||
def write(self):
|
||||
"""Write the contents of the Index to disk
|
||||
"""
|
||||
"""Write the contents of the Index to disk."""
|
||||
err = C.git_index_write(self._index)
|
||||
check_error(err, True)
|
||||
|
||||
@ -119,21 +122,21 @@ class Index(object):
|
||||
check_error(err)
|
||||
|
||||
def read_tree(self, tree):
|
||||
"""read_tree([Tree|Oid])
|
||||
|
||||
Replace the contents of the Index with those of a tree
|
||||
"""Replace the contents of the Index with those of the given tree,
|
||||
expressed either as a <Tree> object or as an oid (string or <Oid>).
|
||||
|
||||
The tree will be read recursively and all its children will also be
|
||||
inserted into the Index.
|
||||
"""
|
||||
repo = self._repo
|
||||
if is_string(tree):
|
||||
tree = self._repo[tree]
|
||||
tree = repo[tree]
|
||||
|
||||
if isinstance(tree, Oid):
|
||||
if not hasattr(self, '_repo'):
|
||||
if repo is None:
|
||||
raise TypeError("id given but no associated repository")
|
||||
|
||||
tree = self._repo[tree]
|
||||
tree = repo[tree]
|
||||
elif not isinstance(tree, Tree):
|
||||
raise TypeError("argument must be Oid or Tree")
|
||||
|
||||
@ -143,9 +146,8 @@ class Index(object):
|
||||
check_error(err)
|
||||
|
||||
def write_tree(self, repo=None):
|
||||
"""write_tree([repo]) -> Oid
|
||||
|
||||
Create a tree out of the Index
|
||||
"""Create a tree out of the Index. Return the <Oid> object of the
|
||||
written tree.
|
||||
|
||||
The contents of the index will be written out to the object
|
||||
database. If there is no associated repository, 'repo' must be
|
||||
@ -155,6 +157,9 @@ class Index(object):
|
||||
It returns the id of the resulting tree.
|
||||
"""
|
||||
coid = ffi.new('git_oid *')
|
||||
|
||||
repo = repo or self._repo
|
||||
|
||||
if repo:
|
||||
err = C.git_index_write_tree_to(coid, self._index, repo._repo)
|
||||
else:
|
||||
@ -163,10 +168,10 @@ class Index(object):
|
||||
check_error(err)
|
||||
return Oid(raw=bytes(ffi.buffer(coid)[:]))
|
||||
|
||||
def remove(self, path):
|
||||
def remove(self, path, level=0):
|
||||
"""Remove an entry from the Index.
|
||||
"""
|
||||
err = C.git_index_remove(self._index, to_bytes(path), 0)
|
||||
err = C.git_index_remove(self._index, to_bytes(path), level)
|
||||
check_error(err, True)
|
||||
|
||||
def add_all(self, pathspecs=[]):
|
||||
@ -175,18 +180,16 @@ class Index(object):
|
||||
If pathspecs are specified, only files matching those pathspecs will
|
||||
be added.
|
||||
"""
|
||||
arr, refs = strings_to_strarray(pathspecs)
|
||||
err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL)
|
||||
check_error(err, True)
|
||||
with StrArray(pathspecs) as arr:
|
||||
err = C.git_index_add_all(self._index, arr, 0, ffi.NULL, ffi.NULL)
|
||||
check_error(err, True)
|
||||
|
||||
def add(self, path_or_entry):
|
||||
"""add([path|entry])
|
||||
"""Add or update an entry in the Index.
|
||||
|
||||
Add or update an entry in the Index
|
||||
|
||||
If a path is given, that file will be added. The path must be
|
||||
relative to the root of the worktree and the Index must be associated
|
||||
with a repository.
|
||||
If a path is given, that file will be added. The path must be relative
|
||||
to the root of the worktree and the Index must be associated with a
|
||||
repository.
|
||||
|
||||
If an IndexEntry is given, that entry will be added or update in the
|
||||
Index without checking for the existence of the path or id.
|
||||
@ -205,12 +208,8 @@ class Index(object):
|
||||
check_error(err, True)
|
||||
|
||||
def diff_to_workdir(self, flags=0, context_lines=3, interhunk_lines=0):
|
||||
"""diff_to_workdir(flags=0, context_lines=3, interhunk_lines=0) -> Diff
|
||||
|
||||
Diff the index against the working directory
|
||||
|
||||
Return a :py:class:`~pygit2.Diff` object with the differences
|
||||
between the index and the working copy.
|
||||
"""Diff the index against the working directory. Return a <Diff> object
|
||||
with the differences between the index and the working copy.
|
||||
|
||||
Arguments:
|
||||
|
||||
@ -222,7 +221,8 @@ class Index(object):
|
||||
interhunk_lines: the maximum number of unchanged lines between hunk
|
||||
boundaries before the hunks will be merged into a one
|
||||
"""
|
||||
if not hasattr(self, '_repo'):
|
||||
repo = self._repo
|
||||
if repo is None:
|
||||
raise ValueError('diff needs an associated repository')
|
||||
|
||||
copts = ffi.new('git_diff_options *')
|
||||
@ -234,19 +234,15 @@ class Index(object):
|
||||
copts.interhunk_lines = interhunk_lines
|
||||
|
||||
cdiff = ffi.new('git_diff **')
|
||||
err = C.git_diff_index_to_workdir(cdiff, self._repo._repo,
|
||||
self._index, copts)
|
||||
err = C.git_diff_index_to_workdir(cdiff, repo._repo, self._index,
|
||||
copts)
|
||||
check_error(err)
|
||||
|
||||
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), self._repo)
|
||||
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), repo)
|
||||
|
||||
def diff_to_tree(self, tree, flags=0, context_lines=3, interhunk_lines=0):
|
||||
"""diff_to_tree(flags=0, context_lines=3, interhunk_lines=0) -> Diff
|
||||
|
||||
Diff the index against a tree
|
||||
|
||||
Return a :py:class:`~pygit2.Diff` object with the differences between
|
||||
the index and the given tree.
|
||||
"""Diff the index against a tree. Return a <Diff> object with the
|
||||
differences between the index and the given tree.
|
||||
|
||||
Arguments:
|
||||
|
||||
@ -260,8 +256,8 @@ class Index(object):
|
||||
interhunk_lines: the maximum number of unchanged lines between hunk
|
||||
boundaries before the hunks will be merged into a one.
|
||||
"""
|
||||
|
||||
if not hasattr(self, '_repo'):
|
||||
repo = self._repo
|
||||
if repo is None:
|
||||
raise ValueError('diff needs an associated repository')
|
||||
|
||||
if not isinstance(tree, Tree):
|
||||
@ -279,11 +275,11 @@ class Index(object):
|
||||
ffi.buffer(ctree)[:] = tree._pointer[:]
|
||||
|
||||
cdiff = ffi.new('git_diff **')
|
||||
err = C.git_diff_tree_to_index(cdiff, self._repo._repo, ctree[0],
|
||||
err = C.git_diff_tree_to_index(cdiff, repo._repo, ctree[0],
|
||||
self._index, copts)
|
||||
check_error(err)
|
||||
|
||||
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), self._repo)
|
||||
return Diff.from_c(bytes(ffi.buffer(cdiff)[:]), repo)
|
||||
|
||||
|
||||
#
|
||||
@ -314,10 +310,12 @@ class Index(object):
|
||||
self._conflicts = None
|
||||
return None
|
||||
|
||||
if self._conflicts is None:
|
||||
self._conflicts = ConflictCollection(self)
|
||||
if self._conflicts is None or self._conflicts() is None:
|
||||
conflicts = ConflictCollection(self)
|
||||
self._conflicts = weakref.ref(conflicts)
|
||||
return conflicts
|
||||
|
||||
return self._conflicts
|
||||
return self._conflicts()
|
||||
|
||||
|
||||
class IndexEntry(object):
|
||||
@ -329,7 +327,7 @@ class IndexEntry(object):
|
||||
self.id = object_id
|
||||
"""The id of the referenced object"""
|
||||
self.mode = mode
|
||||
"""The mode of this entry, a GIT_FILEMODE_ value"""
|
||||
"""The mode of this entry, a GIT_FILEMODE_* value"""
|
||||
|
||||
@property
|
||||
def oid(self):
|
||||
@ -369,26 +367,6 @@ class IndexEntry(object):
|
||||
return entry
|
||||
|
||||
|
||||
class IndexIterator(object):
|
||||
|
||||
def __init__(self, index):
|
||||
self.index = index
|
||||
self.n = 0
|
||||
self.max = len(index)
|
||||
|
||||
def next(self):
|
||||
return self.__next__()
|
||||
|
||||
def __next__(self):
|
||||
if self.n >= self.max:
|
||||
raise StopIteration
|
||||
|
||||
entry = self.index[self.n]
|
||||
self.n += 1
|
||||
|
||||
return entry
|
||||
|
||||
|
||||
class ConflictCollection(object):
|
||||
|
||||
def __init__(self, index):
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -54,4 +54,4 @@ def to_str(s):
|
||||
if type(s) is unicode:
|
||||
return s.encode()
|
||||
|
||||
raise TypeError, 'unexpected type "%s"' % repr(s)
|
||||
raise TypeError('unexpected type "%s"' % repr(s))
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -35,6 +35,7 @@ from .utils import to_bytes
|
||||
|
||||
|
||||
class Refspec(object):
|
||||
"""The constructor is for internal use only"""
|
||||
def __init__(self, owner, ptr):
|
||||
self._owner = owner
|
||||
self._refspec = ptr
|
||||
@ -65,16 +66,14 @@ class Refspec(object):
|
||||
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 True if the given string matches the source of this refspec,
|
||||
False otherwise.
|
||||
"""
|
||||
return bool(C.git_refspec_src_matches(self._refspec, to_bytes(ref)))
|
||||
|
||||
def dst_matches(self, ref):
|
||||
"""dst_matches(str) -> Bool
|
||||
|
||||
Returns whether the given string matches the destination of this
|
||||
refspec"""
|
||||
"""Return True if the given string matches the destination of this
|
||||
refspec, False otherwise."""
|
||||
return bool(C.git_refspec_dst_matches(self._refspec, to_bytes(ref)))
|
||||
|
||||
def _transform(self, ref, fn):
|
||||
@ -88,15 +87,13 @@ class Refspec(object):
|
||||
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."""
|
||||
"""Transform a reference name according to this refspec from the lhs to
|
||||
the rhs. Return an string.
|
||||
"""
|
||||
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"""
|
||||
"""Transform a reference name according to this refspec from the lhs to
|
||||
the rhs. Return an string.
|
||||
"""
|
||||
return self._transform(ref, C.git_refspec_rtransform)
|
||||
|
609
pygit2/remote.py
609
pygit2/remote.py
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -30,10 +30,10 @@ from __future__ import absolute_import
|
||||
|
||||
# Import from pygit2
|
||||
from _pygit2 import Oid
|
||||
from .errors import check_error, GitError
|
||||
from .errors import check_error, Passthrough
|
||||
from .ffi import ffi, C
|
||||
from .refspec import Refspec
|
||||
from .utils import to_bytes, strarray_to_strings, strings_to_strarray
|
||||
from .utils import to_bytes, strarray_to_strings, StrArray
|
||||
|
||||
|
||||
def maybe_string(ptr):
|
||||
@ -49,7 +49,7 @@ class TransferProgress(object):
|
||||
def __init__(self, tp):
|
||||
|
||||
self.total_objects = tp.total_objects
|
||||
"""Total number objects to download"""
|
||||
"""Total number of objects to download"""
|
||||
|
||||
self.indexed_objects = tp.indexed_objects
|
||||
"""Objects which have been indexed"""
|
||||
@ -70,16 +70,35 @@ class TransferProgress(object):
|
||||
""""Number of bytes received up to now"""
|
||||
|
||||
|
||||
class Remote(object):
|
||||
class RemoteCallbacks(object):
|
||||
"""Base class for pygit2 remote callbacks.
|
||||
|
||||
Inherit from this class and override the callbacks which you want to use
|
||||
in your class, which you can then pass to the network operations.
|
||||
"""
|
||||
|
||||
def __init__(self, credentials=None, certificate=None):
|
||||
"""Initialize some callbacks in-line
|
||||
|
||||
Use this constructor to provide credentials and certificate
|
||||
callbacks in-line, instead of defining your own class for these ones.
|
||||
|
||||
You can e.g. also pass in one of the credential objects as 'credentials'
|
||||
instead of creating a function which returns a hard-coded object.
|
||||
"""
|
||||
|
||||
if credentials is not None:
|
||||
self.credentials = credentials
|
||||
if certificate is not None:
|
||||
self.certificate = certificate
|
||||
|
||||
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
|
||||
:param str string: Progress output from the remote
|
||||
"""
|
||||
pass
|
||||
|
||||
def credentials(self, url, username_from_url, allowed_types):
|
||||
"""Credentials callback
|
||||
@ -99,7 +118,26 @@ class Remote(object):
|
||||
|
||||
Return value: credential
|
||||
"""
|
||||
pass
|
||||
raise Passthrough
|
||||
|
||||
def certificate_check(self, certificate, valid, host):
|
||||
"""Certificate callback
|
||||
|
||||
Override with your own function to determine whether the accept
|
||||
the server's certificate.
|
||||
|
||||
:param None certificate: The certificate. It is currently always None
|
||||
while we figure out how to represent it cross-platform
|
||||
|
||||
:param bool valid: Whether the TLS/SSH library thinks the certificate
|
||||
is valid
|
||||
|
||||
:param str host: The hostname we want to connect to
|
||||
|
||||
Return value: True to connect, False to abort
|
||||
"""
|
||||
|
||||
raise Passthrough
|
||||
|
||||
def transfer_progress(self, stats):
|
||||
"""Transfer progress callback
|
||||
@ -108,7 +146,6 @@ class Remote(object):
|
||||
|
||||
:param TransferProgress stats: The progress up to now
|
||||
"""
|
||||
pass
|
||||
|
||||
def update_tips(self, refname, old, new):
|
||||
"""Update tips callabck
|
||||
@ -120,6 +157,169 @@ class Remote(object):
|
||||
:param Oid new: the reference's new value
|
||||
"""
|
||||
|
||||
def push_update_reference(self, refname, message):
|
||||
"""Push update reference callback
|
||||
|
||||
Override with your own function to report the remote's
|
||||
acceptace or rejection of reference updates.
|
||||
|
||||
:param str refname: the name of the reference (on the remote)
|
||||
:param str messsage: rejection message from the remote. If None, the update was accepted.
|
||||
"""
|
||||
|
||||
def _fill_fetch_options(self, fetch_opts):
|
||||
fetch_opts.callbacks.sideband_progress = self._sideband_progress_cb
|
||||
fetch_opts.callbacks.transfer_progress = self._transfer_progress_cb
|
||||
fetch_opts.callbacks.update_tips = self._update_tips_cb
|
||||
fetch_opts.callbacks.credentials = self._credentials_cb
|
||||
fetch_opts.callbacks.certificate_check = self._certificate_cb
|
||||
# We need to make sure that this handle stays alive
|
||||
self._self_handle = ffi.new_handle(self)
|
||||
fetch_opts.callbacks.payload = self._self_handle
|
||||
|
||||
self._stored_exception = None
|
||||
|
||||
def _fill_push_options(self, push_opts):
|
||||
push_opts.callbacks.sideband_progress = self._sideband_progress_cb
|
||||
push_opts.callbacks.transfer_progress = self._transfer_progress_cb
|
||||
push_opts.callbacks.update_tips = self._update_tips_cb
|
||||
push_opts.callbacks.credentials = self._credentials_cb
|
||||
push_opts.callbacks.certificate_check = self._certificate_cb
|
||||
push_opts.callbacks.push_update_reference = self._push_update_reference_cb
|
||||
# We need to make sure that this handle stays alive
|
||||
self._self_handle = ffi.new_handle(self)
|
||||
push_opts.callbacks.payload = self._self_handle
|
||||
|
||||
# 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)
|
||||
|
||||
transfer_progress = getattr(self, 'transfer_progress', None)
|
||||
if not transfer_progress:
|
||||
return 0
|
||||
|
||||
try:
|
||||
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)
|
||||
|
||||
progress = getattr(self, 'progress', None)
|
||||
if not progress:
|
||||
return 0
|
||||
|
||||
try:
|
||||
s = ffi.string(string, length).decode()
|
||||
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)
|
||||
|
||||
update_tips = getattr(self, 'update_tips', None)
|
||||
if not update_tips:
|
||||
return 0
|
||||
|
||||
try:
|
||||
s = maybe_string(refname)
|
||||
a = Oid(raw=bytes(ffi.buffer(a)[:]))
|
||||
b = Oid(raw=bytes(ffi.buffer(b)[:]))
|
||||
|
||||
update_tips(s, a, b)
|
||||
except Exception as e:
|
||||
self._stored_exception = e
|
||||
return C.GIT_EUSER
|
||||
|
||||
return 0
|
||||
|
||||
@ffi.callback("int (*push_update_reference)(const char *ref, const char *msg, void *data)")
|
||||
def _push_update_reference_cb(ref, msg, data):
|
||||
self = ffi.from_handle(data)
|
||||
|
||||
push_update_reference = getattr(self, 'push_update_reference', None)
|
||||
if not push_update_reference:
|
||||
return 0
|
||||
|
||||
try:
|
||||
refname = ffi.string(ref)
|
||||
message = maybe_string(msg)
|
||||
push_update_reference(refname, message)
|
||||
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)
|
||||
|
||||
credentials = getattr(self, 'credentials', None)
|
||||
if not credentials:
|
||||
return 0
|
||||
|
||||
try:
|
||||
ccred = get_credentials(credentials, url, username, allowed)
|
||||
cred_out[0] = ccred[0]
|
||||
except Passthrough as e:
|
||||
return C.GIT_PASSTHROUGH
|
||||
except Exception as e:
|
||||
self._stored_exception = e
|
||||
return C.GIT_EUSER
|
||||
|
||||
return 0
|
||||
|
||||
@ffi.callback('int (*git_transport_certificate_check_cb)'
|
||||
'(git_cert *cert, int valid, const char *host, void *payload)')
|
||||
def _certificate_cb(cert_i, valid, host, data):
|
||||
self = ffi.from_handle(data)
|
||||
|
||||
# We want to simulate what should happen if libgit2 supported pass-through for
|
||||
# this callback. For SSH, 'valid' is always False, because it doesn't look
|
||||
# at known_hosts, but we do want to let it through in order to do what libgit2 would
|
||||
# if the callback were not set.
|
||||
try:
|
||||
is_ssh = cert_i.cert_type == C.GIT_CERT_HOSTKEY_LIBSSH2
|
||||
|
||||
certificate_check = getattr(self, 'certificate_check', None)
|
||||
if not certificate_check:
|
||||
raise Passthrough
|
||||
|
||||
# python's parsing is deep in the libraries and assumes an OpenSSL-owned cert
|
||||
val = certificate_check(None, bool(valid), ffi.string(host))
|
||||
if not val:
|
||||
return C.GIT_ECERTIFICATE
|
||||
except Passthrough as e:
|
||||
if is_ssh:
|
||||
return 0
|
||||
elif valid:
|
||||
return 0
|
||||
else:
|
||||
return C.GIT_ECERTIFICATE
|
||||
except Exception as e:
|
||||
self._stored_exception = e
|
||||
return C.GIT_EUSER
|
||||
|
||||
return 0
|
||||
|
||||
class Remote(object):
|
||||
def __init__(self, repo, ptr):
|
||||
"""The constructor is for internal use only"""
|
||||
|
||||
@ -127,20 +327,6 @@ class Remote(object):
|
||||
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)
|
||||
|
||||
@ -150,72 +336,45 @@ class Remote(object):
|
||||
|
||||
return maybe_string(C.git_remote_name(self._remote))
|
||||
|
||||
def rename(self, new_name):
|
||||
"""Rename this remote
|
||||
|
||||
Returns a list of fetch refspecs which were not in the standard format
|
||||
and thus could not be remapped
|
||||
"""
|
||||
|
||||
if not new_name:
|
||||
raise ValueError("New remote name must be a non-empty string")
|
||||
|
||||
problems = ffi.new('git_strarray *')
|
||||
err = C.git_remote_rename(problems, self._remote, to_bytes(new_name))
|
||||
check_error(err)
|
||||
|
||||
ret = strarray_to_strings(problems)
|
||||
C.git_strarray_free(problems)
|
||||
|
||||
return ret
|
||||
|
||||
@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_bytes(value))
|
||||
check_error(err)
|
||||
|
||||
@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_bytes(value))
|
||||
check_error(err)
|
||||
|
||||
def save(self):
|
||||
"""save()
|
||||
|
||||
Save a remote to its repository's configuration"""
|
||||
"""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.
|
||||
def fetch(self, refspecs=None, message=None, callbacks=None):
|
||||
"""Perform a fetch against this remote. Returns a <TransferProgress>
|
||||
object.
|
||||
"""
|
||||
|
||||
if signature:
|
||||
ptr = signature._pointer[:]
|
||||
else:
|
||||
ptr = ffi.NULL
|
||||
fetch_opts = ffi.new('git_fetch_options *')
|
||||
err = C.git_fetch_init_options(fetch_opts, C.GIT_FETCH_OPTIONS_VERSION)
|
||||
|
||||
self._stored_exception = None
|
||||
err = C.git_remote_fetch(self._remote, ptr, to_bytes(message))
|
||||
if self._stored_exception:
|
||||
raise self._stored_exception
|
||||
if callbacks is None:
|
||||
callbacks = RemoteCallbacks()
|
||||
|
||||
check_error(err)
|
||||
callbacks._fill_fetch_options(fetch_opts)
|
||||
|
||||
try:
|
||||
with StrArray(refspecs) as arr:
|
||||
err = C.git_remote_fetch(self._remote, arr, fetch_opts, to_bytes(message))
|
||||
if callbacks._stored_exception:
|
||||
raise callbacks._stored_exception
|
||||
check_error(err)
|
||||
finally:
|
||||
callbacks._self_handle = None
|
||||
|
||||
return TransferProgress(C.git_remote_stats(self._remote))
|
||||
|
||||
@ -226,10 +385,7 @@ class Remote(object):
|
||||
return C.git_remote_refspec_count(self._remote)
|
||||
|
||||
def get_refspec(self, n):
|
||||
"""get_refspec(n) -> Refspec
|
||||
|
||||
Return the refspec at the given position
|
||||
"""
|
||||
"""Return the <Refspec> object at the given position."""
|
||||
spec = C.git_remote_get_refspec(self._remote, n)
|
||||
return Refspec(self, spec)
|
||||
|
||||
@ -243,12 +399,6 @@ class Remote(object):
|
||||
|
||||
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"""
|
||||
@ -259,153 +409,33 @@ class Remote(object):
|
||||
|
||||
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 push(self, specs, callbacks=None):
|
||||
"""Push the given refspec to the remote. Raises ``GitError`` on
|
||||
protocol error or unpack failure.
|
||||
|
||||
def add_fetch(self, spec):
|
||||
"""add_fetch(refspec)
|
||||
When the remote has a githook installed, that denies the reference
|
||||
this function will return successfully. Thus it is stronly recommended
|
||||
to install a callback, that implements
|
||||
:py:meth:`RemoteCallbacks.push_update_reference` and check the passed
|
||||
parameters for successfull operations.
|
||||
|
||||
Add a fetch refspec to the remote"""
|
||||
|
||||
err = C.git_remote_add_fetch(self._remote, to_bytes(spec))
|
||||
check_error(err)
|
||||
|
||||
def add_push(self, spec):
|
||||
"""add_push(refspec)
|
||||
|
||||
Add a push refspec to the remote"""
|
||||
|
||||
err = C.git_remote_add_push(self._remote, to_bytes(spec))
|
||||
check_error(err)
|
||||
|
||||
@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
|
||||
:param [str] specs: push refspecs to use
|
||||
"""
|
||||
push_opts = ffi.new('git_push_options *')
|
||||
err = C.git_push_init_options(push_opts, C.GIT_PUSH_OPTIONS_VERSION)
|
||||
|
||||
cpush = ffi.new('git_push **')
|
||||
err = C.git_push_new(cpush, self._remote)
|
||||
check_error(err)
|
||||
if callbacks is None:
|
||||
callbacks = RemoteCallbacks()
|
||||
|
||||
push = cpush[0]
|
||||
callbacks._fill_push_options(push_opts)
|
||||
# Build custom callback structure
|
||||
|
||||
try:
|
||||
err = C.git_push_add_refspec(push, to_bytes(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_bytes(message))
|
||||
check_error(err)
|
||||
|
||||
with StrArray(specs) as refspecs:
|
||||
err = C.git_remote_push(self._remote, refspecs, push_opts)
|
||||
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
|
||||
|
||||
callbacks._self_handle = None
|
||||
|
||||
def get_credentials(fn, url, username, allowed):
|
||||
"""Call fn and return the credentials object"""
|
||||
@ -415,29 +445,158 @@ def get_credentials(fn, url, username, allowed):
|
||||
|
||||
creds = fn(url_str, username_str, allowed)
|
||||
|
||||
if not hasattr(creds, 'credential_type') \
|
||||
or not hasattr(creds, 'credential_tuple'):
|
||||
credential_type = getattr(creds, 'credential_type', None)
|
||||
credential_tuple = getattr(creds, 'credential_tuple', None)
|
||||
if not credential_type or not credential_tuple:
|
||||
raise TypeError("credential does not implement interface")
|
||||
|
||||
cred_type = creds.credential_type
|
||||
cred_type = 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
|
||||
name, passwd = credential_tuple
|
||||
err = C.git_cred_userpass_plaintext_new(ccred, to_bytes(name),
|
||||
to_bytes(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_bytes(name), to_bytes(pubkey),
|
||||
to_bytes(privkey), to_bytes(passphrase))
|
||||
|
||||
name, pubkey, privkey, passphrase = credential_tuple
|
||||
if pubkey is None and privkey is None:
|
||||
err = C.git_cred_ssh_key_from_agent(ccred, to_bytes(name))
|
||||
else:
|
||||
err = C.git_cred_ssh_key_new(ccred, to_bytes(name),
|
||||
to_bytes(pubkey), to_bytes(privkey),
|
||||
to_bytes(passphrase))
|
||||
else:
|
||||
raise TypeError("unsupported credential type")
|
||||
|
||||
check_error(err)
|
||||
|
||||
return ccred
|
||||
|
||||
class RemoteCollection(object):
|
||||
"""Collection of configured remotes
|
||||
|
||||
You can use this class to look up and manage the remotes configured
|
||||
in a repository. You can access repositories using index
|
||||
access. E.g. to look up the "origin" remote, you can use
|
||||
|
||||
>>> repo.remotes["origin"]
|
||||
"""
|
||||
|
||||
def __init__(self, repo):
|
||||
self._repo = repo;
|
||||
|
||||
def __len__(self):
|
||||
names = ffi.new('git_strarray *')
|
||||
|
||||
try:
|
||||
err = C.git_remote_list(names, self._repo._repo)
|
||||
check_error(err)
|
||||
|
||||
return names.count
|
||||
finally:
|
||||
C.git_strarray_free(names)
|
||||
|
||||
def __iter__(self):
|
||||
names = ffi.new('git_strarray *')
|
||||
|
||||
try:
|
||||
err = C.git_remote_list(names, self._repo._repo)
|
||||
check_error(err)
|
||||
|
||||
cremote = ffi.new('git_remote **')
|
||||
for i in range(names.count):
|
||||
err = C.git_remote_lookup(cremote, self._repo._repo, names.strings[i])
|
||||
check_error(err)
|
||||
|
||||
yield Remote(self._repo, cremote[0])
|
||||
finally:
|
||||
C.git_strarray_free(names)
|
||||
|
||||
def __getitem__(self, name):
|
||||
if isinstance(name, int):
|
||||
return list(self)[name]
|
||||
|
||||
cremote = ffi.new('git_remote **')
|
||||
err = C.git_remote_lookup(cremote, self._repo._repo, to_bytes(name))
|
||||
check_error(err)
|
||||
|
||||
return Remote(self._repo, cremote[0])
|
||||
|
||||
def create(self, name, url, fetch=None):
|
||||
"""Create a new remote with the given name and url. Returns a <Remote>
|
||||
object.
|
||||
|
||||
If 'fetch' is provided, this fetch refspec will be used instead of the default
|
||||
"""
|
||||
|
||||
cremote = ffi.new('git_remote **')
|
||||
|
||||
if fetch:
|
||||
err = C.git_remote_create_with_fetchspec(cremote, self._repo._repo, to_bytes(name), to_bytes(url), to_bytes(fetch))
|
||||
else:
|
||||
err = C.git_remote_create(cremote, self._repo._repo, to_bytes(name), to_bytes(url))
|
||||
|
||||
check_error(err)
|
||||
|
||||
return Remote(self._repo, cremote[0])
|
||||
|
||||
def rename(self, name, new_name):
|
||||
"""Rename a remote in the configuration. The refspecs in standard
|
||||
format will be renamed.
|
||||
|
||||
Returns a list of fetch refspecs (list of strings) which were not in
|
||||
the standard format and thus could not be remapped.
|
||||
"""
|
||||
|
||||
if not new_name:
|
||||
raise ValueError("Current remote name must be a non-empty string")
|
||||
|
||||
if not new_name:
|
||||
raise ValueError("New remote name must be a non-empty string")
|
||||
|
||||
problems = ffi.new('git_strarray *')
|
||||
err = C.git_remote_rename(problems, self._repo._repo, to_bytes(name), to_bytes(new_name))
|
||||
check_error(err)
|
||||
|
||||
ret = strarray_to_strings(problems)
|
||||
C.git_strarray_free(problems)
|
||||
|
||||
return ret
|
||||
|
||||
def delete(self, name):
|
||||
"""Remove a remote from the configuration
|
||||
|
||||
All remote-tracking branches and configuration settings for the remote will be removed.
|
||||
"""
|
||||
err = C.git_remote_delete(self._repo._repo, to_bytes(name))
|
||||
check_error(err)
|
||||
|
||||
def set_url(self, name, url):
|
||||
""" Set the URL for a remote
|
||||
"""
|
||||
err = C.git_remote_set_url(self._repo._repo, to_bytes(name), to_bytes(url))
|
||||
check_error(err)
|
||||
|
||||
def set_push_url(self, name, url):
|
||||
"""Set the push-URL for a remote
|
||||
"""
|
||||
err = C.git_remote_set_pushurl(self._repo._repo, to_bytes(name), to_bytes(url))
|
||||
check_error(err)
|
||||
|
||||
def add_fetch(self, name, refspec):
|
||||
"""Add a fetch refspec (str) to the remote
|
||||
"""
|
||||
|
||||
err = C.git_remote_add_fetch(self._repo._repo, to_bytes(name), to_bytes(refspec))
|
||||
check_error(err)
|
||||
|
||||
def add_push(self, name, refspec):
|
||||
"""Add a push refspec (str) to the remote
|
||||
"""
|
||||
|
||||
err = C.git_remote_add_push(self._repo._repo, to_bytes(name), to_bytes(refspec))
|
||||
check_error(err)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -28,6 +28,11 @@
|
||||
from _pygit2 import option
|
||||
from _pygit2 import GIT_OPT_GET_SEARCH_PATH, GIT_OPT_SET_SEARCH_PATH
|
||||
from _pygit2 import GIT_OPT_GET_MWINDOW_SIZE, GIT_OPT_SET_MWINDOW_SIZE
|
||||
from _pygit2 import GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT
|
||||
from _pygit2 import GIT_OPT_SET_CACHE_OBJECT_LIMIT
|
||||
from _pygit2 import GIT_OPT_GET_CACHED_MEMORY
|
||||
from _pygit2 import GIT_OPT_ENABLE_CACHING
|
||||
from _pygit2 import GIT_OPT_SET_CACHE_MAX_SIZE
|
||||
|
||||
|
||||
class SearchPathList(object):
|
||||
@ -64,3 +69,36 @@ class Settings(object):
|
||||
@mwindow_size.setter
|
||||
def mwindow_size(self, value):
|
||||
option(GIT_OPT_SET_MWINDOW_SIZE, value)
|
||||
|
||||
@property
|
||||
def mwindow_mapped_limit(self):
|
||||
"""Mwindow mapped limit"""
|
||||
return option(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT)
|
||||
|
||||
@mwindow_mapped_limit.setter
|
||||
def mwindow_mapped_limit(self, value):
|
||||
"""Mwindow mapped limit"""
|
||||
return option(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, value)
|
||||
|
||||
@property
|
||||
def cached_memory(self):
|
||||
"""Maximum mmap window size"""
|
||||
return option(GIT_OPT_GET_CACHED_MEMORY)
|
||||
|
||||
def enable_caching(self, value=True):
|
||||
return option(GIT_OPT_ENABLE_CACHING, value)
|
||||
|
||||
def cache_max_size(self, value):
|
||||
return option(GIT_OPT_SET_CACHE_MAX_SIZE, value)
|
||||
|
||||
def cache_object_limit(self, object_type, value):
|
||||
"""Set the maximum data size for the given type of object to be
|
||||
considered eligible for caching in memory.
|
||||
|
||||
Setting to value to zero means that that type of object will not
|
||||
be cached. Defaults to 0 for GIT_OBJ_BLOB (i.e. won't cache
|
||||
blobs) and 4k for GIT_OBJ_COMMIT, GIT_OBJ_TREE, and GIT_OBJ_TAG.
|
||||
"""
|
||||
return option(GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, value)
|
||||
|
||||
|
||||
|
79
pygit2/submodule.py
Normal file
79
pygit2/submodule.py
Normal file
@ -0,0 +1,79 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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 .errors import check_error
|
||||
from .ffi import ffi, C
|
||||
|
||||
class Submodule(object):
|
||||
|
||||
@classmethod
|
||||
def _from_c(cls, repo, cptr):
|
||||
subm = cls.__new__(cls)
|
||||
|
||||
subm._repo = repo
|
||||
subm._subm = cptr
|
||||
|
||||
return subm
|
||||
|
||||
def __del__(self):
|
||||
C.git_submodule_free(self._subm)
|
||||
|
||||
def open(self):
|
||||
"""Open the repository for a submodule."""
|
||||
crepo = ffi.new('git_repository **')
|
||||
err = C.git_submodule_open(crepo, self._subm)
|
||||
check_error(err)
|
||||
|
||||
return self._repo._from_c(crepo[0], True)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""Name of the submodule."""
|
||||
name = C.git_submodule_name(self._subm)
|
||||
return ffi.string(name).decode('utf-8')
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
"""Path of the submodule."""
|
||||
path = C.git_submodule_path(self._subm)
|
||||
return ffi.string(path).decode('utf-8')
|
||||
|
||||
@property
|
||||
def url(self):
|
||||
"""URL of the submodule."""
|
||||
url = C.git_submodule_url(self._subm)
|
||||
return ffi.string(url).decode('utf-8')
|
||||
|
||||
@property
|
||||
def branch(self):
|
||||
"""Branch that is to be tracked by the submodule."""
|
||||
branch = C.git_submodule_branch(self._subm)
|
||||
return ffi.string(branch).decode('utf-8')
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -50,34 +50,62 @@ def strarray_to_strings(arr):
|
||||
return l
|
||||
|
||||
|
||||
def strings_to_strarray(l):
|
||||
"""Convert a list of strings to a git_strarray
|
||||
class StrArray(object):
|
||||
"""A git_strarray wrapper
|
||||
|
||||
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.
|
||||
Use this in order to get a git_strarray* to pass to libgit2 out of a
|
||||
list of strings. This has a context manager, which you should use, e.g.
|
||||
|
||||
with StrArray(list_of_strings) as arr:
|
||||
C.git_function_that_takes_strarray(arr)
|
||||
"""
|
||||
|
||||
if not isinstance(l, list):
|
||||
raise TypeError("Value must be a list")
|
||||
def __init__(self, l):
|
||||
# Allow passing in None as lg2 typically considers them the same as empty
|
||||
if l is None:
|
||||
self.array = ffi.NULL
|
||||
return
|
||||
|
||||
arr = ffi.new('git_strarray *')
|
||||
strings = ffi.new('char *[]', len(l))
|
||||
if not isinstance(l, list):
|
||||
raise TypeError("Value must be a list")
|
||||
|
||||
# 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)
|
||||
strings = [None] * len(l)
|
||||
for i in range(len(l)):
|
||||
if not is_string(l[i]):
|
||||
raise TypeError("Value must be a string")
|
||||
|
||||
for i in range(len(l)):
|
||||
if not is_string(l[i]):
|
||||
raise TypeError("Value must be a string")
|
||||
strings[i] = ffi.new('char []', to_bytes(l[i]))
|
||||
|
||||
s = ffi.new('char []', to_bytes(l[i]))
|
||||
refs[i] = s
|
||||
strings[i] = s
|
||||
self._arr = ffi.new('char *[]', strings)
|
||||
self._strings = strings
|
||||
self.array = ffi.new('git_strarray *', [self._arr, len(strings)])
|
||||
|
||||
arr.strings = strings
|
||||
arr.count = len(l)
|
||||
def __enter__(self):
|
||||
return self.array
|
||||
|
||||
return arr, refs
|
||||
def __exit__(self, type, value, traceback):
|
||||
pass
|
||||
|
||||
|
||||
class GenericIterator(object):
|
||||
"""Helper to easily implement an iterator.
|
||||
|
||||
The constructor gets a container which must implement __len__ and
|
||||
__getitem__
|
||||
"""
|
||||
|
||||
def __init__(self, container):
|
||||
self.container = container
|
||||
self.length = len(container)
|
||||
self.idx = 0
|
||||
|
||||
def next(self):
|
||||
return self.__next__()
|
||||
|
||||
def __next__(self):
|
||||
idx = self.idx
|
||||
if idx >= self.length:
|
||||
raise StopIteration
|
||||
|
||||
self.idx += 1
|
||||
return self.container[idx]
|
||||
|
@ -1,26 +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.
|
||||
|
||||
__version__ = '0.21.2'
|
171
setup.py
171
setup.py
@ -1,7 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# coding: UTF-8
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -28,45 +28,43 @@
|
||||
|
||||
"""Setup file for pygit2."""
|
||||
|
||||
# Import from the future
|
||||
from __future__ import print_function
|
||||
|
||||
# Import from the Standard Library
|
||||
import codecs
|
||||
from distutils.core import setup, Extension, Command
|
||||
from distutils.command.build import build
|
||||
from distutils.command.sdist import sdist
|
||||
from distutils import log
|
||||
import os
|
||||
from os import getenv, listdir, pathsep
|
||||
from os.path import abspath, isfile
|
||||
from setuptools import setup, Extension, Command
|
||||
import shlex
|
||||
from subprocess import Popen, PIPE
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
# Read version from local pygit2/version.py without pulling in
|
||||
# pygit2/__init__.py
|
||||
sys.path.insert(0, 'pygit2')
|
||||
from version import __version__
|
||||
|
||||
# Python 2 support
|
||||
# See https://github.com/libgit2/pygit2/pull/180 for a discussion about this.
|
||||
if sys.version_info[0] == 2:
|
||||
u = lambda s: unicode(s, 'utf-8')
|
||||
# Get cffi major version
|
||||
try:
|
||||
import cffi
|
||||
except ImportError:
|
||||
cffi_major_version = None
|
||||
else:
|
||||
u = str
|
||||
cffi_major_version = cffi.__version_info__[0]
|
||||
|
||||
# Import stuff from pygit2/_utils.py without loading the whole pygit2 package
|
||||
sys.path.insert(0, 'pygit2')
|
||||
from _build import __version__, get_libgit2_paths
|
||||
if cffi_major_version == 0:
|
||||
from _run import ffi, preamble, C_KEYWORDS
|
||||
ffi.verify(preamble, **C_KEYWORDS)
|
||||
del sys.path[0]
|
||||
|
||||
|
||||
# Use environment variable LIBGIT2 to set your own libgit2 configuration.
|
||||
libgit2_path = os.getenv("LIBGIT2")
|
||||
if libgit2_path is None:
|
||||
if os.name == 'nt':
|
||||
program_files = os.getenv("ProgramFiles")
|
||||
libgit2_path = '%s\libgit2' % program_files
|
||||
else:
|
||||
libgit2_path = '/usr/local'
|
||||
libgit2_bin, libgit2_include, libgit2_lib = get_libgit2_paths()
|
||||
|
||||
libgit2_bin = os.path.join(libgit2_path, 'bin')
|
||||
libgit2_include = os.path.join(libgit2_path, 'include')
|
||||
libgit2_lib = os.getenv('LIBGIT2_LIB', os.path.join(libgit2_path, 'lib'))
|
||||
pygit2_exts = [os.path.join('src', name) for name in os.listdir('src')
|
||||
pygit2_exts = [os.path.join('src', name) for name in sorted(listdir('src'))
|
||||
if name.endswith('.c')]
|
||||
|
||||
|
||||
@ -79,7 +77,6 @@ class TestCommand(Command):
|
||||
|
||||
def initialize_options(self):
|
||||
self.args = ''
|
||||
pass
|
||||
|
||||
def finalize_options(self):
|
||||
pass
|
||||
@ -88,7 +85,7 @@ class TestCommand(Command):
|
||||
self.run_command('build')
|
||||
bld = self.distribution.get_command_obj('build')
|
||||
# Add build_lib in to sys.path so that unittest can found DLLs and libs
|
||||
sys.path = [os.path.abspath(bld.build_lib)] + sys.path
|
||||
sys.path = [abspath(bld.build_lib)] + sys.path
|
||||
|
||||
test_argv0 = [sys.argv[0] + ' test --args=']
|
||||
# For transfering args to unittest, we have to split args by ourself,
|
||||
@ -102,43 +99,10 @@ class TestCommand(Command):
|
||||
unittest.main(None, defaultTest='test.test_suite', argv=test_argv)
|
||||
|
||||
|
||||
class BuildWithDLLs(build):
|
||||
|
||||
# On Windows, we install the git2.dll too.
|
||||
def _get_dlls(self):
|
||||
# return a list of (FQ-in-name, relative-out-name) tuples.
|
||||
ret = []
|
||||
bld_ext = self.distribution.get_command_obj('build_ext')
|
||||
compiler_type = bld_ext.compiler.compiler_type
|
||||
libgit2_dlls = []
|
||||
if compiler_type == 'msvc':
|
||||
libgit2_dlls.append('git2.dll')
|
||||
elif compiler_type == 'mingw32':
|
||||
libgit2_dlls.append('libgit2.dll')
|
||||
look_dirs = [libgit2_bin] + os.getenv("PATH", "").split(os.pathsep)
|
||||
target = os.path.abspath(self.build_lib)
|
||||
for bin in libgit2_dlls:
|
||||
for look in look_dirs:
|
||||
f = os.path.join(look, bin)
|
||||
if os.path.isfile(f):
|
||||
ret.append((f, target))
|
||||
break
|
||||
else:
|
||||
log.warn("Could not find required DLL %r to include", bin)
|
||||
log.debug("(looked in %s)", look_dirs)
|
||||
return ret
|
||||
|
||||
def run(self):
|
||||
build.run(self)
|
||||
if os.name == 'nt':
|
||||
# On Windows we package up the dlls with the plugin.
|
||||
for s, d in self._get_dlls():
|
||||
self.copy_file(s, d)
|
||||
|
||||
|
||||
class sdist_files_from_git(sdist):
|
||||
def get_file_list(self):
|
||||
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE)
|
||||
popen = Popen(['git', 'ls-files'], stdout=PIPE, stderr=PIPE,
|
||||
universal_newlines=True)
|
||||
stdoutdata, stderrdata = popen.communicate()
|
||||
if popen.returncode != 0:
|
||||
print(stderrdata)
|
||||
@ -156,27 +120,68 @@ class sdist_files_from_git(sdist):
|
||||
self.write_manifest()
|
||||
|
||||
|
||||
cmdclass = {
|
||||
'test': TestCommand,
|
||||
'sdist': sdist_files_from_git}
|
||||
|
||||
if os.name == 'nt':
|
||||
# BuildWithDLLs can copy external DLLs into source directory.
|
||||
cmdclass['build'] = BuildWithDLLs
|
||||
|
||||
classifiers = [
|
||||
"Development Status :: 3 - Alpha",
|
||||
"Intended Audience :: Developers",
|
||||
"Topic :: Software Development :: Version Control"]
|
||||
|
||||
|
||||
with codecs.open('README.rst', 'r', 'utf-8') as readme:
|
||||
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()
|
||||
cmdclass = {
|
||||
'test': TestCommand,
|
||||
'sdist': sdist_files_from_git,
|
||||
}
|
||||
|
||||
|
||||
# On Windows, we install the git2.dll too.
|
||||
class BuildWithDLLs(build):
|
||||
def _get_dlls(self):
|
||||
# return a list of (FQ-in-name, relative-out-name) tuples.
|
||||
ret = []
|
||||
bld_ext = self.distribution.get_command_obj('build_ext')
|
||||
compiler_type = bld_ext.compiler.compiler_type
|
||||
libgit2_dlls = []
|
||||
if compiler_type == 'msvc':
|
||||
libgit2_dlls.append('git2.dll')
|
||||
elif compiler_type == 'mingw32':
|
||||
libgit2_dlls.append('libgit2.dll')
|
||||
look_dirs = [libgit2_bin] + getenv("PATH", "").split(pathsep)
|
||||
target = abspath(self.build_lib)
|
||||
for bin in libgit2_dlls:
|
||||
for look in look_dirs:
|
||||
f = os.path.join(look, bin)
|
||||
if isfile(f):
|
||||
ret.append((f, target))
|
||||
break
|
||||
else:
|
||||
log.warn("Could not find required DLL %r to include", bin)
|
||||
log.debug("(looked in %s)", look_dirs)
|
||||
return ret
|
||||
|
||||
def run(self):
|
||||
build.run(self)
|
||||
for s, d in self._get_dlls():
|
||||
self.copy_file(s, d)
|
||||
|
||||
# On Windows we package up the dlls with the plugin.
|
||||
if os.name == 'nt':
|
||||
cmdclass['build'] = BuildWithDLLs
|
||||
|
||||
extra_args = {
|
||||
'ext_modules': [
|
||||
Extension('_pygit2', pygit2_exts, libraries=['git2'],
|
||||
include_dirs=[libgit2_include],
|
||||
library_dirs=[libgit2_lib]),
|
||||
# FFI is added in the build step
|
||||
],
|
||||
}
|
||||
|
||||
if cffi_major_version == 0:
|
||||
extra_args['ext_modules'].append(ffi.verifier.get_extension())
|
||||
else:
|
||||
extra_args['cffi_modules'] = ['pygit2/_run.py:ffi']
|
||||
|
||||
|
||||
setup(name='pygit2',
|
||||
description='Python bindings for libgit2.',
|
||||
@ -184,18 +189,14 @@ setup(name='pygit2',
|
||||
version=__version__,
|
||||
url='http://github.com/libgit2/pygit2',
|
||||
classifiers=classifiers,
|
||||
license='GPLv2',
|
||||
maintainer=u('J. David Ibáñez'),
|
||||
license='GPLv2 with linking exception',
|
||||
maintainer=u'J. David Ibáñez',
|
||||
maintainer_email='jdavid.ibp@gmail.com',
|
||||
long_description=long_description,
|
||||
packages=['pygit2'],
|
||||
package_data={'pygit2': ['decl.h']},
|
||||
install_requires=['cffi'],
|
||||
ext_modules=[
|
||||
Extension('_pygit2', pygit2_exts,
|
||||
include_dirs=[libgit2_include, 'include'],
|
||||
library_dirs=[libgit2_lib],
|
||||
libraries=['git2']),
|
||||
ffi_ext,
|
||||
],
|
||||
cmdclass=cmdclass)
|
||||
setup_requires=['cffi'],
|
||||
install_requires=['cffi', 'six'],
|
||||
zip_safe=False,
|
||||
cmdclass=cmdclass,
|
||||
**extra_args)
|
||||
|
399
src/blame.c
399
src/blame.c
@ -1,399 +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 "signature.h"
|
||||
#include "blame.h"
|
||||
|
||||
extern PyObject *GitError;
|
||||
|
||||
extern PyTypeObject BlameType;
|
||||
extern PyTypeObject BlameIterType;
|
||||
extern PyTypeObject BlameHunkType;
|
||||
|
||||
PyObject*
|
||||
wrap_blame(git_blame *blame, Repository *repo)
|
||||
{
|
||||
Blame *py_blame;
|
||||
|
||||
py_blame = PyObject_New(Blame, &BlameType);
|
||||
if (py_blame) {
|
||||
Py_INCREF(repo);
|
||||
py_blame->repo = repo;
|
||||
py_blame->blame = blame;
|
||||
}
|
||||
|
||||
return (PyObject*) py_blame;
|
||||
}
|
||||
|
||||
#include <stdio.h>
|
||||
PyObject*
|
||||
wrap_blame_hunk(const git_blame_hunk *hunk, Blame *blame)
|
||||
{
|
||||
BlameHunk *py_hunk = NULL;
|
||||
int err;
|
||||
|
||||
if (!hunk)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
py_hunk = PyObject_New(BlameHunk, &BlameHunkType);
|
||||
if (py_hunk == NULL)
|
||||
return NULL;
|
||||
|
||||
py_hunk->lines_in_hunk = hunk->lines_in_hunk;
|
||||
py_hunk->final_commit_id = git_oid_allocfmt(&hunk->final_commit_id);
|
||||
py_hunk->final_start_line_number = hunk->final_start_line_number;
|
||||
|
||||
py_hunk->final_signature = NULL;
|
||||
if (hunk->final_signature) {
|
||||
err = git_signature_dup(&py_hunk->final_signature,
|
||||
hunk->final_signature);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
py_hunk->orig_commit_id = git_oid_allocfmt(&hunk->orig_commit_id);
|
||||
py_hunk->orig_path = hunk->orig_path != NULL ?
|
||||
strdup(hunk->orig_path) : NULL;
|
||||
py_hunk->orig_start_line_number = hunk->orig_start_line_number;
|
||||
|
||||
py_hunk->orig_signature = NULL;
|
||||
if (hunk->orig_signature) {
|
||||
err = git_signature_dup(&py_hunk->orig_signature,
|
||||
hunk->orig_signature);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
py_hunk->boundary = hunk->boundary;
|
||||
return (PyObject*) py_hunk;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BlameHunk_final_committer__doc__, "Final committer.");
|
||||
|
||||
PyObject *
|
||||
BlameHunk_final_committer__get__(BlameHunk *self)
|
||||
{
|
||||
if (!self->final_signature)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
return build_signature((Object*) self, self->final_signature, "utf-8");
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(BlameHunk_orig_committer__doc__, "Origin committer.");
|
||||
|
||||
PyObject *
|
||||
BlameHunk_orig_committer__get__(BlameHunk *self)
|
||||
{
|
||||
if (!self->orig_signature)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
return build_signature((Object*) self, self->orig_signature, "utf-8");
|
||||
}
|
||||
|
||||
static int
|
||||
BlameHunk_init(BlameHunk *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
self->final_commit_id = NULL;
|
||||
self->final_signature = NULL;
|
||||
self->orig_commit_id = NULL;
|
||||
self->orig_path = NULL;
|
||||
self->orig_signature = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
BlameHunk_dealloc(BlameHunk *self)
|
||||
{
|
||||
free(self->final_commit_id);
|
||||
if (self->final_signature)
|
||||
git_signature_free(self->final_signature);
|
||||
free(self->orig_commit_id);
|
||||
if (self->orig_path)
|
||||
free(self->orig_path);
|
||||
if (self->orig_signature)
|
||||
git_signature_free(self->orig_signature);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMemberDef BlameHunk_members[] = {
|
||||
MEMBER(BlameHunk, lines_in_hunk, T_UINT, "Number of lines."),
|
||||
MEMBER(BlameHunk, final_commit_id, T_STRING, "Last changed oid."),
|
||||
MEMBER(BlameHunk, final_start_line_number, T_UINT, "final start line no."),
|
||||
MEMBER(BlameHunk, orig_commit_id, T_STRING, "oid where hunk was found."),
|
||||
MEMBER(BlameHunk, orig_path, T_STRING, "Origin path."),
|
||||
MEMBER(BlameHunk, orig_start_line_number, T_UINT, "Origin start line no."),
|
||||
MEMBER(BlameHunk, boundary, T_BOOL, "Tracked to a boundary commit."),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef BlameHunk_getseters[] = {
|
||||
GETTER(BlameHunk, final_committer),
|
||||
GETTER(BlameHunk, orig_committer),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(BlameHunk__doc__, "Blame Hunk object.");
|
||||
|
||||
PyTypeObject BlameHunkType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.BlameHunk", /* tp_name */
|
||||
sizeof(BlameHunk), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)BlameHunk_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 */
|
||||
BlameHunk__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
BlameHunk_members, /* tp_members */
|
||||
BlameHunk_getseters, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
0, /* tp_descr_set */
|
||||
0, /* tp_dictoffset */
|
||||
(initproc)BlameHunk_init, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
|
||||
PyObject *
|
||||
BlameIter_iternext(BlameIter *self)
|
||||
{
|
||||
if (self->i < self->n)
|
||||
return wrap_blame_hunk(git_blame_get_hunk_byindex(
|
||||
self->blame->blame, self->i++), self->blame);
|
||||
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
BlameIter_dealloc(BlameIter *self)
|
||||
{
|
||||
Py_CLEAR(self->blame);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(BlameIter__doc__, "Blame iterator object.");
|
||||
|
||||
PyTypeObject BlameIterType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.BlameIter", /* tp_name */
|
||||
sizeof(BlameIter), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)BlameIter_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 */
|
||||
BlameIter__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
PyObject_SelfIter, /* tp_iter */
|
||||
(iternextfunc) BlameIter_iternext, /* tp_iternext */
|
||||
};
|
||||
|
||||
|
||||
PyObject *
|
||||
Blame_iter(Blame *self)
|
||||
{
|
||||
BlameIter *iter;
|
||||
|
||||
iter = PyObject_New(BlameIter, &BlameIterType);
|
||||
if (iter != NULL) {
|
||||
Py_INCREF(self);
|
||||
iter->blame = self;
|
||||
iter->i = 0;
|
||||
iter->n = git_blame_get_hunk_count(self->blame);
|
||||
}
|
||||
return (PyObject*)iter;
|
||||
}
|
||||
|
||||
Py_ssize_t
|
||||
Blame_len(Blame *self)
|
||||
{
|
||||
assert(self->blame);
|
||||
return (Py_ssize_t)git_blame_get_hunk_count(self->blame);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
Blame_getitem(Blame *self, PyObject *value)
|
||||
{
|
||||
size_t i;
|
||||
const git_blame_hunk *hunk;
|
||||
|
||||
if (PyLong_Check(value) < 0) {
|
||||
PyErr_SetObject(PyExc_IndexError, value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i = PyLong_AsUnsignedLong(value);
|
||||
if (PyErr_Occurred()) {
|
||||
PyErr_SetObject(PyExc_IndexError, value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hunk = git_blame_get_hunk_byindex(self->blame, i);
|
||||
if (!hunk) {
|
||||
PyErr_SetObject(PyExc_IndexError, value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wrap_blame_hunk(hunk, self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Blame_for_line__doc__,
|
||||
"for_line(line_no) -> hunk\n"
|
||||
"\n"
|
||||
"Returns the blame hunk data for the given \"line_no\" in blame.\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"line_no\n"
|
||||
" Line number, countings starts with 1.");
|
||||
|
||||
PyObject *
|
||||
Blame_for_line(Blame *self, PyObject *args)
|
||||
{
|
||||
size_t line_no;
|
||||
const git_blame_hunk *hunk;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "I", &line_no))
|
||||
return NULL;
|
||||
|
||||
hunk = git_blame_get_hunk_byline(self->blame, line_no);
|
||||
if (!hunk) {
|
||||
PyErr_SetObject(PyExc_IndexError, args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wrap_blame_hunk(hunk, self);
|
||||
}
|
||||
|
||||
static void
|
||||
Blame_dealloc(Blame *self)
|
||||
{
|
||||
git_blame_free(self->blame);
|
||||
Py_CLEAR(self->repo);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMappingMethods Blame_as_mapping = {
|
||||
(lenfunc)Blame_len, /* mp_length */
|
||||
(binaryfunc)Blame_getitem, /* mp_subscript */
|
||||
0, /* mp_ass_subscript */
|
||||
};
|
||||
|
||||
static PyMethodDef Blame_methods[] = {
|
||||
METHOD(Blame, for_line, METH_VARARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(Blame__doc__, "Blame objects.");
|
||||
|
||||
PyTypeObject BlameType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.Blame", /* tp_name */
|
||||
sizeof(Blame), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)Blame_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 */
|
||||
&Blame_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 */
|
||||
Blame__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
(getiterfunc)Blame_iter, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
Blame_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 */
|
||||
0, /* tp_init */
|
||||
0, /* tp_alloc */
|
||||
0, /* tp_new */
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -27,11 +27,12 @@
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include "blob.h"
|
||||
#include "diff.h"
|
||||
#include "error.h"
|
||||
#include "utils.h"
|
||||
#include "object.h"
|
||||
#include "blob.h"
|
||||
#include "patch.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern PyObject *GitError;
|
||||
|
||||
@ -132,7 +133,7 @@ PyDoc_STRVAR(Blob_size__doc__, "Size.");
|
||||
PyObject *
|
||||
Blob_size__get__(Blob *self)
|
||||
{
|
||||
return PyLong_FromLongLong(git_blob_rawsize(self->blob));
|
||||
return PyInt_FromLongLong(git_blob_rawsize(self->blob));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
27
src/branch.c
27
src/branch.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -81,6 +81,28 @@ Branch_is_head(Branch *self)
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Branch_is_checked_out__doc__,
|
||||
"is_checked_out()\n"
|
||||
"\n"
|
||||
"True if branch is checked out by any repo connected to the current one, "
|
||||
" False otherwise.");
|
||||
|
||||
PyObject *
|
||||
Branch_is_checked_out(Branch *self)
|
||||
{
|
||||
int err;
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
err = git_branch_is_checked_out(self->reference);
|
||||
if (err == 1)
|
||||
Py_RETURN_TRUE;
|
||||
else if (err == 0)
|
||||
Py_RETURN_FALSE;
|
||||
else
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Branch_rename__doc__,
|
||||
"rename(name, force=False)\n"
|
||||
@ -101,7 +123,7 @@ Branch_rename(Branch *self, PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "s|i", &c_name, &force))
|
||||
return NULL;
|
||||
|
||||
err = git_branch_move(&c_out, self->reference, c_name, force, NULL, NULL);
|
||||
err = git_branch_move(&c_out, self->reference, c_name, force);
|
||||
if (err == GIT_OK)
|
||||
return wrap_branch(c_out, self->repo);
|
||||
else
|
||||
@ -234,6 +256,7 @@ Branch_upstream_name__get__(Branch *self)
|
||||
PyMethodDef Branch_methods[] = {
|
||||
METHOD(Branch, delete, METH_NOARGS),
|
||||
METHOD(Branch, is_head, METH_NOARGS),
|
||||
METHOD(Branch, is_checked_out, METH_NOARGS),
|
||||
METHOD(Branch, rename, METH_VARARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -34,6 +34,7 @@
|
||||
|
||||
PyObject* Branch_delete(Branch *self, PyObject *args);
|
||||
PyObject* Branch_is_head(Branch *self);
|
||||
PyObject* Branch_is_checked_out(Branch *self);
|
||||
PyObject* Branch_move(Branch *self, PyObject *args);
|
||||
|
||||
PyObject* wrap_branch(git_reference *c_reference, Repository *repo);
|
||||
|
14
src/commit.c
14
src/commit.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -35,6 +35,7 @@
|
||||
#include "oid.h"
|
||||
|
||||
extern PyTypeObject TreeType;
|
||||
extern PyObject *GitError;
|
||||
|
||||
|
||||
PyDoc_STRVAR(Commit_message_encoding__doc__, "Message encoding.");
|
||||
@ -79,7 +80,7 @@ PyDoc_STRVAR(Commit_commit_time__doc__, "Commit time.");
|
||||
PyObject *
|
||||
Commit_commit_time__get__(Commit *commit)
|
||||
{
|
||||
return PyLong_FromLongLong(git_commit_time(commit->commit));
|
||||
return PyInt_FromLongLong(git_commit_time(commit->commit));
|
||||
}
|
||||
|
||||
|
||||
@ -88,7 +89,7 @@ PyDoc_STRVAR(Commit_commit_time_offset__doc__, "Commit time offset.");
|
||||
PyObject *
|
||||
Commit_commit_time_offset__get__(Commit *commit)
|
||||
{
|
||||
return PyLong_FromLong(git_commit_time_offset(commit->commit));
|
||||
return PyInt_FromLong(git_commit_time_offset(commit->commit));
|
||||
}
|
||||
|
||||
|
||||
@ -131,8 +132,11 @@ Commit_tree__get__(Commit *commit)
|
||||
int err;
|
||||
|
||||
err = git_commit_tree(&tree, commit->commit);
|
||||
if (err == GIT_ENOTFOUND)
|
||||
Py_RETURN_NONE;
|
||||
if (err == GIT_ENOTFOUND) {
|
||||
char tree_id[GIT_OID_HEXSZ + 1] = { 0 };
|
||||
git_oid_fmt(tree_id, git_commit_tree_id(commit->commit));
|
||||
return PyErr_Format(GitError, "Unable to read tree %s", tree_id);
|
||||
}
|
||||
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
627
src/diff.c
627
src/diff.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -28,22 +28,26 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <structmember.h>
|
||||
#include "diff.h"
|
||||
#include "error.h"
|
||||
#include "oid.h"
|
||||
#include "patch.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
#include "diff.h"
|
||||
|
||||
extern PyObject *GitError;
|
||||
|
||||
extern PyTypeObject TreeType;
|
||||
extern PyTypeObject IndexType;
|
||||
extern PyTypeObject DiffType;
|
||||
extern PyTypeObject HunkType;
|
||||
extern PyTypeObject DiffDeltaType;
|
||||
extern PyTypeObject DiffFileType;
|
||||
extern PyTypeObject DiffHunkType;
|
||||
extern PyTypeObject DiffLineType;
|
||||
extern PyTypeObject DiffStatsType;
|
||||
extern PyTypeObject RepositoryType;
|
||||
|
||||
PyTypeObject PatchType;
|
||||
|
||||
PyObject*
|
||||
PyObject *
|
||||
wrap_diff(git_diff *diff, Repository *repo)
|
||||
{
|
||||
Diff *py_diff;
|
||||
@ -52,148 +56,162 @@ wrap_diff(git_diff *diff, Repository *repo)
|
||||
if (py_diff) {
|
||||
Py_INCREF(repo);
|
||||
py_diff->repo = repo;
|
||||
py_diff->list = diff;
|
||||
py_diff->diff = diff;
|
||||
}
|
||||
|
||||
return (PyObject*) py_diff;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
wrap_patch(git_patch *patch)
|
||||
wrap_diff_file(const git_diff_file *file)
|
||||
{
|
||||
Patch *py_patch;
|
||||
DiffFile *py_file;
|
||||
|
||||
if (!patch)
|
||||
if (!file)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
py_patch = PyObject_New(Patch, &PatchType);
|
||||
if (py_patch) {
|
||||
size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
|
||||
const git_diff_delta *delta;
|
||||
const git_diff_hunk *hunk;
|
||||
const git_diff_line *line;
|
||||
int err;
|
||||
|
||||
delta = git_patch_get_delta(patch);
|
||||
|
||||
py_patch->old_file_path = delta->old_file.path;
|
||||
py_patch->new_file_path = delta->new_file.path;
|
||||
py_patch->status = git_diff_status_char(delta->status);
|
||||
py_patch->similarity = delta->similarity;
|
||||
py_patch->flags = delta->flags;
|
||||
py_patch->old_id = git_oid_allocfmt(&delta->old_file.id);
|
||||
py_patch->new_id = git_oid_allocfmt(&delta->new_file.id);
|
||||
|
||||
git_patch_line_stats(NULL, &additions, &deletions, patch);
|
||||
py_patch->additions = additions;
|
||||
py_patch->deletions = deletions;
|
||||
|
||||
hunk_amounts = git_patch_num_hunks(patch);
|
||||
py_patch->hunks = PyList_New(hunk_amounts);
|
||||
for (i = 0; i < hunk_amounts; ++i) {
|
||||
Hunk *py_hunk = NULL;
|
||||
|
||||
err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
py_hunk = PyObject_New(Hunk, &HunkType);
|
||||
if (py_hunk != NULL) {
|
||||
py_hunk->old_start = hunk->old_start;
|
||||
py_hunk->old_lines = hunk->old_lines;
|
||||
py_hunk->new_start = hunk->new_start;
|
||||
py_hunk->new_lines = hunk->new_lines;
|
||||
|
||||
py_hunk->lines = PyList_New(lines_in_hunk);
|
||||
for (j = 0; j < lines_in_hunk; ++j) {
|
||||
PyObject *py_line_origin = NULL, *py_line = NULL;
|
||||
|
||||
err = git_patch_get_line_in_hunk(&line, patch, i, j);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
py_line_origin = to_unicode_n(&line->origin, 1,
|
||||
NULL, NULL);
|
||||
py_line = to_unicode_n(line->content, line->content_len,
|
||||
NULL, NULL);
|
||||
PyList_SetItem(py_hunk->lines, j,
|
||||
Py_BuildValue("OO", py_line_origin, py_line));
|
||||
|
||||
Py_DECREF(py_line_origin);
|
||||
Py_DECREF(py_line);
|
||||
}
|
||||
|
||||
PyList_SetItem((PyObject*) py_patch->hunks, i,
|
||||
(PyObject*) py_hunk);
|
||||
}
|
||||
}
|
||||
py_file = PyObject_New(DiffFile, &DiffFileType);
|
||||
if (py_file) {
|
||||
py_file->id = git_oid_to_python(&file->id);
|
||||
py_file->path = file->path != NULL ? strdup(file->path) : NULL;
|
||||
py_file->size = file->size;
|
||||
py_file->flags = file->flags;
|
||||
py_file->mode = file->mode;
|
||||
}
|
||||
git_patch_free(patch);
|
||||
|
||||
return (PyObject*) py_patch;
|
||||
return (PyObject *) py_file;
|
||||
}
|
||||
|
||||
PyObject*
|
||||
diff_get_patch_byindex(git_diff *diff, size_t idx)
|
||||
PyObject *
|
||||
wrap_diff_delta(const git_diff_delta *delta)
|
||||
{
|
||||
git_patch *patch = NULL;
|
||||
DiffDelta *py_delta;
|
||||
|
||||
if (!delta)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
py_delta = PyObject_New(DiffDelta, &DiffDeltaType);
|
||||
if (py_delta) {
|
||||
py_delta->status = delta->status;
|
||||
py_delta->flags = delta->flags;
|
||||
py_delta->similarity = delta->similarity;
|
||||
py_delta->nfiles = delta->nfiles;
|
||||
py_delta->old_file = wrap_diff_file(&delta->old_file);
|
||||
py_delta->new_file = wrap_diff_file(&delta->new_file);
|
||||
}
|
||||
|
||||
return (PyObject *) py_delta;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
wrap_diff_hunk(git_patch *patch, size_t idx)
|
||||
{
|
||||
DiffHunk *py_hunk;
|
||||
const git_diff_hunk *hunk;
|
||||
const git_diff_line *line;
|
||||
size_t j, lines_in_hunk;
|
||||
int err;
|
||||
|
||||
err = git_patch_from_diff(&patch, diff, idx);
|
||||
err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, idx);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return (PyObject*) wrap_patch(patch);
|
||||
py_hunk = PyObject_New(DiffHunk, &DiffHunkType);
|
||||
if (py_hunk) {
|
||||
py_hunk->old_start = hunk->old_start;
|
||||
py_hunk->old_lines = hunk->old_lines;
|
||||
py_hunk->new_start = hunk->new_start;
|
||||
py_hunk->new_lines = hunk->new_lines;
|
||||
py_hunk->header = to_unicode_n((const char *) &hunk->header,
|
||||
hunk->header_len, NULL, NULL);
|
||||
|
||||
py_hunk->lines = PyList_New(lines_in_hunk);
|
||||
for (j = 0; j < lines_in_hunk; ++j) {
|
||||
PyObject *py_line = NULL;
|
||||
|
||||
err = git_patch_get_line_in_hunk(&line, patch, idx, j);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
py_line = wrap_diff_line(line);
|
||||
if (py_line == NULL)
|
||||
return NULL;
|
||||
|
||||
PyList_SetItem(py_hunk->lines, j, py_line);
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject *) py_hunk;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
wrap_diff_stats(git_diff *diff)
|
||||
{
|
||||
git_diff_stats *stats;
|
||||
DiffStats *py_stats;
|
||||
int err;
|
||||
|
||||
err = git_diff_get_stats(&stats, diff);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
py_stats = PyObject_New(DiffStats, &DiffStatsType);
|
||||
if (!py_stats) {
|
||||
git_diff_stats_free(stats);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_stats->stats = stats;
|
||||
|
||||
return (PyObject *) py_stats;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
wrap_diff_line(const git_diff_line *line)
|
||||
{
|
||||
DiffLine *py_line;
|
||||
|
||||
py_line = PyObject_New(DiffLine, &DiffLineType);
|
||||
if (py_line) {
|
||||
py_line->origin = line->origin;
|
||||
py_line->old_lineno = line->old_lineno;
|
||||
py_line->new_lineno = line->new_lineno;
|
||||
py_line->num_lines = line->num_lines;
|
||||
py_line->content = to_unicode_n(line->content, line->content_len,
|
||||
NULL, NULL);
|
||||
py_line->content_offset = line->content_offset;
|
||||
}
|
||||
|
||||
return (PyObject *) py_line;
|
||||
}
|
||||
|
||||
static void
|
||||
Patch_dealloc(Patch *self)
|
||||
DiffFile_dealloc(DiffFile *self)
|
||||
{
|
||||
Py_CLEAR(self->hunks);
|
||||
free(self->old_id);
|
||||
free(self->new_id);
|
||||
/* We do not have to free old_file_path and new_file_path, they will
|
||||
* be freed by git_diff_list_free in Diff_dealloc */
|
||||
Py_CLEAR(self->id);
|
||||
if (self->path)
|
||||
free(self->path);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMemberDef Patch_members[] = {
|
||||
MEMBER(Patch, old_file_path, T_STRING, "old file path"),
|
||||
MEMBER(Patch, new_file_path, T_STRING, "new file path"),
|
||||
MEMBER(Patch, old_id, T_STRING, "old oid"),
|
||||
MEMBER(Patch, new_id, T_STRING, "new oid"),
|
||||
MEMBER(Patch, status, T_CHAR, "status"),
|
||||
MEMBER(Patch, similarity, T_INT, "similarity"),
|
||||
MEMBER(Patch, hunks, T_OBJECT, "hunks"),
|
||||
MEMBER(Patch, additions, T_INT, "additions"),
|
||||
MEMBER(Patch, deletions, T_INT, "deletions"),
|
||||
PyMemberDef DiffFile_members[] = {
|
||||
MEMBER(DiffFile, id, T_OBJECT, "Oid of the item."),
|
||||
MEMBER(DiffFile, path, T_STRING, "Path to the entry."),
|
||||
MEMBER(DiffFile, size, T_LONG, "Size of the entry."),
|
||||
MEMBER(DiffFile, flags, T_UINT, "Combination of GIT_DIFF_FLAG_* flags."),
|
||||
MEMBER(DiffFile, mode, T_USHORT, "Mode of the entry."),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(Patch_is_binary__doc__, "True if binary data, False if not.");
|
||||
|
||||
PyObject *
|
||||
Patch_is_binary__get__(Patch *self)
|
||||
{
|
||||
if (!(self->flags & GIT_DIFF_FLAG_NOT_BINARY) &&
|
||||
(self->flags & GIT_DIFF_FLAG_BINARY))
|
||||
Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
PyDoc_STRVAR(DiffFile__doc__, "DiffFile object.");
|
||||
|
||||
PyGetSetDef Patch_getseters[] = {
|
||||
GETTER(Patch, is_binary),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(Patch__doc__, "Diff patch object.");
|
||||
|
||||
PyTypeObject PatchType = {
|
||||
PyTypeObject DiffFileType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.Patch", /* tp_name */
|
||||
sizeof(Patch), /* tp_basicsize */
|
||||
"_pygit2.DiffFile", /* tp_name */
|
||||
sizeof(DiffFile), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)Patch_dealloc, /* tp_dealloc */
|
||||
(destructor)DiffFile_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
@ -209,7 +227,7 @@ PyTypeObject PatchType = {
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT, /* tp_flags */
|
||||
Patch__doc__, /* tp_doc */
|
||||
DiffFile__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
@ -217,8 +235,8 @@ PyTypeObject PatchType = {
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
Patch_members, /* tp_members */
|
||||
Patch_getseters, /* tp_getset */
|
||||
DiffFile_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
0, /* tp_descr_get */
|
||||
@ -230,11 +248,188 @@ PyTypeObject PatchType = {
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(DiffDelta_status_char__doc__,
|
||||
"status_char()\n"
|
||||
"\n"
|
||||
"Return the single character abbreviation for a delta status code."
|
||||
);
|
||||
|
||||
PyObject *
|
||||
DiffDelta_status_char(DiffDelta *self)
|
||||
{
|
||||
char status = git_diff_status_char(self->status);
|
||||
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
return Py_BuildValue("c", status);
|
||||
#else
|
||||
return Py_BuildValue("C", status);
|
||||
#endif
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(DiffDelta_is_binary__doc__, "True if binary data, False if not.");
|
||||
|
||||
PyObject *
|
||||
DiffDelta_is_binary__get__(DiffDelta *self)
|
||||
{
|
||||
if (!(self->flags & GIT_DIFF_FLAG_NOT_BINARY) &&
|
||||
(self->flags & GIT_DIFF_FLAG_BINARY))
|
||||
Py_RETURN_TRUE;
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
DiffDelta_dealloc(DiffDelta *self)
|
||||
{
|
||||
Py_CLEAR(self->old_file);
|
||||
Py_CLEAR(self->new_file);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
static PyMethodDef DiffDelta_methods[] = {
|
||||
METHOD(DiffDelta, status_char, METH_NOARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyMemberDef DiffDelta_members[] = {
|
||||
MEMBER(DiffDelta, status, T_UINT, "A GIT_DELTA_* constant."),
|
||||
MEMBER(DiffDelta, flags, T_UINT, "Combination of GIT_DIFF_FLAG_* flags."),
|
||||
MEMBER(DiffDelta, similarity, T_USHORT, "For renamed and copied."),
|
||||
MEMBER(DiffDelta, nfiles, T_USHORT, "Number of files in the delta."),
|
||||
MEMBER(DiffDelta, old_file, T_OBJECT, "\"from\" side of the diff."),
|
||||
MEMBER(DiffDelta, new_file, T_OBJECT, "\"to\" side of the diff."),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef DiffDelta_getseters[] = {
|
||||
GETTER(DiffDelta, is_binary),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(DiffDelta__doc__, "DiffDelta object.");
|
||||
|
||||
PyTypeObject DiffDeltaType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.DiffDelta", /* tp_name */
|
||||
sizeof(DiffDelta), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)DiffDelta_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 */
|
||||
DiffDelta__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
DiffDelta_methods, /* tp_methods */
|
||||
DiffDelta_members, /* tp_members */
|
||||
DiffDelta_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 */
|
||||
};
|
||||
|
||||
static void
|
||||
DiffLine_dealloc(DiffLine *self)
|
||||
{
|
||||
Py_CLEAR(self->content);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMemberDef DiffLine_members[] = {
|
||||
MEMBER(DiffLine, origin, T_CHAR, "Type of the diff line"),
|
||||
MEMBER(DiffLine, old_lineno, T_INT,
|
||||
"Line number in old file or -1 for added line"),
|
||||
MEMBER(DiffLine, new_lineno, T_INT,
|
||||
"Line number in new file or -1 for deleted line"),
|
||||
MEMBER(DiffLine, num_lines, T_INT,
|
||||
"Number of newline characters in content"),
|
||||
MEMBER(DiffLine, content_offset, T_INT,
|
||||
"Offset in the original file to the content"),
|
||||
MEMBER(DiffLine, content, T_OBJECT, "Content of the diff line"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(DiffLine__doc__, "DiffLine object.");
|
||||
|
||||
PyTypeObject DiffLineType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.DiffLine", /* tp_name */
|
||||
sizeof(DiffLine), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)DiffLine_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 */
|
||||
DiffLine__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
DiffLine_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 */
|
||||
};
|
||||
|
||||
PyObject *
|
||||
diff_get_patch_byindex(git_diff *diff, size_t idx)
|
||||
{
|
||||
git_patch *patch = NULL;
|
||||
int err;
|
||||
|
||||
err = git_patch_from_diff(&patch, diff, idx);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return (PyObject*) wrap_patch(patch);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
DiffIter_iternext(DiffIter *self)
|
||||
{
|
||||
if (self->i < self->n)
|
||||
return diff_get_patch_byindex(self->diff->list, self->i++);
|
||||
return diff_get_patch_byindex(self->diff->diff, self->i++);
|
||||
|
||||
PyErr_SetNone(PyExc_StopIteration);
|
||||
return NULL;
|
||||
@ -283,11 +478,12 @@ PyTypeObject DiffIterType = {
|
||||
Py_ssize_t
|
||||
Diff_len(Diff *self)
|
||||
{
|
||||
assert(self->list);
|
||||
return (Py_ssize_t)git_diff_num_deltas(self->list);
|
||||
assert(self->diff);
|
||||
return (Py_ssize_t)git_diff_num_deltas(self->diff);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Diff_patch__doc__, "Patch diff string.");
|
||||
PyDoc_STRVAR(Diff_patch__doc__,
|
||||
"Patch diff string. Can be None in some cases, such as empty commits.");
|
||||
|
||||
PyObject *
|
||||
Diff_patch__get__(Diff *self)
|
||||
@ -295,15 +491,15 @@ Diff_patch__get__(Diff *self)
|
||||
git_patch* patch;
|
||||
git_buf buf = {NULL};
|
||||
int err = GIT_ERROR;
|
||||
size_t i, len, num;
|
||||
size_t i, num;
|
||||
PyObject *py_patch = NULL;
|
||||
|
||||
num = git_diff_num_deltas(self->list);
|
||||
num = git_diff_num_deltas(self->diff);
|
||||
if (num == 0)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
for (i = 0, len = 1; i < num ; ++i) {
|
||||
err = git_patch_from_diff(&patch, self->list, i);
|
||||
for (i = 0; i < num ; ++i) {
|
||||
err = git_patch_from_diff(&patch, self->diff, i);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
|
||||
@ -325,30 +521,32 @@ cleanup:
|
||||
|
||||
|
||||
static void
|
||||
Hunk_dealloc(Hunk *self)
|
||||
DiffHunk_dealloc(DiffHunk *self)
|
||||
{
|
||||
Py_CLEAR(self->header);
|
||||
Py_CLEAR(self->lines);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMemberDef Hunk_members[] = {
|
||||
MEMBER(Hunk, old_start, T_INT, "Old start."),
|
||||
MEMBER(Hunk, old_lines, T_INT, "Old lines."),
|
||||
MEMBER(Hunk, new_start, T_INT, "New start."),
|
||||
MEMBER(Hunk, new_lines, T_INT, "New lines."),
|
||||
MEMBER(Hunk, lines, T_OBJECT, "Lines."),
|
||||
PyMemberDef DiffHunk_members[] = {
|
||||
MEMBER(DiffHunk, old_start, T_INT, "Old start."),
|
||||
MEMBER(DiffHunk, old_lines, T_INT, "Old lines."),
|
||||
MEMBER(DiffHunk, new_start, T_INT, "New start."),
|
||||
MEMBER(DiffHunk, new_lines, T_INT, "New lines."),
|
||||
MEMBER(DiffHunk, header, T_OBJECT, "Header."),
|
||||
MEMBER(DiffHunk, lines, T_OBJECT, "Lines."),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(Hunk__doc__, "Hunk object.");
|
||||
PyDoc_STRVAR(DiffHunk__doc__, "DiffHunk object.");
|
||||
|
||||
PyTypeObject HunkType = {
|
||||
PyTypeObject DiffHunkType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.Hunk", /* tp_name */
|
||||
sizeof(Hunk), /* tp_basicsize */
|
||||
"_pygit2.DiffHunk", /* tp_name */
|
||||
sizeof(DiffHunk), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)Hunk_dealloc, /* tp_dealloc */
|
||||
(destructor)DiffHunk_dealloc, /* tp_dealloc */
|
||||
0, /* tp_print */
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
@ -364,7 +562,7 @@ PyTypeObject HunkType = {
|
||||
0, /* tp_setattro */
|
||||
0, /* tp_as_buffer */
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
|
||||
Hunk__doc__, /* tp_doc */
|
||||
DiffHunk__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
@ -372,7 +570,7 @@ PyTypeObject HunkType = {
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
Hunk_members, /* tp_members */
|
||||
DiffHunk_members, /* tp_members */
|
||||
0, /* tp_getset */
|
||||
0, /* tp_base */
|
||||
0, /* tp_dict */
|
||||
@ -384,6 +582,132 @@ PyTypeObject HunkType = {
|
||||
0, /* tp_new */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(DiffStats_insertions__doc__, "Total number of insertions");
|
||||
|
||||
PyObject *
|
||||
DiffStats_insertions__get__(DiffStats *self)
|
||||
{
|
||||
return PyInt_FromSize_t(git_diff_stats_insertions(self->stats));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(DiffStats_deletions__doc__, "Total number of deletions");
|
||||
|
||||
PyObject *
|
||||
DiffStats_deletions__get__(DiffStats *self)
|
||||
{
|
||||
return PyInt_FromSize_t(git_diff_stats_deletions(self->stats));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(DiffStats_files_changed__doc__, "Total number of files changed");
|
||||
|
||||
PyObject *
|
||||
DiffStats_files_changed__get__(DiffStats *self)
|
||||
{
|
||||
return PyInt_FromSize_t(git_diff_stats_files_changed(self->stats));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(DiffStats_format__doc__,
|
||||
"format(format, width)-> str\n"
|
||||
"\n"
|
||||
"Format the stats as a string\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"format\n"
|
||||
" The format to use. A pygit2.GIT_DIFF_STATS_* constant\n"
|
||||
"\n"
|
||||
"width\n"
|
||||
" The width of the output. The output will be scaled to fit.");
|
||||
|
||||
PyObject *
|
||||
DiffStats_format(DiffStats *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
int err, format;
|
||||
git_buf buf = { 0 };
|
||||
Py_ssize_t width;
|
||||
PyObject *str;
|
||||
char *keywords[] = {"format", "width", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "in", keywords, &format, &width))
|
||||
return NULL;
|
||||
|
||||
if (width <= 0) {
|
||||
PyErr_SetString(PyExc_ValueError, "width must be positive");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_diff_stats_to_buf(&buf, self->stats, format, width);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
str = to_unicode(buf.ptr, NULL, NULL);
|
||||
git_buf_free(&buf);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
DiffStats_dealloc(DiffStats *self)
|
||||
{
|
||||
git_diff_stats_free(self->stats);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMethodDef DiffStats_methods[] = {
|
||||
METHOD(DiffStats, format, METH_VARARGS | METH_KEYWORDS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef DiffStats_getseters[] = {
|
||||
GETTER(DiffStats, insertions),
|
||||
GETTER(DiffStats, deletions),
|
||||
GETTER(DiffStats, files_changed),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(DiffStats__doc__, "DiffStats object.");
|
||||
|
||||
PyTypeObject DiffStatsType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.DiffStats", /* tp_name */
|
||||
sizeof(DiffStats), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)DiffStats_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 */
|
||||
DiffStats__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
DiffStats_methods, /* tp_methods */
|
||||
0, /* tp_members */
|
||||
DiffStats_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 */
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(Diff_from_c__doc__, "Method exposed for Index to hook into");
|
||||
|
||||
PyObject *
|
||||
@ -429,7 +753,7 @@ Diff_merge(Diff *self, PyObject *args)
|
||||
if (py_diff->repo->repo != self->repo->repo)
|
||||
return Error_set(GIT_ERROR);
|
||||
|
||||
err = git_diff_merge(self->list, py_diff->list);
|
||||
err = git_diff_merge(self->diff, py_diff->diff);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -454,7 +778,7 @@ Diff_find_similar(Diff *self, PyObject *args, PyObject *kwds)
|
||||
&opts.flags, &opts.rename_threshold, &opts.copy_threshold, &opts.rename_from_rewrite_threshold, &opts.break_rewrite_threshold, &opts.rename_limit))
|
||||
return NULL;
|
||||
|
||||
err = git_diff_find_similar(self->list, &opts);
|
||||
err = git_diff_find_similar(self->diff, &opts);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -471,7 +795,7 @@ Diff_iter(Diff *self)
|
||||
Py_INCREF(self);
|
||||
iter->diff = self;
|
||||
iter->i = 0;
|
||||
iter->n = git_diff_num_deltas(self->list);
|
||||
iter->n = git_diff_num_deltas(self->diff);
|
||||
}
|
||||
return (PyObject*)iter;
|
||||
}
|
||||
@ -481,25 +805,32 @@ Diff_getitem(Diff *self, PyObject *value)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (PyLong_Check(value) < 0)
|
||||
return NULL;
|
||||
if (!PyInt_Check(value))
|
||||
return NULL; /* FIXME Raise error */
|
||||
|
||||
i = PyLong_AsUnsignedLong(value);
|
||||
|
||||
return diff_get_patch_byindex(self->list, i);
|
||||
i = PyInt_AsSize_t(value);
|
||||
return diff_get_patch_byindex(self->diff, i);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Diff_stats__doc__, "Accumulate diff statistics for all patches");
|
||||
|
||||
PyObject *
|
||||
Diff_stats__get__(Diff *self)
|
||||
{
|
||||
return wrap_diff_stats(self->diff);
|
||||
}
|
||||
|
||||
static void
|
||||
Diff_dealloc(Diff *self)
|
||||
{
|
||||
git_diff_free(self->list);
|
||||
git_diff_free(self->diff);
|
||||
Py_CLEAR(self->repo);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyGetSetDef Diff_getseters[] = {
|
||||
GETTER(Diff, patch),
|
||||
GETTER(Diff, stats),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
12
src/diff.h
12
src/diff.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -33,15 +33,13 @@
|
||||
#include <git2.h>
|
||||
#include "types.h"
|
||||
|
||||
#define DIFF_CHECK_TYPES(_x, _y, _type_x, _type_y) \
|
||||
PyObject_TypeCheck(_x, _type_x) && \
|
||||
PyObject_TypeCheck(_y, _type_y)
|
||||
|
||||
|
||||
PyObject* Diff_changes(Diff *self);
|
||||
PyObject* Diff_patch(Diff *self);
|
||||
|
||||
PyObject* wrap_diff(git_diff *diff, Repository *repo);
|
||||
PyObject* wrap_patch(git_patch *patch);
|
||||
PyObject* wrap_diff_delta(const git_diff_delta *delta);
|
||||
PyObject* wrap_diff_file(const git_diff_file *file);
|
||||
PyObject * wrap_diff_hunk(git_patch *patch, size_t idx);
|
||||
PyObject* wrap_diff_line(const git_diff_line *line);
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -126,3 +126,10 @@ Error_set_oid(int err, const git_oid *oid, size_t len)
|
||||
hex[len] = '\0';
|
||||
return Error_set_str(err, hex);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
Error_type_error(const char *format, PyObject *value)
|
||||
{
|
||||
PyErr_Format(PyExc_TypeError, format, Py_TYPE(value)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -37,5 +37,6 @@ PyObject* Error_set(int err);
|
||||
PyObject* Error_set_exc(PyObject* exception);
|
||||
PyObject* Error_set_str(int err, const char *str);
|
||||
PyObject* Error_set_oid(int err, const git_oid *oid, size_t len);
|
||||
PyObject* Error_type_error(const char *format, PyObject *value);
|
||||
|
||||
#endif
|
||||
|
21
src/note.c
21
src/note.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -39,13 +39,13 @@ extern PyTypeObject SignatureType;
|
||||
PyDoc_STRVAR(Note_remove__doc__,
|
||||
"Removes a note for an annotated object");
|
||||
|
||||
PyObject*
|
||||
PyObject *
|
||||
Note_remove(Note *self, PyObject* args)
|
||||
{
|
||||
char *ref = "refs/notes/commits";
|
||||
int err = GIT_ERROR;
|
||||
git_oid annotated_id;
|
||||
Signature *py_author, *py_committer;
|
||||
Oid *id;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "O!O!|s",
|
||||
&SignatureType, &py_author,
|
||||
@ -53,12 +53,9 @@ Note_remove(Note *self, PyObject* args)
|
||||
&ref))
|
||||
return NULL;
|
||||
|
||||
err = git_oid_fromstr(&annotated_id, self->annotated_id);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
id = (Oid *) self->annotated_id;
|
||||
err = git_note_remove(self->repo->repo, ref, py_author->signature,
|
||||
py_committer->signature, &annotated_id);
|
||||
py_committer->signature, &id->oid);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -90,7 +87,7 @@ static void
|
||||
Note_dealloc(Note *self)
|
||||
{
|
||||
Py_CLEAR(self->repo);
|
||||
free(self->annotated_id);
|
||||
Py_CLEAR(self->annotated_id);
|
||||
git_note_free(self->note);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
@ -102,7 +99,7 @@ PyMethodDef Note_methods[] = {
|
||||
};
|
||||
|
||||
PyMemberDef Note_members[] = {
|
||||
MEMBER(Note, annotated_id, T_STRING, "id of the annotated object."),
|
||||
MEMBER(Note, annotated_id, T_OBJECT, "id of the annotated object."),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
@ -211,7 +208,7 @@ PyTypeObject NoteIterType = {
|
||||
};
|
||||
|
||||
|
||||
PyObject*
|
||||
PyObject *
|
||||
wrap_note(Repository* repo, git_oid* annotated_id, const char* ref)
|
||||
{
|
||||
Note* py_note = NULL;
|
||||
@ -229,7 +226,7 @@ wrap_note(Repository* repo, git_oid* annotated_id, const char* ref)
|
||||
|
||||
py_note->repo = repo;
|
||||
Py_INCREF(repo);
|
||||
py_note->annotated_id = git_oid_allocfmt(annotated_id);
|
||||
py_note->annotated_id = git_oid_to_python(annotated_id);
|
||||
|
||||
return (PyObject*) py_note;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
40
src/object.c
40
src/object.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -97,7 +97,7 @@ PyDoc_STRVAR(Object_type__doc__,
|
||||
PyObject *
|
||||
Object_type__get__(Object *self)
|
||||
{
|
||||
return PyLong_FromLong(git_object_type(self->obj));
|
||||
return PyInt_FromLong(git_object_type(self->obj));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Object__pointer__doc__, "Get the object's pointer. For internal use only.");
|
||||
@ -135,24 +135,6 @@ Object_read_raw(Object *self)
|
||||
return aux;
|
||||
}
|
||||
|
||||
static git_otype
|
||||
py_type_to_git_type(PyTypeObject *py_type)
|
||||
{
|
||||
git_otype type = GIT_OBJ_BAD;
|
||||
|
||||
if (py_type == &CommitType) {
|
||||
type = GIT_OBJ_COMMIT;
|
||||
} else if (py_type == &TreeType) {
|
||||
type = GIT_OBJ_TREE;
|
||||
} else if (py_type == &BlobType) {
|
||||
type = GIT_OBJ_BLOB;
|
||||
} else if (py_type == &TagType) {
|
||||
type = GIT_OBJ_TAG;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Object_peel__doc__,
|
||||
"peel(target_type) -> Object\n"
|
||||
"\n"
|
||||
@ -161,23 +143,15 @@ PyDoc_STRVAR(Object_peel__doc__,
|
||||
PyObject *
|
||||
Object_peel(Object *self, PyObject *py_type)
|
||||
{
|
||||
int type = -1, err;
|
||||
int err;
|
||||
git_otype otype;
|
||||
git_object *peeled;
|
||||
|
||||
if (PyLong_Check(py_type)) {
|
||||
type = PyLong_AsLong(py_type);
|
||||
if (type == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
} else if (PyType_Check(py_type)) {
|
||||
type = py_type_to_git_type((PyTypeObject *) py_type);
|
||||
}
|
||||
|
||||
if (type == -1) {
|
||||
PyErr_SetString(PyExc_ValueError, "invalid target type");
|
||||
otype = py_object_to_otype(py_type);
|
||||
if (otype == GIT_OBJ_BAD)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_object_peel(&peeled, self->obj, (git_otype)type);
|
||||
err = git_object_peel(&peeled, self->obj, otype);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -209,8 +209,10 @@ Oid_init(Oid *self, PyObject *args, PyObject *kw)
|
||||
Py_hash_t
|
||||
Oid_hash(PyObject *oid)
|
||||
{
|
||||
/* TODO Randomize (use _Py_HashSecret) to avoid collission DoS attacks? */
|
||||
return *(Py_hash_t*) ((Oid*)oid)->oid.id;
|
||||
PyObject *py_oid = git_oid_to_py_str(&((Oid *)oid)->oid);
|
||||
Py_hash_t ret = PyObject_Hash(py_oid);
|
||||
Py_DECREF(py_oid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
182
src/options.c
182
src/options.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -65,10 +65,11 @@ option(PyObject *self, PyObject *args)
|
||||
if (!py_option)
|
||||
return NULL;
|
||||
|
||||
if (!PyLong_Check(py_option))
|
||||
goto on_non_integer;
|
||||
if (!PyInt_Check(py_option))
|
||||
return Error_type_error(
|
||||
"option should be an integer, got %.200s", py_option);
|
||||
|
||||
option = PyLong_AsLong(py_option);
|
||||
option = PyInt_AsLong(py_option);
|
||||
|
||||
switch (option) {
|
||||
case GIT_OPT_GET_SEARCH_PATH:
|
||||
@ -79,11 +80,11 @@ option(PyObject *self, PyObject *args)
|
||||
if (!py_level)
|
||||
return NULL;
|
||||
|
||||
if (!PyLong_Check(py_level))
|
||||
goto on_non_integer;
|
||||
if (!PyInt_Check(py_level))
|
||||
return Error_type_error(
|
||||
"level should be an integer, got %.200s", py_level);
|
||||
|
||||
return get_search_path(PyLong_AsLong(py_level));
|
||||
break;
|
||||
return get_search_path(PyInt_AsLong(py_level));
|
||||
}
|
||||
|
||||
case GIT_OPT_SET_SEARCH_PATH:
|
||||
@ -100,23 +101,22 @@ option(PyObject *self, PyObject *args)
|
||||
if (!py_path)
|
||||
return NULL;
|
||||
|
||||
if (!PyLong_Check(py_level))
|
||||
goto on_non_integer;
|
||||
if (!PyInt_Check(py_level))
|
||||
return Error_type_error(
|
||||
"level should be an integer, got %.200s", py_level);
|
||||
|
||||
path = py_str_borrow_c_str(&tpath, py_path, NULL);
|
||||
if (!path)
|
||||
return NULL;
|
||||
|
||||
err = git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, PyLong_AsLong(py_level), path);
|
||||
err = git_libgit2_opts(
|
||||
GIT_OPT_SET_SEARCH_PATH, PyInt_AsLong(py_level), path);
|
||||
Py_DECREF(tpath);
|
||||
|
||||
if (err < 0) {
|
||||
Error_set(err);
|
||||
return NULL;
|
||||
}
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIT_OPT_GET_MWINDOW_SIZE:
|
||||
@ -124,14 +124,10 @@ option(PyObject *self, PyObject *args)
|
||||
size_t size;
|
||||
|
||||
error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_SIZE, &size);
|
||||
if (error < 0) {
|
||||
Error_set(error);
|
||||
return NULL;
|
||||
}
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
return PyLong_FromSize_t(size);
|
||||
|
||||
break;
|
||||
return PyInt_FromSize_t(size);
|
||||
}
|
||||
|
||||
case GIT_OPT_SET_MWINDOW_SIZE:
|
||||
@ -143,25 +139,141 @@ option(PyObject *self, PyObject *args)
|
||||
if (!py_size)
|
||||
return NULL;
|
||||
|
||||
if (!PyLong_Check(py_size))
|
||||
goto on_non_integer;
|
||||
if (!PyInt_Check(py_size))
|
||||
return Error_type_error(
|
||||
"size should be an integer, got %.200s", py_size);
|
||||
|
||||
size = PyLong_AsSize_t(py_size);
|
||||
size = PyInt_AsSize_t(py_size);
|
||||
error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_SIZE, size);
|
||||
if (error < 0) {
|
||||
Error_set(error);
|
||||
return NULL;
|
||||
}
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
break;
|
||||
}
|
||||
|
||||
case GIT_OPT_GET_MWINDOW_MAPPED_LIMIT:
|
||||
{
|
||||
size_t limit;
|
||||
|
||||
error = git_libgit2_opts(GIT_OPT_GET_MWINDOW_MAPPED_LIMIT, &limit);
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
return PyInt_FromSize_t(limit);
|
||||
}
|
||||
|
||||
case GIT_OPT_SET_MWINDOW_MAPPED_LIMIT:
|
||||
{
|
||||
size_t limit;
|
||||
PyObject *py_limit;
|
||||
|
||||
py_limit = PyTuple_GetItem(args, 1);
|
||||
if (!py_limit)
|
||||
return NULL;
|
||||
|
||||
if (PyInt_Check(py_limit)) {
|
||||
limit = PyInt_AsSize_t(py_limit);
|
||||
} else if (PyLong_Check(py_limit)) {
|
||||
limit = PyLong_AsSize_t(py_limit);
|
||||
} else {
|
||||
return Error_type_error(
|
||||
"limit should be an integer, got %.200s", py_limit);
|
||||
}
|
||||
|
||||
error = git_libgit2_opts(GIT_OPT_SET_MWINDOW_MAPPED_LIMIT, limit);
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
case GIT_OPT_SET_CACHE_OBJECT_LIMIT:
|
||||
{
|
||||
size_t limit;
|
||||
int object_type;
|
||||
PyObject *py_object_type, *py_limit;
|
||||
|
||||
py_object_type = PyTuple_GetItem(args, 1);
|
||||
if (!py_object_type)
|
||||
return NULL;
|
||||
|
||||
py_limit = PyTuple_GetItem(args, 2);
|
||||
if (!py_limit)
|
||||
return NULL;
|
||||
|
||||
if (!PyInt_Check(py_limit))
|
||||
return Error_type_error(
|
||||
"limit should be an integer, got %.200s", py_limit);
|
||||
|
||||
object_type = PyInt_AsLong(py_object_type);
|
||||
limit = PyInt_AsSize_t(py_limit);
|
||||
error = git_libgit2_opts(
|
||||
GIT_OPT_SET_CACHE_OBJECT_LIMIT, object_type, limit);
|
||||
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
case GIT_OPT_SET_CACHE_MAX_SIZE:
|
||||
{
|
||||
size_t max_size;
|
||||
PyObject *py_max_size;
|
||||
|
||||
py_max_size = PyTuple_GetItem(args, 1);
|
||||
if (!py_max_size)
|
||||
return NULL;
|
||||
|
||||
if (!PyInt_Check(py_max_size))
|
||||
return Error_type_error(
|
||||
"max_size should be an integer, got %.200s", py_max_size);
|
||||
|
||||
max_size = PyInt_AsSize_t(py_max_size);
|
||||
error = git_libgit2_opts(GIT_OPT_SET_CACHE_MAX_SIZE, max_size);
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
case GIT_OPT_ENABLE_CACHING:
|
||||
{
|
||||
int flag;
|
||||
PyObject *py_flag;
|
||||
|
||||
py_flag = PyTuple_GetItem(args, 1);
|
||||
|
||||
if (!PyInt_Check(py_flag))
|
||||
return Error_type_error(
|
||||
"flag should be an integer, got %.200s", py_flag);
|
||||
|
||||
flag = PyInt_AsSize_t(py_flag);
|
||||
error = git_libgit2_opts(GIT_OPT_ENABLE_CACHING, flag);
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
case GIT_OPT_GET_CACHED_MEMORY:
|
||||
{
|
||||
size_t current;
|
||||
size_t allowed;
|
||||
PyObject* tup = PyTuple_New(2);
|
||||
|
||||
error = git_libgit2_opts(GIT_OPT_GET_CACHED_MEMORY, ¤t, &allowed);
|
||||
if (error < 0)
|
||||
return Error_set(error);
|
||||
|
||||
PyTuple_SetItem(tup, 0, PyInt_FromLong(current));
|
||||
PyTuple_SetItem(tup, 1, PyInt_FromLong(allowed));
|
||||
|
||||
return tup;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
PyErr_SetString(PyExc_ValueError, "unknown/unsupported option value");
|
||||
return NULL;
|
||||
|
||||
on_non_integer:
|
||||
PyErr_SetString(PyExc_TypeError, "option is not an integer");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
158
src/patch.c
Normal file
158
src/patch.c
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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 "diff.h"
|
||||
#include "error.h"
|
||||
#include "oid.h"
|
||||
#include "types.h"
|
||||
#include "utils.h"
|
||||
|
||||
extern PyTypeObject DiffHunkType;
|
||||
PyTypeObject PatchType;
|
||||
|
||||
|
||||
PyObject *
|
||||
wrap_patch(git_patch *patch)
|
||||
{
|
||||
Patch *py_patch;
|
||||
PyObject *py_hunk;
|
||||
size_t i, hunk_amounts;
|
||||
|
||||
if (!patch)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
py_patch = PyObject_New(Patch, &PatchType);
|
||||
if (py_patch) {
|
||||
py_patch->patch = patch;
|
||||
|
||||
hunk_amounts = git_patch_num_hunks(patch);
|
||||
py_patch->hunks = PyList_New(hunk_amounts);
|
||||
for (i = 0; i < hunk_amounts; ++i) {
|
||||
py_hunk = wrap_diff_hunk(patch, i);
|
||||
if (py_hunk)
|
||||
PyList_SetItem((PyObject*) py_patch->hunks, i, py_hunk);
|
||||
}
|
||||
}
|
||||
|
||||
return (PyObject*) py_patch;
|
||||
}
|
||||
|
||||
static void
|
||||
Patch_dealloc(Patch *self)
|
||||
{
|
||||
Py_CLEAR(self->hunks);
|
||||
git_patch_free(self->patch);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Patch_delta__doc__, "Get the delta associated with a patch.");
|
||||
|
||||
PyObject *
|
||||
Patch_delta__get__(Patch *self)
|
||||
{
|
||||
if (!self->patch)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
return wrap_diff_delta(git_patch_get_delta(self->patch));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Patch_line_stats__doc__,
|
||||
"Get line counts of each type in a patch.");
|
||||
|
||||
PyObject *
|
||||
Patch_line_stats__get__(Patch *self)
|
||||
{
|
||||
size_t context, additions, deletions;
|
||||
int err;
|
||||
|
||||
if (!self->patch)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
err = git_patch_line_stats(&context, &additions, &deletions,
|
||||
self->patch);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return Py_BuildValue("III", context, additions, deletions);
|
||||
}
|
||||
|
||||
PyMemberDef Patch_members[] = {
|
||||
MEMBER(Patch, hunks, T_OBJECT, "hunks"),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef Patch_getseters[] = {
|
||||
GETTER(Patch, delta),
|
||||
GETTER(Patch, line_stats),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyDoc_STRVAR(Patch__doc__, "Diff patch object.");
|
||||
|
||||
PyTypeObject PatchType = {
|
||||
PyVarObject_HEAD_INIT(NULL, 0)
|
||||
"_pygit2.Patch", /* tp_name */
|
||||
sizeof(Patch), /* tp_basicsize */
|
||||
0, /* tp_itemsize */
|
||||
(destructor)Patch_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 */
|
||||
Patch__doc__, /* tp_doc */
|
||||
0, /* tp_traverse */
|
||||
0, /* tp_clear */
|
||||
0, /* tp_richcompare */
|
||||
0, /* tp_weaklistoffset */
|
||||
0, /* tp_iter */
|
||||
0, /* tp_iternext */
|
||||
0, /* tp_methods */
|
||||
Patch_members, /* tp_members */
|
||||
Patch_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,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -25,14 +25,13 @@
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDE_pygit2_blame_h
|
||||
#define INCLUDE_pygit2_blame_h
|
||||
#ifndef INCLUDE_pygit2_patch_h
|
||||
#define INCLUDE_pygit2_patch_h
|
||||
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
#include <git2.h>
|
||||
#include "types.h"
|
||||
|
||||
PyObject* wrap_blame(git_blame *blame, Repository *repo);
|
||||
PyObject* wrap_patch(git_patch *patch);
|
||||
|
||||
#endif
|
117
src/pygit2.c
117
src/pygit2.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -44,8 +44,12 @@ extern PyTypeObject ObjectType;
|
||||
extern PyTypeObject CommitType;
|
||||
extern PyTypeObject DiffType;
|
||||
extern PyTypeObject DiffIterType;
|
||||
extern PyTypeObject DiffDeltaType;
|
||||
extern PyTypeObject DiffFileType;
|
||||
extern PyTypeObject DiffHunkType;
|
||||
extern PyTypeObject DiffLineType;
|
||||
extern PyTypeObject DiffStatsType;
|
||||
extern PyTypeObject PatchType;
|
||||
extern PyTypeObject HunkType;
|
||||
extern PyTypeObject TreeType;
|
||||
extern PyTypeObject TreeBuilderType;
|
||||
extern PyTypeObject TreeEntryType;
|
||||
@ -62,10 +66,6 @@ extern PyTypeObject RemoteType;
|
||||
extern PyTypeObject RefspecType;
|
||||
extern PyTypeObject NoteType;
|
||||
extern PyTypeObject NoteIterType;
|
||||
extern PyTypeObject BlameType;
|
||||
extern PyTypeObject BlameIterType;
|
||||
extern PyTypeObject BlameHunkType;
|
||||
|
||||
|
||||
|
||||
PyDoc_STRVAR(discover_repository__doc__,
|
||||
@ -144,7 +144,44 @@ hash(PyObject *self, PyObject *args)
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(init_file_backend__doc__,
|
||||
"init_file_backend(path) -> object\n"
|
||||
"\n"
|
||||
"open repo backend given path.");
|
||||
PyObject *
|
||||
init_file_backend(PyObject *self, PyObject *args)
|
||||
{
|
||||
const char* path = NULL;
|
||||
int err = GIT_OK;
|
||||
git_repository *repository = NULL;
|
||||
if (!PyArg_ParseTuple(args, "s", &path)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_repository_open(&repository, path);
|
||||
if (err < 0) {
|
||||
Error_set_str(err, path);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
return PyCapsule_New(repository, "backend", NULL);
|
||||
|
||||
cleanup:
|
||||
if (repository) {
|
||||
git_repository_free(repository);
|
||||
}
|
||||
|
||||
if (err == GIT_ENOTFOUND) {
|
||||
PyErr_Format(GitError, "Repository not found at %s", path);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyMethodDef module_methods[] = {
|
||||
{"init_file_backend", init_file_backend, METH_VARARGS,
|
||||
init_file_backend__doc__},
|
||||
{"discover_repository", discover_repository, METH_VARARGS,
|
||||
discover_repository__doc__},
|
||||
{"hashfile", hashfile, METH_VARARGS, hashfile__doc__},
|
||||
@ -153,7 +190,7 @@ PyMethodDef module_methods[] = {
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyObject*
|
||||
PyObject *
|
||||
moduleinit(PyObject* m)
|
||||
{
|
||||
if (m == NULL)
|
||||
@ -170,6 +207,12 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_SET_SEARCH_PATH);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_GET_MWINDOW_SIZE);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_SET_MWINDOW_SIZE);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_GET_MWINDOW_MAPPED_LIMIT);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_SET_MWINDOW_MAPPED_LIMIT);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_SET_CACHE_OBJECT_LIMIT);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_GET_CACHED_MEMORY);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_ENABLE_CACHING);
|
||||
ADD_CONSTANT_INT(m, GIT_OPT_SET_CACHE_MAX_SIZE);
|
||||
|
||||
/* Errors */
|
||||
GitError = PyErr_NewException("_pygit2.GitError", NULL, NULL);
|
||||
@ -214,7 +257,6 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_OBJ_BLOB)
|
||||
ADD_CONSTANT_INT(m, GIT_OBJ_TAG)
|
||||
/* Valid modes for index and tree entries. */
|
||||
ADD_CONSTANT_INT(m, GIT_FILEMODE_NEW)
|
||||
ADD_CONSTANT_INT(m, GIT_FILEMODE_TREE)
|
||||
ADD_CONSTANT_INT(m, GIT_FILEMODE_BLOB)
|
||||
ADD_CONSTANT_INT(m, GIT_FILEMODE_BLOB_EXECUTABLE)
|
||||
@ -261,6 +303,7 @@ moduleinit(PyObject* m)
|
||||
ADD_TYPE(m, Branch)
|
||||
ADD_CONSTANT_INT(m, GIT_BRANCH_LOCAL)
|
||||
ADD_CONSTANT_INT(m, GIT_BRANCH_REMOTE)
|
||||
ADD_CONSTANT_INT(m, GIT_BRANCH_ALL)
|
||||
|
||||
/*
|
||||
* Index & Working copy
|
||||
@ -274,10 +317,11 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_STATUS_WT_MODIFIED)
|
||||
ADD_CONSTANT_INT(m, GIT_STATUS_WT_DELETED)
|
||||
ADD_CONSTANT_INT(m, GIT_STATUS_IGNORED) /* Flags for ignored files */
|
||||
ADD_CONSTANT_INT(m, GIT_STATUS_CONFLICTED)
|
||||
/* Different checkout strategies */
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_NONE)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_SAFE_CREATE)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_RECREATE_MISSING)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_FORCE)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_ALLOW_CONFLICTS)
|
||||
ADD_CONSTANT_INT(m, GIT_CHECKOUT_REMOVE_UNTRACKED)
|
||||
@ -292,11 +336,19 @@ moduleinit(PyObject* m)
|
||||
*/
|
||||
INIT_TYPE(DiffType, NULL, NULL)
|
||||
INIT_TYPE(DiffIterType, NULL, NULL)
|
||||
INIT_TYPE(DiffDeltaType, NULL, NULL)
|
||||
INIT_TYPE(DiffFileType, NULL, NULL)
|
||||
INIT_TYPE(DiffHunkType, NULL, NULL)
|
||||
INIT_TYPE(DiffLineType, NULL, NULL)
|
||||
INIT_TYPE(DiffStatsType, NULL, NULL)
|
||||
INIT_TYPE(PatchType, NULL, NULL)
|
||||
INIT_TYPE(HunkType, NULL, NULL)
|
||||
ADD_TYPE(m, Diff)
|
||||
ADD_TYPE(m, DiffDelta)
|
||||
ADD_TYPE(m, DiffFile)
|
||||
ADD_TYPE(m, DiffHunk)
|
||||
ADD_TYPE(m, DiffLine)
|
||||
ADD_TYPE(m, DiffStats)
|
||||
ADD_TYPE(m, Patch)
|
||||
ADD_TYPE(m, Hunk)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_NORMAL)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_REVERSE)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FORCE_TEXT)
|
||||
@ -315,9 +367,15 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_IGNORE_CASE)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_SHOW_UNTRACKED_CONTENT)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_SKIP_BINARY_CHECK)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_SHOW_BINARY)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_INCLUDE_TYPECHANGE)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_INCLUDE_TYPECHANGE_TREES)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_RECURSE_IGNORED_DIRS)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_STATS_NONE)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_STATS_FULL)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_STATS_SHORT)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_STATS_NUMBER)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_STATS_INCLUDE_SUMMARY)
|
||||
/* Flags for diff find similar */
|
||||
/* --find-renames */
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FIND_RENAMES)
|
||||
@ -330,6 +388,23 @@ moduleinit(PyObject* m)
|
||||
/* --break-rewrites=/M */
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FIND_AND_BREAK_REWRITES)
|
||||
|
||||
/* DiffDelta and DiffFile flags */
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_BINARY)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_NOT_BINARY)
|
||||
ADD_CONSTANT_INT(m, GIT_DIFF_FLAG_VALID_ID)
|
||||
|
||||
/* DiffDelta.status */
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_UNMODIFIED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_ADDED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_DELETED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_MODIFIED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_RENAMED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_COPIED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_IGNORED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_UNTRACKED)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_TYPECHANGE)
|
||||
ADD_CONSTANT_INT(m, GIT_DELTA_UNREADABLE)
|
||||
|
||||
/* Config */
|
||||
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_LOCAL);
|
||||
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_GLOBAL);
|
||||
@ -337,11 +412,6 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_CONFIG_LEVEL_SYSTEM);
|
||||
|
||||
/* Blame */
|
||||
INIT_TYPE(BlameType, NULL, NULL)
|
||||
INIT_TYPE(BlameIterType, NULL, NULL)
|
||||
INIT_TYPE(BlameHunkType, NULL, NULL)
|
||||
ADD_TYPE(m, Blame)
|
||||
ADD_TYPE(m, BlameHunk)
|
||||
ADD_CONSTANT_INT(m, GIT_BLAME_NORMAL)
|
||||
ADD_CONSTANT_INT(m, GIT_BLAME_TRACK_COPIES_SAME_FILE)
|
||||
ADD_CONSTANT_INT(m, GIT_BLAME_TRACK_COPIES_SAME_COMMIT_MOVES)
|
||||
@ -355,8 +425,21 @@ moduleinit(PyObject* m)
|
||||
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_FASTFORWARD)
|
||||
ADD_CONSTANT_INT(m, GIT_MERGE_ANALYSIS_UNBORN)
|
||||
|
||||
/* Describe */
|
||||
ADD_CONSTANT_INT(m, GIT_DESCRIBE_DEFAULT);
|
||||
ADD_CONSTANT_INT(m, GIT_DESCRIBE_TAGS);
|
||||
ADD_CONSTANT_INT(m, GIT_DESCRIBE_ALL);
|
||||
|
||||
/* Stash */
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_DEFAULT);
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_KEEP_INDEX);
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_INCLUDE_UNTRACKED);
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_INCLUDE_IGNORED);
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_APPLY_DEFAULT);
|
||||
ADD_CONSTANT_INT(m, GIT_STASH_APPLY_REINSTATE_INDEX);
|
||||
|
||||
/* Global initialization of libgit2 */
|
||||
git_threads_init();
|
||||
git_libgit2_init();
|
||||
|
||||
return m;
|
||||
}
|
||||
|
169
src/reference.c
169
src/reference.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -60,8 +60,8 @@ RefLogIter_iternext(RefLogIter *self)
|
||||
entry = git_reflog_entry_byindex(self->reflog, self->i);
|
||||
py_entry = PyObject_New(RefLogEntry, &RefLogEntryType);
|
||||
|
||||
py_entry->oid_old = git_oid_allocfmt(git_reflog_entry_id_old(entry));
|
||||
py_entry->oid_new = git_oid_allocfmt(git_reflog_entry_id_new(entry));
|
||||
py_entry->oid_old = git_oid_to_python(git_reflog_entry_id_old(entry));
|
||||
py_entry->oid_new = git_oid_to_python(git_reflog_entry_id_new(entry));
|
||||
py_entry->message = strdup(git_reflog_entry_message(entry));
|
||||
err = git_signature_dup(&py_entry->signature,
|
||||
git_reflog_entry_committer(entry));
|
||||
@ -163,7 +163,7 @@ Reference_rename(Reference *self, PyObject *py_name)
|
||||
return NULL;
|
||||
|
||||
/* Rename */
|
||||
err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL, NULL);
|
||||
err = git_reference_rename(&new_reference, self->reference, c_name, 0, NULL);
|
||||
git_reference_free(self->reference);
|
||||
free(c_name);
|
||||
if (err < 0)
|
||||
@ -205,10 +205,7 @@ Reference_resolve(Reference *self, PyObject *args)
|
||||
PyDoc_STRVAR(Reference_target__doc__,
|
||||
"The reference target: If direct the value will be an Oid object, if it\n"
|
||||
"is symbolic it will be an string with the full name of the target\n"
|
||||
"reference.\n"
|
||||
"\n"
|
||||
"The target is writable. Setting the Reference's target to another Oid\n"
|
||||
"object will direct the reference to that Oid instead.");
|
||||
"reference.\n");
|
||||
|
||||
PyObject *
|
||||
Reference_target__get__(Reference *self)
|
||||
@ -230,48 +227,72 @@ Reference_target__get__(Reference *self)
|
||||
return to_path(c_name);
|
||||
}
|
||||
|
||||
int
|
||||
Reference_target__set__(Reference *self, PyObject *py_target)
|
||||
PyDoc_STRVAR(Reference_set_target__doc__,
|
||||
"set_target(target, [message])\n"
|
||||
"\n"
|
||||
"Set the target of this reference.\n"
|
||||
"\n"
|
||||
"Update the reference using the given signature and message.\n"
|
||||
"These will be used to fill the reflog entry which will be created\n"
|
||||
"as a result of this update\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"target\n"
|
||||
" The new target for this reference\n"
|
||||
"message\n"
|
||||
" Message to use for the reflog.\n");
|
||||
|
||||
PyObject *
|
||||
Reference_set_target(Reference *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
git_oid oid;
|
||||
char *c_name;
|
||||
int err;
|
||||
git_reference *new_ref;
|
||||
PyObject *py_target = NULL;
|
||||
const char *message = NULL;
|
||||
char *keywords[] = {"target", "message", NULL};
|
||||
|
||||
CHECK_REFERENCE_INT(self);
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", keywords,
|
||||
&py_target, &message))
|
||||
return NULL;
|
||||
|
||||
/* Case 1: Direct */
|
||||
if (GIT_REF_OID == git_reference_type(self->reference)) {
|
||||
err = py_oid_to_git_oid_expand(self->repo->repo, py_target, &oid);
|
||||
if (err < 0)
|
||||
return err;
|
||||
goto error;
|
||||
|
||||
err = git_reference_set_target(&new_ref, self->reference, &oid, NULL, NULL);
|
||||
err = git_reference_set_target(&new_ref, self->reference, &oid, message);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
git_reference_free(self->reference);
|
||||
self->reference = new_ref;
|
||||
return 0;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
/* Case 2: Symbolic */
|
||||
c_name = py_path_to_c_str(py_target);
|
||||
if (c_name == NULL)
|
||||
return -1;
|
||||
return NULL;
|
||||
|
||||
err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, NULL, NULL);
|
||||
err = git_reference_symbolic_set_target(&new_ref, self->reference, c_name, message);
|
||||
free(c_name);
|
||||
if (err < 0)
|
||||
goto error;
|
||||
|
||||
git_reference_free(self->reference);
|
||||
self->reference = new_ref;
|
||||
return 0;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
|
||||
error:
|
||||
Error_set(err);
|
||||
return -1;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -304,7 +325,7 @@ Reference_type__get__(Reference *self)
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
c_type = git_reference_type(self->reference);
|
||||
return PyLong_FromLong(c_type);
|
||||
return PyInt_FromLong(c_type);
|
||||
}
|
||||
|
||||
|
||||
@ -335,93 +356,50 @@ Reference_log(Reference *self)
|
||||
return (PyObject*)iter;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Reference_log_append__doc__,
|
||||
"log_append(oid, committer, message[, encoding])\n"
|
||||
"\n"
|
||||
"Append a reflog entry to the reference. If the oid is None then keep\n"
|
||||
"the current reference's oid. The message parameter may be None.");
|
||||
|
||||
PyObject *
|
||||
Reference_log_append(Reference *self, PyObject *args)
|
||||
{
|
||||
git_signature *committer;
|
||||
const char *message = NULL;
|
||||
git_reflog *reflog;
|
||||
git_oid oid;
|
||||
const git_oid *ref_oid;
|
||||
int err;
|
||||
PyObject *py_oid = NULL;
|
||||
Signature *py_committer;
|
||||
PyObject *py_message = NULL;
|
||||
char *encoding = NULL;
|
||||
git_repository *repo;
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
/* Input parameters */
|
||||
if (!PyArg_ParseTuple(args, "OO!O|s", &py_oid,
|
||||
&SignatureType, &py_committer,
|
||||
&py_message, &encoding))
|
||||
return NULL;
|
||||
|
||||
if (py_oid == Py_None)
|
||||
ref_oid = git_reference_target(self->reference);
|
||||
else {
|
||||
err = py_oid_to_git_oid_expand(self->repo->repo, py_oid, &oid);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
ref_oid = &oid;
|
||||
}
|
||||
|
||||
if (py_message != Py_None) {
|
||||
message = py_str_to_c_str(py_message, encoding);
|
||||
if (message == NULL)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Go */
|
||||
repo = git_reference_owner(self->reference);
|
||||
err = git_reflog_read(&reflog, repo, git_reference_name(self->reference));
|
||||
if (err < 0) {
|
||||
free((void *)message);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
committer = (git_signature *)py_committer->signature;
|
||||
err = git_reflog_append(reflog, ref_oid, committer, message);
|
||||
if (!err)
|
||||
err = git_reflog_write(reflog);
|
||||
|
||||
git_reflog_free(reflog);
|
||||
free((void *)message);
|
||||
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Reference_get_object__doc__,
|
||||
"get_object() -> object\n"
|
||||
"\n"
|
||||
"Retrieves the object the current reference is pointing to.");
|
||||
"Retrieves the object the current reference is pointing to.\n"
|
||||
"\n"
|
||||
"This method is deprecated, please use Reference.peel() instead.");
|
||||
|
||||
PyObject *
|
||||
Reference_get_object(Reference *self)
|
||||
{
|
||||
return PyObject_CallMethod((PyObject *) self, "peel", NULL);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Reference_peel__doc__,
|
||||
"peel(type=None) -> object\n"
|
||||
"\n"
|
||||
"Retrieve an object of the given type by recursive peeling.\n"
|
||||
"\n"
|
||||
"If no type is provided, the first non-tag object will be returned.");
|
||||
|
||||
PyObject *
|
||||
Reference_peel(Reference *self, PyObject *args)
|
||||
{
|
||||
int err;
|
||||
git_object* obj;
|
||||
git_otype otype;
|
||||
git_object *obj;
|
||||
PyObject *py_type = Py_None;
|
||||
|
||||
CHECK_REFERENCE(self);
|
||||
|
||||
err = git_reference_peel(&obj, self->reference, GIT_OBJ_ANY);
|
||||
if (!PyArg_ParseTuple(args, "|O", &py_type))
|
||||
return NULL;
|
||||
|
||||
otype = py_object_to_otype(py_type);
|
||||
if (otype == GIT_OBJ_BAD)
|
||||
return NULL;
|
||||
|
||||
err = git_reference_peel(&obj, self->reference, otype);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return wrap_object(obj, self->repo);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(RefLogEntry_committer__doc__, "Committer.");
|
||||
|
||||
PyObject *
|
||||
@ -446,16 +424,16 @@ RefLogEntry_init(RefLogEntry *self, PyObject *args, PyObject *kwds)
|
||||
static void
|
||||
RefLogEntry_dealloc(RefLogEntry *self)
|
||||
{
|
||||
free(self->oid_old);
|
||||
free(self->oid_new);
|
||||
Py_CLEAR(self->oid_old);
|
||||
Py_CLEAR(self->oid_new);
|
||||
free(self->message);
|
||||
git_signature_free(self->signature);
|
||||
PyObject_Del(self);
|
||||
}
|
||||
|
||||
PyMemberDef RefLogEntry_members[] = {
|
||||
MEMBER(RefLogEntry, oid_new, T_STRING, "New oid."),
|
||||
MEMBER(RefLogEntry, oid_old, T_STRING, "Old oid."),
|
||||
MEMBER(RefLogEntry, oid_new, T_OBJECT, "New oid."),
|
||||
MEMBER(RefLogEntry, oid_old, T_OBJECT, "Old oid."),
|
||||
MEMBER(RefLogEntry, message, T_STRING, "Message."),
|
||||
{NULL}
|
||||
};
|
||||
@ -514,15 +492,16 @@ PyMethodDef Reference_methods[] = {
|
||||
METHOD(Reference, rename, METH_O),
|
||||
METHOD(Reference, resolve, METH_NOARGS),
|
||||
METHOD(Reference, log, METH_NOARGS),
|
||||
METHOD(Reference, log_append, METH_VARARGS),
|
||||
METHOD(Reference, get_object, METH_NOARGS),
|
||||
METHOD(Reference, set_target, METH_VARARGS | METH_KEYWORDS),
|
||||
METHOD(Reference, peel, METH_VARARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef Reference_getseters[] = {
|
||||
GETTER(Reference, name),
|
||||
GETTER(Reference, shorthand),
|
||||
GETSET(Reference, target),
|
||||
GETTER(Reference, target),
|
||||
GETTER(Reference, type),
|
||||
{NULL}
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
640
src/repository.c
640
src/repository.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -36,7 +36,6 @@
|
||||
#include "note.h"
|
||||
#include "repository.h"
|
||||
#include "branch.h"
|
||||
#include "blame.h"
|
||||
#include "signature.h"
|
||||
#include <git2/odb_backend.h>
|
||||
|
||||
@ -56,6 +55,9 @@ extern PyTypeObject ReferenceType;
|
||||
extern PyTypeObject NoteType;
|
||||
extern PyTypeObject NoteIterType;
|
||||
|
||||
/* forward-declaration for Repsository._from_c() */
|
||||
PyTypeObject RepositoryType;
|
||||
|
||||
git_otype
|
||||
int_to_loose_object_type(int type_id)
|
||||
{
|
||||
@ -68,11 +70,25 @@ int_to_loose_object_type(int type_id)
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *
|
||||
wrap_repository(git_repository *c_repo)
|
||||
{
|
||||
Repository *py_repo = PyObject_GC_New(Repository, &RepositoryType);
|
||||
|
||||
if (py_repo) {
|
||||
py_repo->repo = c_repo;
|
||||
py_repo->config = NULL;
|
||||
py_repo->index = NULL;
|
||||
py_repo->owned = 1;
|
||||
}
|
||||
|
||||
return (PyObject *)py_repo;
|
||||
}
|
||||
|
||||
int
|
||||
Repository_init(Repository *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *path;
|
||||
int err;
|
||||
PyObject *backend;
|
||||
|
||||
if (kwds && PyDict_Size(kwds) > 0) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
@ -80,28 +96,72 @@ Repository_init(Repository *self, PyObject *args, PyObject *kwds)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &path))
|
||||
return -1;
|
||||
|
||||
err = git_repository_open(&self->repo, path);
|
||||
if (err < 0) {
|
||||
Error_set_str(err, path);
|
||||
if (!PyArg_ParseTuple(args, "O", &backend)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
self->repo = PyCapsule_GetPointer(backend, "backend");
|
||||
if (self->repo == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"Repository unable to unpack backend.");
|
||||
return -1;
|
||||
}
|
||||
self->owned = 1;
|
||||
self->config = NULL;
|
||||
self->index = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository__from_c__doc__, "Init a Repository from a pointer. For internal use only.");
|
||||
PyObject *
|
||||
Repository__from_c(Repository *py_repo, PyObject *args)
|
||||
{
|
||||
PyObject *py_pointer, *py_free;
|
||||
char *buffer;
|
||||
Py_ssize_t len;
|
||||
int err;
|
||||
|
||||
py_repo->repo = NULL;
|
||||
py_repo->config = NULL;
|
||||
py_repo->index = NULL;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "OO!", &py_pointer, &PyBool_Type, &py_free))
|
||||
return NULL;
|
||||
|
||||
err = PyBytes_AsStringAndSize(py_pointer, &buffer, &len);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
if (len != sizeof(git_repository *)) {
|
||||
PyErr_SetString(PyExc_TypeError, "invalid pointer length");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
py_repo->repo = *((git_repository **) buffer);
|
||||
py_repo->owned = py_free == Py_True;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository__disown__doc__, "Mark the object as not-owned by us. For internal use only.");
|
||||
PyObject *
|
||||
Repository__disown(Repository *py_repo)
|
||||
{
|
||||
py_repo->owned = 0;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
void
|
||||
Repository_dealloc(Repository *self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_CLEAR(self->index);
|
||||
Py_CLEAR(self->config);
|
||||
git_repository_free(self->repo);
|
||||
|
||||
if (self->owned)
|
||||
git_repository_free(self->repo);
|
||||
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
||||
@ -178,38 +238,6 @@ Repository_head__get__(Repository *self)
|
||||
return wrap_reference(head, self);
|
||||
}
|
||||
|
||||
int
|
||||
Repository_head__set__(Repository *self, PyObject *py_val)
|
||||
{
|
||||
int err;
|
||||
if (PyObject_TypeCheck(py_val, &OidType)) {
|
||||
git_oid oid;
|
||||
py_oid_to_git_oid(py_val, &oid);
|
||||
err = git_repository_set_head_detached(self->repo, &oid, NULL, NULL);
|
||||
if (err < 0) {
|
||||
Error_set(err);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
const char *refname;
|
||||
PyObject *trefname;
|
||||
|
||||
refname = py_str_borrow_c_str(&trefname, py_val, NULL);
|
||||
if (refname == NULL)
|
||||
return -1;
|
||||
|
||||
err = git_repository_set_head(self->repo, refname, NULL, NULL);
|
||||
Py_DECREF(trefname);
|
||||
if (err < 0) {
|
||||
Error_set_str(err, refname);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_head_is_detached__doc__,
|
||||
"A repository's HEAD is detached when it points directly to a commit\n"
|
||||
"instead of a branch.");
|
||||
@ -293,9 +321,11 @@ Repository_git_object_lookup_prefix(Repository *self, PyObject *key)
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_lookup_branch__doc__,
|
||||
"lookup_branch(branch_name, [branch_type]) -> Object\n"
|
||||
"lookup_branch(branch_name, [branch_type]) -> Branch\n"
|
||||
"\n"
|
||||
"Returns the Git reference for the given branch name (local or remote).");
|
||||
"Returns the Git reference for the given branch name (local or remote).\n"
|
||||
"If branch_type is GIT_BRANCH_REMOTE, you must include the remote name\n"
|
||||
"in the branch name (eg 'origin/master').");
|
||||
|
||||
PyObject *
|
||||
Repository_lookup_branch(Repository *self, PyObject *args)
|
||||
@ -319,6 +349,26 @@ Repository_lookup_branch(Repository *self, PyObject *args)
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_path_is_ignored__doc__,
|
||||
"Check if a path is ignored in the repository.");
|
||||
|
||||
PyObject *
|
||||
Repository_path_is_ignored(Repository *self, PyObject *args)
|
||||
{
|
||||
int ignored;
|
||||
char *path;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "s", &path))
|
||||
return NULL;
|
||||
|
||||
git_ignore_path_is_ignored(&ignored, self->repo, path);
|
||||
if (ignored == 1)
|
||||
Py_RETURN_TRUE;
|
||||
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_revparse_single__doc__,
|
||||
"revparse_single(revision) -> Object\n"
|
||||
"\n"
|
||||
@ -511,7 +561,8 @@ Repository_workdir__set__(Repository *self, PyObject *py_workdir)
|
||||
PyDoc_STRVAR(Repository_merge_base__doc__,
|
||||
"merge_base(oid, oid) -> Oid\n"
|
||||
"\n"
|
||||
"Find as good common ancestors as possible for a merge.");
|
||||
"Find as good common ancestors as possible for a merge.\n"
|
||||
"Returns None if there is no merge base between the commits");
|
||||
|
||||
PyObject *
|
||||
Repository_merge_base(Repository *self, PyObject *args)
|
||||
@ -535,6 +586,10 @@ Repository_merge_base(Repository *self, PyObject *args)
|
||||
return NULL;
|
||||
|
||||
err = git_merge_base(&oid, self->repo, &oid1, &oid2);
|
||||
|
||||
if (err == GIT_ENOTFOUND)
|
||||
Py_RETURN_NONE;
|
||||
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -548,7 +603,7 @@ PyDoc_STRVAR(Repository_merge_analysis__doc__,
|
||||
"them into the HEAD of the repository\n"
|
||||
"\n"
|
||||
"The first returned value is a mixture of the GIT_MERGE_ANALYSIS_NONE, _NORMAL,\n"
|
||||
" _UP_TO_DATE, _FASTFORWARD and _UNBORN flags.\n"
|
||||
"_UP_TO_DATE, _FASTFORWARD and _UNBORN flags.\n"
|
||||
"The second value is the user's preference from 'merge.ff'");
|
||||
|
||||
PyObject *
|
||||
@ -557,7 +612,7 @@ Repository_merge_analysis(Repository *self, PyObject *py_id)
|
||||
int err;
|
||||
size_t len;
|
||||
git_oid id;
|
||||
git_merge_head *merge_head;
|
||||
git_annotated_commit *commit;
|
||||
git_merge_analysis_t analysis;
|
||||
git_merge_preference_t preference;
|
||||
|
||||
@ -565,12 +620,12 @@ Repository_merge_analysis(Repository *self, PyObject *py_id)
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
err = git_merge_head_from_id(&merge_head, self->repo, &id);
|
||||
err = git_annotated_commit_lookup(&commit, self->repo, &id);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
err = git_merge_analysis(&analysis, &preference, self->repo, (const git_merge_head **) &merge_head, 1);
|
||||
git_merge_head_free(merge_head);
|
||||
err = git_merge_analysis(&analysis, &preference, self->repo, (const git_annotated_commit **) &commit, 1);
|
||||
git_annotated_commit_free(commit);
|
||||
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
@ -592,7 +647,7 @@ PyDoc_STRVAR(Repository_merge__doc__,
|
||||
PyObject *
|
||||
Repository_merge(Repository *self, PyObject *py_oid)
|
||||
{
|
||||
git_merge_head *oid_merge_head;
|
||||
git_annotated_commit *commit;
|
||||
git_oid oid;
|
||||
int err;
|
||||
size_t len;
|
||||
@ -603,15 +658,56 @@ Repository_merge(Repository *self, PyObject *py_oid)
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
err = git_merge_head_from_id(&oid_merge_head, self->repo, &oid);
|
||||
err = git_annotated_commit_lookup(&commit, self->repo, &oid);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE | GIT_CHECKOUT_RECREATE_MISSING;
|
||||
err = git_merge(self->repo,
|
||||
(const git_merge_head **)&oid_merge_head, 1,
|
||||
(const git_annotated_commit **)&commit, 1,
|
||||
&merge_opts, &checkout_opts);
|
||||
|
||||
git_merge_head_free(oid_merge_head);
|
||||
git_annotated_commit_free(commit);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_cherrypick__doc__,
|
||||
"cherrypick(id)\n"
|
||||
"\n"
|
||||
"Cherry-pick the given oid, producing changes in the index and working directory.\n"
|
||||
"\n"
|
||||
"Merges the given commit into HEAD as a cherrypick, writing the results into the\n"
|
||||
"working directory. Any changes are staged for commit and any conflicts\n"
|
||||
"are written to the index. Callers should inspect the repository's\n"
|
||||
"index after this completes, resolve any conflicts and prepare a\n"
|
||||
"commit.");
|
||||
|
||||
PyObject *
|
||||
Repository_cherrypick(Repository *self, PyObject *py_oid)
|
||||
{
|
||||
git_commit *commit;
|
||||
git_oid oid;
|
||||
int err;
|
||||
size_t len;
|
||||
git_cherrypick_options cherrypick_opts = GIT_CHERRYPICK_OPTIONS_INIT;
|
||||
|
||||
len = py_oid_to_git_oid(py_oid, &oid);
|
||||
if (len == 0)
|
||||
return NULL;
|
||||
|
||||
err = git_commit_lookup(&commit, self->repo, &oid);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
cherrypick_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_SAFE;
|
||||
err = git_cherrypick(self->repo,
|
||||
commit,
|
||||
(const git_cherrypick_options *)&cherrypick_opts);
|
||||
|
||||
git_commit_free(commit);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -766,8 +862,88 @@ Repository_create_blob_fromdisk(Repository *self, PyObject *args)
|
||||
}
|
||||
|
||||
|
||||
#define BUFSIZE 4096
|
||||
|
||||
PyDoc_STRVAR(Repository_create_blob_fromiobase__doc__,
|
||||
"create_blob_fromiobase(io.IOBase) -> Oid\n"
|
||||
"\n"
|
||||
"Create a new blob from an IOBase object.");
|
||||
|
||||
PyObject *
|
||||
Repository_create_blob_fromiobase(Repository *self, PyObject *py_file)
|
||||
{
|
||||
git_writestream *stream;
|
||||
git_oid oid;
|
||||
PyObject *py_is_readable;
|
||||
int is_readable;
|
||||
int err;
|
||||
|
||||
py_is_readable = PyObject_CallMethod(py_file, "readable", NULL);
|
||||
if (!py_is_readable) {
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError))
|
||||
PyErr_SetObject(PyExc_TypeError, py_file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
is_readable = PyObject_IsTrue(py_is_readable);
|
||||
Py_DECREF(py_is_readable);
|
||||
|
||||
if (!is_readable) {
|
||||
Py_DECREF(py_file);
|
||||
PyErr_SetString(PyExc_TypeError, "expected readable IO type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_blob_create_fromstream(&stream, self->repo, NULL);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
for (;;) {
|
||||
PyObject *py_bytes;
|
||||
char *bytes;
|
||||
Py_ssize_t size;
|
||||
|
||||
py_bytes = PyObject_CallMethod(py_file, "read", "i", 4096);
|
||||
if (!py_bytes)
|
||||
return NULL;
|
||||
|
||||
if (py_bytes == Py_None) {
|
||||
Py_DECREF(py_bytes);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (PyBytes_AsStringAndSize(py_bytes, &bytes, &size)) {
|
||||
Py_DECREF(py_bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
Py_DECREF(py_bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
err = stream->write(stream, bytes, size);
|
||||
Py_DECREF(py_bytes);
|
||||
if (err < 0)
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (err < 0) {
|
||||
stream->free(stream);
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
err = git_blob_create_fromstream_commit(&oid, stream);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_create_commit__doc__,
|
||||
"create_commit(reference, author, committer, message, tree, parents[, encoding]) -> Oid\n"
|
||||
"create_commit(reference_name, author, committer, message, tree, parents[, encoding]) -> Oid\n"
|
||||
"\n"
|
||||
"Create a new commit object, return its oid.");
|
||||
|
||||
@ -893,7 +1069,7 @@ Repository_create_tag(Repository *self, PyObject *args)
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_create_branch__doc__,
|
||||
"create_branch(name, commit, force=False) -> bytes\n"
|
||||
"create_branch(name, commit, force=False) -> Branch\n"
|
||||
"\n"
|
||||
"Create a new branch \"name\" which points to a commit.\n"
|
||||
"\n"
|
||||
@ -918,7 +1094,7 @@ Repository_create_branch(Repository *self, PyObject *args)
|
||||
if (!PyArg_ParseTuple(args, "sO!|i", &c_name, &CommitType, &py_commit, &force))
|
||||
return NULL;
|
||||
|
||||
err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force, NULL, NULL);
|
||||
err = git_branch_create(&c_reference, self->repo, c_name, py_commit->commit, force);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -965,10 +1141,66 @@ out:
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_listall_branches__doc__,
|
||||
"listall_branches([flags]) -> [str, ...]\n"
|
||||
PyDoc_STRVAR(Repository_listall_reference_objects__doc__,
|
||||
"listall_reference_objects() -> [Reference, ...]\n"
|
||||
"\n"
|
||||
"Return a tuple with all the branches in the repository.");
|
||||
"Return a list with all the reference objects in the repository.");
|
||||
|
||||
PyObject *
|
||||
Repository_listall_reference_objects(Repository *self, PyObject *args)
|
||||
{
|
||||
git_reference_iterator *iter;
|
||||
git_reference *ref = NULL;
|
||||
int err;
|
||||
PyObject *list;
|
||||
|
||||
list = PyList_New(0);
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
if ((err = git_reference_iterator_new(&iter, self->repo)) < 0)
|
||||
return Error_set(err);
|
||||
|
||||
while ((err = git_reference_next(&ref, iter)) == 0) {
|
||||
PyObject *py_ref = wrap_reference(ref, self);
|
||||
if (py_ref == NULL)
|
||||
goto error;
|
||||
|
||||
err = PyList_Append(list, py_ref);
|
||||
Py_DECREF(py_ref);
|
||||
|
||||
if (err < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
git_reference_iterator_free(iter);
|
||||
if (err == GIT_ITEROVER)
|
||||
err = 0;
|
||||
|
||||
if (err < 0) {
|
||||
Py_CLEAR(list);
|
||||
return Error_set(err);
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
error:
|
||||
git_reference_iterator_free(iter);
|
||||
Py_CLEAR(list);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_listall_branches__doc__,
|
||||
"listall_branches([flag]) -> [str, ...]\n"
|
||||
"\n"
|
||||
"Return a list with all the branches in the repository.\n"
|
||||
"\n"
|
||||
"The *flag* may be:\n"
|
||||
"\n"
|
||||
"- GIT_BRANCH_LOCAL - return all local branches (set by default)\n"
|
||||
"- GIT_BRANCH_REMOTE - return all remote-tracking branches\n"
|
||||
"- GIT_BRANCH_ALL - return local branches and remote-tracking branches");
|
||||
|
||||
PyObject *
|
||||
Repository_listall_branches(Repository *self, PyObject *args)
|
||||
@ -1022,6 +1254,173 @@ error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_listall_submodules__doc__,
|
||||
"listall_submodules() -> [str, ...]\n"
|
||||
"\n"
|
||||
"Return a list with all submodule paths in the repository.\n");
|
||||
|
||||
static int foreach_path_cb(git_submodule *submodule, const char *name, void *payload)
|
||||
{
|
||||
PyObject *list = (PyObject *)payload;
|
||||
PyObject *path = to_unicode(git_submodule_path(submodule), NULL, NULL);
|
||||
|
||||
return PyList_Append(list, path);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
Repository_listall_submodules(Repository *self, PyObject *args)
|
||||
{
|
||||
int err;
|
||||
PyObject *list;
|
||||
|
||||
list = PyList_New(0);
|
||||
if (list == NULL)
|
||||
return NULL;
|
||||
|
||||
err = git_submodule_foreach(self->repo, foreach_path_cb, list);
|
||||
if (err != 0) {
|
||||
Py_DECREF(list);
|
||||
return Py_None;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository_init_submodules__doc__,
|
||||
"init_submodule(submodules=None, overwrite=False)\n"
|
||||
"\n"
|
||||
"Initialize all submodules in repository.\n"
|
||||
"submodules: List of submodules to initialize. Default argument initializes all submodules.\n"
|
||||
"overwrite: Flag indicating if initialization should overwrite submodule entries.\n");
|
||||
|
||||
static int foreach_sub_init_cb(git_submodule *submodule, const char *name, void *payload)
|
||||
{
|
||||
return git_submodule_init(submodule, *(int*)payload);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
Repository_init_submodules(Repository* self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *list = Py_None;
|
||||
PyObject *oflag = Py_False;
|
||||
char *kwlist[] = {"submodules", "overwrite", NULL};
|
||||
int err, fflag;
|
||||
PyObject *iter, *subpath, *next;
|
||||
const char *c_subpath;
|
||||
git_submodule *submodule;
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &list, &oflag))
|
||||
return NULL;
|
||||
|
||||
fflag = PyObject_IsTrue(oflag);
|
||||
|
||||
if (fflag != 0 && fflag != 1)
|
||||
fflag = 0;
|
||||
|
||||
//Init all submodules listed in repository
|
||||
if (list == Py_None) {
|
||||
err = git_submodule_foreach(self->repo, foreach_sub_init_cb, &fflag);
|
||||
if (err != 0)
|
||||
return Error_set(err);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
iter = PyObject_GetIter(list);
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
next = PyIter_Next(iter);
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
c_subpath = py_str_borrow_c_str(&subpath, next, NULL);
|
||||
|
||||
git_submodule_lookup(&submodule, self->repo, c_subpath);
|
||||
Py_DECREF(subpath);
|
||||
if (!submodule) {
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
"Submodule does not exist");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_submodule_init(submodule, fflag);
|
||||
if (err != 0) {
|
||||
return Error_set(err);
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_update_submodules__doc__,
|
||||
"update_submodules(submodules=None, init=False)\n"
|
||||
"\n"
|
||||
"Updates the specified submodules, or all if None are specified\n"
|
||||
"init: Flag indicating if submodules should be automatically initialized if necessary.\n");
|
||||
|
||||
static int foreach_sub_update_cb(git_submodule *submodule, const char *name, void *payload)
|
||||
{
|
||||
git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
|
||||
return git_submodule_update(submodule, *(int*)payload, &opts);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
Repository_update_submodules(Repository *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
PyObject *list = Py_None;
|
||||
PyObject *py_init = Py_False;
|
||||
PyObject *iter, *next, *subpath;
|
||||
int init, err;
|
||||
const char *c_subpath;
|
||||
git_submodule *submodule;
|
||||
git_submodule_update_options opts = GIT_SUBMODULE_UPDATE_OPTIONS_INIT;
|
||||
|
||||
char *kwlist[] = {"submodules", "init", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &list, &py_init))
|
||||
return NULL;
|
||||
|
||||
init = PyObject_IsTrue(py_init);
|
||||
|
||||
if (init != 0 && init != 1)
|
||||
init = 0;
|
||||
|
||||
if (list == Py_None) {
|
||||
err = git_submodule_foreach(self->repo, foreach_sub_update_cb, &init);
|
||||
if (err != 0)
|
||||
return Error_set(err);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
iter = PyObject_GetIter(list);
|
||||
if (!iter)
|
||||
return NULL;
|
||||
|
||||
while (1) {
|
||||
next = PyIter_Next(iter);
|
||||
if (!next)
|
||||
break;
|
||||
|
||||
c_subpath = py_str_borrow_c_str(&subpath, next, NULL);
|
||||
|
||||
git_submodule_lookup(&submodule, self->repo, c_subpath);
|
||||
Py_DECREF(subpath);
|
||||
if (!submodule) {
|
||||
PyErr_SetString(PyExc_KeyError,
|
||||
"Submodule does not exist");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_submodule_update(submodule, init, &opts);
|
||||
if (err != 0) {
|
||||
return Error_set(err);
|
||||
}
|
||||
}
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_lookup_reference__doc__,
|
||||
"lookup_reference(name) -> Reference\n"
|
||||
@ -1085,7 +1484,7 @@ Repository_create_reference_direct(Repository *self, PyObject *args,
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL, NULL);
|
||||
err = git_reference_create(&c_reference, self->repo, c_name, &oid, force, NULL);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -1119,7 +1518,7 @@ Repository_create_reference_symbolic(Repository *self, PyObject *args,
|
||||
return NULL;
|
||||
|
||||
err = git_reference_symbolic_create(&c_reference, self->repo, c_name,
|
||||
c_target, force, NULL, NULL);
|
||||
c_target, force, NULL);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
@ -1164,7 +1563,7 @@ Repository_status(Repository *self)
|
||||
path = entry->head_to_index->old_file.path;
|
||||
else
|
||||
path = entry->index_to_workdir->old_file.path;
|
||||
status = PyLong_FromLong((long) entry->status);
|
||||
status = PyInt_FromLong((long) entry->status);
|
||||
|
||||
err = PyDict_SetItemString(dict, path, status);
|
||||
Py_CLEAR(status);
|
||||
@ -1206,7 +1605,7 @@ Repository_status_file(Repository *self, PyObject *value)
|
||||
free(path);
|
||||
return err_obj;
|
||||
}
|
||||
return PyLong_FromLong(status);
|
||||
return PyInt_FromLong(status);
|
||||
}
|
||||
|
||||
|
||||
@ -1249,7 +1648,7 @@ Repository_TreeBuilder(Repository *self, PyObject *args)
|
||||
}
|
||||
}
|
||||
|
||||
err = git_treebuilder_create(&bld, tree);
|
||||
err = git_treebuilder_new(&bld, self->repo, tree);
|
||||
if (must_free != NULL)
|
||||
git_tree_free(must_free);
|
||||
|
||||
@ -1342,8 +1741,8 @@ Repository_create_note(Repository *self, PyObject* args)
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
err = git_note_create(¬e_id, self->repo, py_author->signature,
|
||||
py_committer->signature, ref,
|
||||
err = git_note_create(¬e_id, self->repo, ref, py_author->signature,
|
||||
py_committer->signature,
|
||||
&annotated_id, message, force);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
@ -1374,79 +1773,13 @@ Repository_lookup_note(Repository *self, PyObject* args)
|
||||
return (PyObject*) wrap_note(self, &annotated_id, ref);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_blame__doc__,
|
||||
"blame(path, [flags, min_match_characters, newest_commit, oldest_commit,\n"
|
||||
" min_line, max_line]) -> blame\n"
|
||||
"\n"
|
||||
"Get the blame for a single file.\n"
|
||||
"\n"
|
||||
"Arguments:\n"
|
||||
"\n"
|
||||
"path\n"
|
||||
" A path to file to consider.\n"
|
||||
"flags\n"
|
||||
" A GIT_BLAME_* constant.\n"
|
||||
"min_match_characters\n"
|
||||
" The number of alphanum chars that must be detected as moving/copying\n"
|
||||
" within a file for it to associate those lines with the parent commit.\n"
|
||||
"newest_commit\n"
|
||||
" The id of the newest commit to consider.\n"
|
||||
"oldest_commit\n"
|
||||
" The id of the oldest commit to consider.\n"
|
||||
"min_line\n"
|
||||
" The first line in the file to blame.\n"
|
||||
"max_line\n"
|
||||
" The last line in the file to blame.\n"
|
||||
"\n"
|
||||
"Examples::\n"
|
||||
"\n"
|
||||
" repo.blame('foo.c', flags=GIT_BLAME_TRACK_COPIES_SAME_FILE)");
|
||||
|
||||
PyObject *
|
||||
Repository_blame(Repository *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
git_blame_options opts = GIT_BLAME_OPTIONS_INIT;
|
||||
git_blame *blame;
|
||||
char *path;
|
||||
PyObject *value1 = NULL;
|
||||
PyObject *value2 = NULL;
|
||||
int err;
|
||||
char *keywords[] = {"path", "flags", "min_match_characters", "newest_commit",
|
||||
"oldest_commit", "min_line", "max_line", NULL};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|IHO!O!II", keywords,
|
||||
&path, &opts.flags,
|
||||
&opts.min_match_characters,
|
||||
&OidType, &value1,
|
||||
&OidType, &value2,
|
||||
&opts.min_line, &opts.max_line))
|
||||
return NULL;
|
||||
|
||||
if (value1) {
|
||||
err = py_oid_to_git_oid_expand(self->repo, value1, &opts.newest_commit);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
}
|
||||
if (value2) {
|
||||
err = py_oid_to_git_oid_expand(self->repo, value2, &opts.oldest_commit);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
err = git_blame_file(&blame, self->repo, path, &opts);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
return wrap_blame(blame, self);
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_reset__doc__,
|
||||
"reset(oid, reset_type)\n"
|
||||
"\n"
|
||||
"Resets current head to the provided oid.\n"
|
||||
"reset_type:\n"
|
||||
"GIT_RESET_SOFT: resets head to point to oid, but does not modfy working copy, and leaves the changes in the index.\n"
|
||||
"GIT_RESET_MIXED: resets head to point to oid, but does not modfy working copy. It empties the index too.\n"
|
||||
"GIT_RESET_SOFT: resets head to point to oid, but does not modify working copy, and leaves the changes in the index.\n"
|
||||
"GIT_RESET_MIXED: resets head to point to oid, but does not modify working copy. It empties the index too.\n"
|
||||
"GIT_RESET_HARD: resets head to point to oid, and resets too the working copy and the content of the index.\n");
|
||||
|
||||
PyObject *
|
||||
@ -1470,17 +1803,36 @@ Repository_reset(Repository *self, PyObject* args)
|
||||
|
||||
err = git_object_lookup_prefix(&target, self->repo, &oid, len,
|
||||
GIT_OBJ_ANY);
|
||||
err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL, NULL);
|
||||
err = err < 0 ? err : git_reset(self->repo, target, reset_type, NULL);
|
||||
git_object_free(target);
|
||||
if (err < 0)
|
||||
return Error_set_oid(err, &oid, len);
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Repository_expand_id__doc__,
|
||||
"expand_id(hex) -> Oid\n"
|
||||
"\n"
|
||||
"Expand a string into a full Oid according to the objects in this repsitory.\n");
|
||||
|
||||
PyObject *
|
||||
Repository_expand_id(Repository *self, PyObject *py_hex)
|
||||
{
|
||||
git_oid oid;
|
||||
int err;
|
||||
|
||||
err = py_oid_to_git_oid_expand(self->repo, py_hex, &oid);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
return git_oid_to_python(&oid);
|
||||
}
|
||||
|
||||
PyMethodDef Repository_methods[] = {
|
||||
METHOD(Repository, create_blob, METH_VARARGS),
|
||||
METHOD(Repository, create_blob_fromworkdir, METH_VARARGS),
|
||||
METHOD(Repository, create_blob_fromdisk, METH_VARARGS),
|
||||
METHOD(Repository, create_blob_fromiobase, METH_O),
|
||||
METHOD(Repository, create_commit, METH_VARARGS),
|
||||
METHOD(Repository, create_tag, METH_VARARGS),
|
||||
METHOD(Repository, TreeBuilder, METH_VARARGS),
|
||||
@ -1488,11 +1840,16 @@ PyMethodDef Repository_methods[] = {
|
||||
METHOD(Repository, merge_base, METH_VARARGS),
|
||||
METHOD(Repository, merge_analysis, METH_O),
|
||||
METHOD(Repository, merge, METH_O),
|
||||
METHOD(Repository, cherrypick, METH_O),
|
||||
METHOD(Repository, read, METH_O),
|
||||
METHOD(Repository, write, METH_VARARGS),
|
||||
METHOD(Repository, create_reference_direct, METH_VARARGS),
|
||||
METHOD(Repository, create_reference_symbolic, METH_VARARGS),
|
||||
METHOD(Repository, listall_references, METH_NOARGS),
|
||||
METHOD(Repository, listall_reference_objects, METH_NOARGS),
|
||||
METHOD(Repository, listall_submodules, METH_NOARGS),
|
||||
METHOD(Repository, init_submodules, METH_VARARGS | METH_KEYWORDS),
|
||||
METHOD(Repository, update_submodules, METH_VARARGS | METH_KEYWORDS),
|
||||
METHOD(Repository, lookup_reference, METH_O),
|
||||
METHOD(Repository, revparse_single, METH_O),
|
||||
METHOD(Repository, status, METH_NOARGS),
|
||||
@ -1502,16 +1859,19 @@ PyMethodDef Repository_methods[] = {
|
||||
METHOD(Repository, lookup_note, METH_VARARGS),
|
||||
METHOD(Repository, git_object_lookup_prefix, METH_O),
|
||||
METHOD(Repository, lookup_branch, METH_VARARGS),
|
||||
METHOD(Repository, path_is_ignored, METH_VARARGS),
|
||||
METHOD(Repository, listall_branches, METH_VARARGS),
|
||||
METHOD(Repository, create_branch, METH_VARARGS),
|
||||
METHOD(Repository, blame, METH_VARARGS | METH_KEYWORDS),
|
||||
METHOD(Repository, reset, METH_VARARGS),
|
||||
METHOD(Repository, expand_id, METH_O),
|
||||
METHOD(Repository, _from_c, METH_VARARGS),
|
||||
METHOD(Repository, _disown, METH_NOARGS),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
PyGetSetDef Repository_getseters[] = {
|
||||
GETTER(Repository, path),
|
||||
GETSET(Repository, head),
|
||||
GETTER(Repository, head),
|
||||
GETTER(Repository, head_is_detached),
|
||||
GETTER(Repository, head_is_unborn),
|
||||
GETTER(Repository, is_empty),
|
||||
@ -1524,7 +1884,7 @@ PyGetSetDef Repository_getseters[] = {
|
||||
|
||||
|
||||
PyDoc_STRVAR(Repository__doc__,
|
||||
"Repository(path) -> Repository\n"
|
||||
"Repository(backend) -> Repository\n"
|
||||
"\n"
|
||||
"Git repository.");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -33,6 +33,8 @@
|
||||
#include <git2.h>
|
||||
#include "types.h"
|
||||
|
||||
PyObject *wrap_repository(git_repository *c_repo);
|
||||
|
||||
int Repository_init(Repository *self, PyObject *args, PyObject *kwds);
|
||||
int Repository_traverse(Repository *self, visitproc visit, void *arg);
|
||||
int Repository_clear(Repository *self);
|
||||
@ -56,6 +58,8 @@ PyObject* Repository_create_commit(Repository *self, PyObject *args);
|
||||
PyObject* Repository_create_tag(Repository *self, PyObject *args);
|
||||
PyObject* Repository_create_branch(Repository *self, PyObject *args);
|
||||
PyObject* Repository_listall_references(Repository *self, PyObject *args);
|
||||
PyObject* Repository_listall_reference_objects(Repository *self,
|
||||
PyObject *args);
|
||||
PyObject* Repository_listall_branches(Repository *self, PyObject *args);
|
||||
PyObject* Repository_lookup_reference(Repository *self, PyObject *py_name);
|
||||
|
||||
@ -70,5 +74,6 @@ PyObject* Repository_TreeBuilder(Repository *self, PyObject *args);
|
||||
PyObject* Repository_blame(Repository *self, PyObject *args, PyObject *kwds);
|
||||
|
||||
PyObject* Repository_merge(Repository *self, PyObject *py_oid);
|
||||
PyObject* Repository_cherrypick(Repository *self, PyObject *py_oid);
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -38,7 +38,7 @@ Signature_init(Signature *self, PyObject *args, PyObject *kwds)
|
||||
{
|
||||
char *keywords[] = {"name", "email", "time", "offset", "encoding", NULL};
|
||||
PyObject *py_name, *tname;
|
||||
char *email, *encoding = "ascii";
|
||||
char *email, *encoding = "utf-8";
|
||||
const char *name;
|
||||
long long time = -1;
|
||||
int offset = 0;
|
||||
@ -96,10 +96,10 @@ Signature_dealloc(Signature *self)
|
||||
|
||||
PyDoc_STRVAR(Signature__pointer__doc__, "Get the signature's pointer. For internal use only.");
|
||||
PyObject *
|
||||
Signature__pointer__get__(Repository *self)
|
||||
Signature__pointer__get__(Signature *self)
|
||||
{
|
||||
/* Bytes means a raw buffer */
|
||||
return PyBytes_FromStringAndSize((char *) &self->repo, sizeof(git_repository *));
|
||||
return PyBytes_FromStringAndSize((char *) &self->signature, sizeof(git_signature *));
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(Signature__encoding__doc__, "Encoding.");
|
||||
@ -158,7 +158,7 @@ PyDoc_STRVAR(Signature_time__doc__, "Unix time.");
|
||||
PyObject *
|
||||
Signature_time__get__(Signature *self)
|
||||
{
|
||||
return PyLong_FromLongLong(self->signature->when.time);
|
||||
return PyInt_FromLongLong(self->signature->when.time);
|
||||
}
|
||||
|
||||
|
||||
@ -167,7 +167,7 @@ PyDoc_STRVAR(Signature_offset__doc__, "Offset from UTC in minutes.");
|
||||
PyObject *
|
||||
Signature_offset__get__(Signature *self)
|
||||
{
|
||||
return PyLong_FromLong(self->signature->when.offset);
|
||||
return PyInt_FromLong(self->signature->when.offset);
|
||||
}
|
||||
|
||||
PyGetSetDef Signature_getseters[] = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -111,7 +111,11 @@ PyDoc_STRVAR(Tag__message__doc__, "Tag message (bytes).");
|
||||
PyObject *
|
||||
Tag__message__get__(Tag *self)
|
||||
{
|
||||
return PyBytes_FromString(git_tag_message(self->tag));
|
||||
const char *message;
|
||||
message = git_tag_message(self->tag);
|
||||
if (!message)
|
||||
Py_RETURN_NONE;
|
||||
return PyBytes_FromString(message);
|
||||
}
|
||||
|
||||
PyMethodDef Tag_methods[] = {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
60
src/tree.c
60
src/tree.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -54,7 +54,7 @@ PyDoc_STRVAR(TreeEntry_filemode__doc__, "Filemode.");
|
||||
PyObject *
|
||||
TreeEntry_filemode__get__(TreeEntry *self)
|
||||
{
|
||||
return PyLong_FromLong(git_tree_entry_filemode(self->entry));
|
||||
return PyInt_FromLong(git_tree_entry_filemode(self->entry));
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +67,24 @@ TreeEntry_name__get__(TreeEntry *self)
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(TreeEntry__name__doc__, "Name (bytes).");
|
||||
|
||||
PyObject *
|
||||
TreeEntry__name__get__(TreeEntry *self)
|
||||
{
|
||||
return PyBytes_FromString(git_tree_entry_name(self->entry));
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(TreeEntry_type__doc__, "Type.");
|
||||
|
||||
PyObject *
|
||||
TreeEntry_type__get__(TreeEntry *self)
|
||||
{
|
||||
return to_path(git_object_type2string(git_tree_entry_type(self->entry)));
|
||||
}
|
||||
|
||||
|
||||
PyDoc_STRVAR(TreeEntry_id__doc__, "Object id.");
|
||||
|
||||
PyObject *
|
||||
@ -87,10 +105,20 @@ TreeEntry_oid__get__(TreeEntry *self)
|
||||
return TreeEntry_id__get__(self);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_ids(TreeEntry *a, TreeEntry *b)
|
||||
{
|
||||
const git_oid *id_a, *id_b;
|
||||
id_a = git_tree_entry_id(a->entry);
|
||||
id_b = git_tree_entry_id(b->entry);
|
||||
return git_oid_cmp(id_a, id_b);
|
||||
}
|
||||
|
||||
PyObject *
|
||||
TreeEntry_richcompare(PyObject *a, PyObject *b, int op)
|
||||
{
|
||||
PyObject *res;
|
||||
TreeEntry *ta, *tb;
|
||||
int cmp;
|
||||
|
||||
/* We only support comparing to another tree entry */
|
||||
@ -99,7 +127,14 @@ TreeEntry_richcompare(PyObject *a, PyObject *b, int op)
|
||||
return Py_NotImplemented;
|
||||
}
|
||||
|
||||
cmp =git_tree_entry_cmp(((TreeEntry*)a)->entry, ((TreeEntry*)b)->entry);
|
||||
ta = (TreeEntry *) a;
|
||||
tb = (TreeEntry *) b;
|
||||
|
||||
/* This is sorting order, if they sort equally, we still need to compare the ids */
|
||||
cmp = git_tree_entry_cmp(ta->entry, tb->entry);
|
||||
if (cmp == 0)
|
||||
cmp = compare_ids(ta, tb);
|
||||
|
||||
switch (op) {
|
||||
case Py_LT:
|
||||
res = (cmp <= 0) ? Py_True: Py_False;
|
||||
@ -137,17 +172,28 @@ TreeEntry_hex__get__(TreeEntry *self)
|
||||
return git_oid_to_py_str(git_tree_entry_id(self->entry));
|
||||
}
|
||||
|
||||
PyObject *
|
||||
TreeEntry_repr(TreeEntry *self)
|
||||
{
|
||||
char str[GIT_OID_HEXSZ + 1] = { 0 };
|
||||
const char *typename;
|
||||
|
||||
typename = git_object_type2string(git_tree_entry_type(self->entry));
|
||||
git_oid_fmt(str, git_tree_entry_id(self->entry));
|
||||
return PyString_FromFormat("pygit2.TreeEntry('%s', %s, %s)", git_tree_entry_name(self->entry), typename, str);
|
||||
}
|
||||
|
||||
PyGetSetDef TreeEntry_getseters[] = {
|
||||
GETTER(TreeEntry, filemode),
|
||||
GETTER(TreeEntry, name),
|
||||
GETTER(TreeEntry, _name),
|
||||
GETTER(TreeEntry, oid),
|
||||
GETTER(TreeEntry, id),
|
||||
GETTER(TreeEntry, hex),
|
||||
GETTER(TreeEntry, type),
|
||||
{NULL}
|
||||
};
|
||||
|
||||
|
||||
PyDoc_STRVAR(TreeEntry__doc__, "TreeEntry objects.");
|
||||
|
||||
PyTypeObject TreeEntryType = {
|
||||
@ -160,7 +206,7 @@ PyTypeObject TreeEntryType = {
|
||||
0, /* tp_getattr */
|
||||
0, /* tp_setattr */
|
||||
0, /* tp_compare */
|
||||
0, /* tp_repr */
|
||||
(reprfunc)TreeEntry_repr, /* tp_repr */
|
||||
0, /* tp_as_number */
|
||||
0, /* tp_as_sequence */
|
||||
0, /* tp_as_mapping */
|
||||
@ -244,7 +290,7 @@ Tree_fix_index(Tree *self, PyObject *py_index)
|
||||
size_t len;
|
||||
long slen;
|
||||
|
||||
index = PyLong_AsLong(py_index);
|
||||
index = PyInt_AsLong(py_index);
|
||||
if (PyErr_Occurred())
|
||||
return -1;
|
||||
|
||||
@ -313,7 +359,7 @@ Tree_getitem(Tree *self, PyObject *value)
|
||||
int err;
|
||||
|
||||
/* Case 1: integer */
|
||||
if (PyLong_Check(value))
|
||||
if (PyInt_Check(value))
|
||||
return Tree_getitem_by_index(self, value);
|
||||
|
||||
/* Case 2: byte or text string */
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -88,7 +88,7 @@ TreeBuilder_write(TreeBuilder *self)
|
||||
int err;
|
||||
git_oid oid;
|
||||
|
||||
err = git_treebuilder_write(&oid, self->repo->repo, self->bld);
|
||||
err = git_treebuilder_write(&oid, self->bld);
|
||||
if (err < 0)
|
||||
return Error_set(err);
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
95
src/types.h
95
src/types.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -32,8 +32,8 @@
|
||||
#include <Python.h>
|
||||
#include <git2.h>
|
||||
|
||||
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 21)
|
||||
#error You need a compatible libgit2 version (v0.21.x)
|
||||
#if !(LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR == 26)
|
||||
#error You need a compatible libgit2 version (v0.26.x)
|
||||
#endif
|
||||
|
||||
/*
|
||||
@ -47,6 +47,7 @@ typedef struct {
|
||||
git_repository *repo;
|
||||
PyObject *index; /* It will be None for a bare repository */
|
||||
PyObject *config; /* It will be None for a bare repository */
|
||||
int owned; /* _from_c() sometimes means we don't own the C pointer */
|
||||
} Repository;
|
||||
|
||||
|
||||
@ -79,7 +80,7 @@ typedef struct {
|
||||
PyObject_HEAD
|
||||
Repository *repo;
|
||||
git_note *note;
|
||||
char* annotated_id;
|
||||
PyObject* annotated_id;
|
||||
} Note;
|
||||
|
||||
typedef struct {
|
||||
@ -89,30 +90,41 @@ typedef struct {
|
||||
char* ref;
|
||||
} NoteIter;
|
||||
|
||||
/* git_patch */
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
git_patch *patch;
|
||||
PyObject* hunks;
|
||||
} Patch;
|
||||
|
||||
/* git _diff */
|
||||
SIMPLE_TYPE(Diff, git_diff, list)
|
||||
/* git_diff */
|
||||
SIMPLE_TYPE(Diff, git_diff, diff)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Diff* diff;
|
||||
Diff *diff;
|
||||
size_t i;
|
||||
size_t n;
|
||||
} DiffIter;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyObject* hunks;
|
||||
const char * old_file_path;
|
||||
const char * new_file_path;
|
||||
char* old_id;
|
||||
char* new_id;
|
||||
char status;
|
||||
unsigned similarity;
|
||||
unsigned additions;
|
||||
unsigned deletions;
|
||||
unsigned flags;
|
||||
} Patch;
|
||||
PyObject *id;
|
||||
char *path;
|
||||
git_off_t size;
|
||||
uint32_t flags;
|
||||
uint16_t mode;
|
||||
} DiffFile;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
git_delta_t status;
|
||||
uint32_t flags;
|
||||
uint16_t similarity;
|
||||
uint16_t nfiles;
|
||||
PyObject *old_file;
|
||||
PyObject *new_file;
|
||||
} DiffDelta;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
@ -121,8 +133,20 @@ typedef struct {
|
||||
int old_lines;
|
||||
int new_start;
|
||||
int new_lines;
|
||||
} Hunk;
|
||||
PyObject *header;
|
||||
} DiffHunk;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
char origin;
|
||||
int old_lineno;
|
||||
int new_lineno;
|
||||
int num_lines;
|
||||
git_off_t content_offset;
|
||||
PyObject *content;
|
||||
} DiffLine;
|
||||
|
||||
SIMPLE_TYPE(DiffStats, git_diff_stats, stats);
|
||||
|
||||
/* git_tree_walk , git_treebuilder*/
|
||||
SIMPLE_TYPE(TreeBuilder, git_treebuilder, bld)
|
||||
@ -147,12 +171,6 @@ typedef struct {
|
||||
git_index_entry entry;
|
||||
} IndexEntry;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Index *owner;
|
||||
int i;
|
||||
} IndexIter;
|
||||
|
||||
|
||||
/* git_reference, git_reflog */
|
||||
SIMPLE_TYPE(Walker, git_revwalk, walk)
|
||||
@ -164,8 +182,8 @@ typedef Reference Branch;
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
git_signature *signature;
|
||||
char *oid_old;
|
||||
char *oid_new;
|
||||
PyObject *oid_old;
|
||||
PyObject *oid_new;
|
||||
char *message;
|
||||
} RefLogEntry;
|
||||
|
||||
@ -185,27 +203,4 @@ typedef struct {
|
||||
char *encoding;
|
||||
} Signature;
|
||||
|
||||
/* git_blame */
|
||||
SIMPLE_TYPE(Blame, git_blame, blame)
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
Blame* blame;
|
||||
size_t i;
|
||||
size_t n;
|
||||
} BlameIter;
|
||||
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
unsigned lines_in_hunk;
|
||||
char* final_commit_id;
|
||||
unsigned final_start_line_number;
|
||||
git_signature* final_signature;
|
||||
char* orig_commit_id;
|
||||
char* orig_path;
|
||||
unsigned orig_start_line_number;
|
||||
git_signature* orig_signature;
|
||||
char boundary;
|
||||
} BlameHunk;
|
||||
|
||||
#endif
|
||||
|
51
src/utils.c
51
src/utils.c
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -31,6 +31,10 @@
|
||||
#include "utils.h"
|
||||
|
||||
extern PyTypeObject ReferenceType;
|
||||
extern PyTypeObject TreeType;
|
||||
extern PyTypeObject CommitType;
|
||||
extern PyTypeObject BlobType;
|
||||
extern PyTypeObject TagType;
|
||||
|
||||
/**
|
||||
* py_str_to_c_str() returns a newly allocated C string holding the string
|
||||
@ -79,8 +83,7 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
|
||||
}
|
||||
|
||||
/* Type error */
|
||||
PyErr_Format(PyExc_TypeError, "unexpected %.200s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
Error_type_error("unexpected %.200s", value);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -90,7 +93,7 @@ py_str_borrow_c_str(PyObject **tvalue, PyObject *value, const char *encoding)
|
||||
PyObject *
|
||||
get_pylist_from_git_strarray(git_strarray *strarray)
|
||||
{
|
||||
int index;
|
||||
size_t index;
|
||||
PyObject *new_list;
|
||||
|
||||
new_list = PyList_New(strarray->count);
|
||||
@ -153,3 +156,43 @@ on_error:
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static git_otype
|
||||
py_type_to_git_type(PyTypeObject *py_type)
|
||||
{
|
||||
if (py_type == &CommitType)
|
||||
return GIT_OBJ_COMMIT;
|
||||
else if (py_type == &TreeType)
|
||||
return GIT_OBJ_TREE;
|
||||
else if (py_type == &BlobType)
|
||||
return GIT_OBJ_BLOB;
|
||||
else if (py_type == &TagType)
|
||||
return GIT_OBJ_TAG;
|
||||
|
||||
PyErr_SetString(PyExc_ValueError, "invalid target type");
|
||||
return GIT_OBJ_BAD; /* -1 */
|
||||
}
|
||||
|
||||
git_otype
|
||||
py_object_to_otype(PyObject *py_type)
|
||||
{
|
||||
long value;
|
||||
|
||||
if (py_type == Py_None)
|
||||
return GIT_OBJ_ANY;
|
||||
|
||||
if (PyInt_Check(py_type)) {
|
||||
value = PyInt_AsLong(py_type);
|
||||
if (value == -1 && PyErr_Occurred())
|
||||
return GIT_OBJ_BAD;
|
||||
|
||||
/* TODO Check whether the value is a valid value */
|
||||
return (git_otype)value;
|
||||
}
|
||||
|
||||
if (PyType_Check(py_type))
|
||||
return py_type_to_git_type((PyTypeObject *) py_type);
|
||||
|
||||
PyErr_SetString(PyExc_ValueError, "invalid target type");
|
||||
return GIT_OBJ_BAD; /* -1 */
|
||||
}
|
||||
|
38
src/utils.h
38
src/utils.h
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -40,14 +40,17 @@
|
||||
#endif
|
||||
|
||||
/* Python 2 support */
|
||||
#ifndef Py_hash_t
|
||||
#define Py_hash_t long
|
||||
#endif
|
||||
|
||||
#ifndef PyLong_AsSize_t
|
||||
#define PyLong_AsSize_t (size_t)PyLong_AsSsize_t
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION == 2
|
||||
#define PyLong_FromSize_t PyInt_FromSize_t
|
||||
#define PyLong_AsSize_t (size_t)PyInt_AsSsize_t
|
||||
#define PyLong_AsLong PyInt_AsLong
|
||||
#undef PyLong_Check
|
||||
#define PyLong_Check PyInt_Check
|
||||
#define PyLong_FromLong PyInt_FromLong
|
||||
#define PyInteger_Type PyInt_Type
|
||||
#define PyInt_AsSize_t (size_t)PyInt_AsLong
|
||||
#define PyInt_FromLongLong PyInt_FromLong
|
||||
#define PyBytes_AS_STRING PyString_AS_STRING
|
||||
#define PyBytes_AsString PyString_AsString
|
||||
#define PyBytes_AsStringAndSize PyString_AsStringAndSize
|
||||
@ -58,17 +61,16 @@
|
||||
#define to_path(x) to_bytes(x)
|
||||
#define to_encoding(x) to_bytes(x)
|
||||
#else
|
||||
#define PyInteger_Type PyLong_Type
|
||||
#define PyInt_Check PyLong_Check
|
||||
#define PyInt_FromSize_t PyLong_FromSize_t
|
||||
#define PyInt_FromLong PyLong_FromLong
|
||||
#define PyInt_FromLongLong PyLong_FromLongLong
|
||||
#define PyInt_AsLong PyLong_AsLong
|
||||
#define PyInt_AsSize_t PyLong_AsSize_t
|
||||
|
||||
#define to_path(x) to_unicode(x, Py_FileSystemDefaultEncoding, "strict")
|
||||
#define to_encoding(x) PyUnicode_DecodeASCII(x, strlen(x), "strict")
|
||||
#endif
|
||||
|
||||
#ifdef PYPY_VERSION
|
||||
#define PyLong_AsSize_t (size_t)PyLong_AsUnsignedLong
|
||||
#endif
|
||||
|
||||
#ifndef Py_hash_t
|
||||
#define Py_hash_t long
|
||||
#define PyString_FromFormat(s, ...) PyUnicode_FromFormat(s, __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
@ -119,6 +121,8 @@ const char *py_str_borrow_c_str(PyObject **tvaue, PyObject *value, const char *e
|
||||
PyObject * get_pylist_from_git_strarray(git_strarray *strarray);
|
||||
int get_strarraygit_from_pylist(git_strarray *array, PyObject *pylist);
|
||||
|
||||
int py_object_to_otype(PyObject *py_type);
|
||||
|
||||
#define py_path_to_c_str(py_path) \
|
||||
py_str_to_c_str(py_path, Py_FileSystemDefaultEncoding)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
@ -98,13 +98,13 @@ PyDoc_STRVAR(Walker_sort__doc__,
|
||||
PyObject *
|
||||
Walker_sort(Walker *self, PyObject *py_sort_mode)
|
||||
{
|
||||
int sort_mode;
|
||||
long sort_mode;
|
||||
|
||||
sort_mode = (int)PyLong_AsLong(py_sort_mode);
|
||||
sort_mode = PyInt_AsLong(py_sort_mode);
|
||||
if (sort_mode == -1 && PyErr_Occurred())
|
||||
return NULL;
|
||||
|
||||
git_revwalk_sorting(self->walk, sort_mode);
|
||||
git_revwalk_sorting(self->walk, (unsigned int)sort_mode);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2010-2014 The pygit2 contributors
|
||||
* Copyright 2010-2017 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,
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
|
BIN
test/data/binaryfilerepo.tar
Normal file
BIN
test/data/binaryfilerepo.tar
Normal file
Binary file not shown.
BIN
test/data/submodulerepo.tar
Normal file
BIN
test/data/submodulerepo.tar
Normal file
Binary file not shown.
74
test/test_archive.py
Normal file
74
test/test_archive.py
Normal file
@ -0,0 +1,74 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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.
|
||||
|
||||
"""Tests for Blame objects."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import pygit2
|
||||
from pygit2 import Index, Oid, Tree, Object
|
||||
import tarfile
|
||||
import os
|
||||
from . import utils
|
||||
from time import time
|
||||
|
||||
TREE_HASH = 'fd937514cb799514d4b81bb24c5fcfeb6472b245'
|
||||
COMMIT_HASH = '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98'
|
||||
|
||||
class ArchiveTest(utils.RepoTestCase):
|
||||
|
||||
def check_writing(self, treeish, timestamp=None):
|
||||
archive = tarfile.open('foo.tar', mode='w')
|
||||
self.repo.write_archive(treeish, archive)
|
||||
|
||||
index = Index()
|
||||
if isinstance(treeish, Object):
|
||||
index.read_tree(treeish.peel(Tree))
|
||||
else:
|
||||
index.read_tree(self.repo[treeish].peel(Tree))
|
||||
|
||||
self.assertEqual(len(index), len(archive.getmembers()))
|
||||
|
||||
if timestamp:
|
||||
fileinfo = archive.getmembers()[0]
|
||||
self.assertEqual(timestamp, fileinfo.mtime)
|
||||
|
||||
archive.close()
|
||||
self.assertTrue(os.path.isfile('foo.tar'))
|
||||
os.remove('foo.tar')
|
||||
|
||||
def test_write_tree(self):
|
||||
self.check_writing(TREE_HASH)
|
||||
self.check_writing(Oid(hex=TREE_HASH))
|
||||
self.check_writing(self.repo[TREE_HASH])
|
||||
|
||||
def test_write_commit(self):
|
||||
commit_timestamp = self.repo[COMMIT_HASH].committer.time
|
||||
self.check_writing(COMMIT_HASH, commit_timestamp)
|
||||
self.check_writing(Oid(hex=COMMIT_HASH), commit_timestamp)
|
||||
self.check_writing(self.repo[COMMIT_HASH], commit_timestamp)
|
65
test/test_attributes.py
Normal file
65
test/test_attributes.py
Normal file
@ -0,0 +1,65 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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 __future__ import unicode_literals, print_function
|
||||
|
||||
# Import from the Standard Library
|
||||
import binascii
|
||||
import unittest
|
||||
import tempfile
|
||||
import os
|
||||
from os.path import join, realpath
|
||||
import sys
|
||||
|
||||
# Import from pygit2
|
||||
from pygit2 import GIT_OBJ_ANY, GIT_OBJ_BLOB, GIT_OBJ_COMMIT
|
||||
from pygit2 import init_repository, clone_repository, discover_repository
|
||||
from pygit2 import Oid, Reference, hashfile
|
||||
import pygit2
|
||||
from . import utils
|
||||
|
||||
try:
|
||||
import __pypy__
|
||||
except ImportError:
|
||||
__pypy__ = None
|
||||
|
||||
class RepositorySignatureTest(utils.RepoTestCase):
|
||||
|
||||
def test_no_attr(self):
|
||||
self.assertIsNone(self.repo.get_attr('file', 'foo'))
|
||||
|
||||
with open(join(self.repo.workdir, '.gitattributes'), 'w+') as f:
|
||||
print('*.py text\n', file=f)
|
||||
print('*.jpg -text\n', file=f)
|
||||
print('*.sh eol=lf\n', file=f)
|
||||
|
||||
self.assertIsNone(self.repo.get_attr('file.py', 'foo'))
|
||||
self.assertTrue(self.repo.get_attr('file.py', 'text'))
|
||||
self.assertFalse(self.repo.get_attr('file.jpg', 'text'))
|
||||
self.assertEqual("lf", self.repo.get_attr('file.sh', 'eol'))
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -31,7 +31,7 @@ from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import pygit2
|
||||
from pygit2 import Signature
|
||||
from pygit2 import Signature, Oid
|
||||
from pygit2 import GIT_DIFF_INCLUDE_UNMODIFIED
|
||||
from pygit2 import GIT_DIFF_IGNORE_WHITESPACE, GIT_DIFF_IGNORE_WHITESPACE_EOL
|
||||
from . import utils
|
||||
@ -41,13 +41,13 @@ from datetime import datetime
|
||||
PATH = 'hello.txt'
|
||||
|
||||
HUNKS = [
|
||||
('acecd5ea2924a4b900e7e149496e1f4b57976e51', 1,
|
||||
(Oid(hex='acecd5ea2924a4b900e7e149496e1f4b57976e51'), 1,
|
||||
Signature('J. David Ibañez', 'jdavid@itaapy.com',
|
||||
1297179898, 60, encoding='utf-8'), True),
|
||||
('6aaa262e655dd54252e5813c8e5acd7780ed097d', 2,
|
||||
(Oid(hex='6aaa262e655dd54252e5813c8e5acd7780ed097d'), 2,
|
||||
Signature('J. David Ibañez', 'jdavid@itaapy.com',
|
||||
1297696877, 60, encoding='utf-8'), False),
|
||||
('4ec4389a8068641da2d6578db0419484972284c8', 3,
|
||||
(Oid(hex='4ec4389a8068641da2d6578db0419484972284c8'), 3,
|
||||
Signature('J. David Ibañez', 'jdavid@itaapy.com',
|
||||
1297696908, 60, encoding='utf-8'), False)
|
||||
]
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -30,6 +30,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
from os.path import dirname, join
|
||||
import io
|
||||
import unittest
|
||||
|
||||
import pygit2
|
||||
@ -112,6 +113,19 @@ class BlobTest(utils.RepoTestCase):
|
||||
self.assertTrue(isinstance(blob, pygit2.Blob))
|
||||
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
|
||||
|
||||
def test_create_blob_fromiobase(self):
|
||||
self.assertRaises(TypeError, self.repo.create_blob_fromiobase, 'bad type')
|
||||
|
||||
f = io.BytesIO(BLOB_CONTENT)
|
||||
blob_oid = self.repo.create_blob_fromiobase(f)
|
||||
blob = self.repo[blob_oid]
|
||||
|
||||
self.assertTrue(isinstance(blob, pygit2.Blob))
|
||||
self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
|
||||
|
||||
self.assertEqual(blob_oid, blob.id)
|
||||
self.assertEqual(BLOB_SHA, blob_oid.hex)
|
||||
|
||||
def test_diff_blob(self):
|
||||
blob = self.repo[BLOB_SHA]
|
||||
old_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -39,6 +39,135 @@ I18N_LAST_COMMIT = '5470a671a80ac3789f1a6a8cefbcf43ce7af0563'
|
||||
ORIGIN_MASTER_COMMIT = '784855caf26449a1914d2cf62d12b9374d76ae78'
|
||||
|
||||
|
||||
class BranchesObjectTestCase(utils.RepoTestCase):
|
||||
def test_lookup_branch_local(self):
|
||||
branch = self.repo.branches['master']
|
||||
self.assertEqual(branch.target.hex, LAST_COMMIT)
|
||||
|
||||
branch = self.repo.branches.local['i18n']
|
||||
self.assertEqual(branch.target.hex, I18N_LAST_COMMIT)
|
||||
|
||||
self.assertTrue(self.repo.branches.get('not-exists') is None)
|
||||
|
||||
self.assertRaises(KeyError, lambda: self.repo.branches['not-exists'])
|
||||
|
||||
def test_listall_branches(self):
|
||||
branches = sorted(self.repo.branches)
|
||||
self.assertEqual(branches, ['i18n', 'master'])
|
||||
|
||||
def test_create_branch(self):
|
||||
commit = self.repo[LAST_COMMIT]
|
||||
reference = self.repo.branches.create('version1', commit)
|
||||
self.assertTrue('version1' in self.repo.branches)
|
||||
reference = self.repo.branches['version1']
|
||||
self.assertEqual(reference.target.hex, LAST_COMMIT)
|
||||
|
||||
# try to create existing reference
|
||||
self.assertRaises(ValueError,
|
||||
lambda: self.repo.branches.create('version1', commit))
|
||||
|
||||
# try to create existing reference with force
|
||||
reference = self.repo.branches.create('version1', commit, True)
|
||||
self.assertEqual(reference.target.hex, LAST_COMMIT)
|
||||
|
||||
def test_delete(self):
|
||||
self.repo.branches.delete('i18n')
|
||||
|
||||
self.assertTrue(self.repo.branches.get('i18n') is None)
|
||||
|
||||
def test_cant_delete_master(self):
|
||||
self.assertRaises(pygit2.GitError, lambda: self.repo.branches.delete('master'))
|
||||
|
||||
def test_branch_is_head_returns_true_if_branch_is_head(self):
|
||||
branch = self.repo.branches.get('master')
|
||||
self.assertTrue(branch.is_head())
|
||||
|
||||
def test_branch_is_head_returns_false_if_branch_is_not_head(self):
|
||||
branch = self.repo.branches.get('i18n')
|
||||
self.assertFalse(branch.is_head())
|
||||
|
||||
def test_branch_rename_succeeds(self):
|
||||
new_branch = self.repo.branches['i18n'].rename('new-branch')
|
||||
self.assertEqual(new_branch.target.hex, I18N_LAST_COMMIT)
|
||||
|
||||
new_branch_2 = self.repo.branches.get('new-branch')
|
||||
self.assertEqual(new_branch_2.target.hex, I18N_LAST_COMMIT)
|
||||
|
||||
def test_branch_rename_fails_if_destination_already_exists(self):
|
||||
original_branch = self.repo.branches.get('i18n')
|
||||
self.assertRaises(ValueError, lambda: original_branch.rename('master'))
|
||||
|
||||
def test_branch_rename_not_fails_if_force_is_true(self):
|
||||
original_branch = self.repo.branches.get('master')
|
||||
new_branch = original_branch.rename('i18n', True)
|
||||
self.assertEqual(new_branch.target.hex, LAST_COMMIT)
|
||||
|
||||
def test_branch_rename_fails_with_invalid_names(self):
|
||||
original_branch = self.repo.branches.get('i18n')
|
||||
self.assertRaises(ValueError,
|
||||
lambda: original_branch.rename('abc@{123'))
|
||||
|
||||
def test_branch_name(self):
|
||||
branch = self.repo.branches.get('master')
|
||||
self.assertEqual(branch.branch_name, 'master')
|
||||
self.assertEqual(branch.name, 'refs/heads/master')
|
||||
|
||||
branch = self.repo.branches.get('i18n')
|
||||
self.assertEqual(branch.branch_name, 'i18n')
|
||||
self.assertEqual(branch.name, 'refs/heads/i18n')
|
||||
|
||||
|
||||
class BranchesObjectEmptyRepoTestCase(utils.EmptyRepoTestCase):
|
||||
def setUp(self):
|
||||
super(utils.EmptyRepoTestCase, self).setUp()
|
||||
|
||||
remote = self.repo.remotes[0]
|
||||
remote.fetch()
|
||||
|
||||
def test_lookup_branch_remote(self):
|
||||
branch = self.repo.branches.remote.get('origin/master')
|
||||
self.assertEqual(branch.target.hex, ORIGIN_MASTER_COMMIT)
|
||||
|
||||
self.assertTrue(
|
||||
self.repo.branches.remote.get('origin/not-exists') is None)
|
||||
|
||||
def test_listall_branches(self):
|
||||
branches = sorted(self.repo.branches.remote)
|
||||
self.assertEqual(branches, ['origin/master'])
|
||||
|
||||
def test_branch_remote_name(self):
|
||||
self.repo.remotes[0].fetch()
|
||||
branch = self.repo.branches.remote['origin/master']
|
||||
self.assertEqual(branch.remote_name, 'origin')
|
||||
|
||||
def test_branch_upstream(self):
|
||||
self.repo.remotes[0].fetch()
|
||||
remote_master = self.repo.branches.remote['origin/master']
|
||||
master = self.repo.branches.create('master',
|
||||
self.repo[remote_master.target.hex])
|
||||
|
||||
self.assertTrue(master.upstream is None)
|
||||
master.upstream = remote_master
|
||||
self.assertEqual(master.upstream.branch_name, 'origin/master')
|
||||
|
||||
def set_bad_upstream():
|
||||
master.upstream = 2.5
|
||||
|
||||
self.assertRaises(TypeError, set_bad_upstream)
|
||||
|
||||
master.upstream = None
|
||||
self.assertTrue(master.upstream is None)
|
||||
|
||||
def test_branch_upstream_name(self):
|
||||
self.repo.remotes[0].fetch()
|
||||
remote_master = self.repo.branches.remote['origin/master']
|
||||
master = self.repo.branches.create('master',
|
||||
self.repo[remote_master.target.hex])
|
||||
|
||||
master.upstream = remote_master
|
||||
self.assertEqual(master.upstream_name, 'refs/remotes/origin/master')
|
||||
|
||||
|
||||
class BranchesTestCase(utils.RepoTestCase):
|
||||
def test_lookup_branch_local(self):
|
||||
branch = self.repo.lookup_branch('master')
|
||||
@ -88,6 +217,14 @@ class BranchesTestCase(utils.RepoTestCase):
|
||||
branch = self.repo.lookup_branch('i18n')
|
||||
self.assertFalse(branch.is_head())
|
||||
|
||||
def test_branch_is_checked_out_returns_true_if_branch_is_checked_out(self):
|
||||
branch = self.repo.lookup_branch('master')
|
||||
self.assertTrue(branch.is_checked_out())
|
||||
|
||||
def test_branch_is_checked_out_returns_false_if_branch_is_not_checked_out(self):
|
||||
branch = self.repo.lookup_branch('i18n')
|
||||
self.assertFalse(branch.is_checked_out())
|
||||
|
||||
def test_branch_rename_succeeds(self):
|
||||
original_branch = self.repo.lookup_branch('i18n')
|
||||
new_branch = original_branch.rename('new-branch')
|
||||
@ -159,6 +296,7 @@ class BranchesEmptyRepoTestCase(utils.EmptyRepoTestCase):
|
||||
|
||||
def set_bad_upstream():
|
||||
master.upstream = 2.5
|
||||
|
||||
self.assertRaises(TypeError, set_bad_upstream)
|
||||
|
||||
master.upstream = None
|
||||
|
71
test/test_cherrypick.py
Normal file
71
test/test_cherrypick.py
Normal file
@ -0,0 +1,71 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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.
|
||||
|
||||
"""Tests for merging and information about it."""
|
||||
|
||||
# Import from the future
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import unittest
|
||||
import os
|
||||
|
||||
from pygit2 import GIT_MERGE_ANALYSIS_NONE, GIT_MERGE_ANALYSIS_NORMAL, GIT_MERGE_ANALYSIS_UP_TO_DATE
|
||||
from pygit2 import GIT_MERGE_ANALYSIS_FASTFORWARD, GIT_MERGE_ANALYSIS_UNBORN
|
||||
import pygit2
|
||||
|
||||
from . import utils
|
||||
|
||||
class CherrypickTestBasic(utils.RepoTestCaseForMerging):
|
||||
|
||||
def test_cherrypick_none(self):
|
||||
self.assertRaises(TypeError, self.repo.cherrypick, None)
|
||||
|
||||
def test_cherrypick_invalid_hex(self):
|
||||
branch_head_hex = '12345678'
|
||||
self.assertRaises(KeyError, self.repo.cherrypick, branch_head_hex)
|
||||
|
||||
def test_cherrypick_already_something_in_index(self):
|
||||
branch_head_hex = '03490f16b15a09913edb3a067a3dc67fbb8d41f1'
|
||||
branch_oid = self.repo.get(branch_head_hex).id
|
||||
with open(os.path.join(self.repo.workdir, 'inindex.txt'), 'w') as f:
|
||||
f.write('new content')
|
||||
self.repo.index.add('inindex.txt')
|
||||
self.assertRaises(pygit2.GitError, self.repo.cherrypick, branch_oid)
|
||||
|
||||
class CherrypickTestWithConflicts(utils.RepoTestCaseForMerging):
|
||||
|
||||
def test_cherrypick_remove_conflicts(self):
|
||||
other_branch_tip = '1b2bae55ac95a4be3f8983b86cd579226d0eb247'
|
||||
self.repo.cherrypick(other_branch_tip)
|
||||
idx = self.repo.index
|
||||
conflicts = idx.conflicts
|
||||
self.assertTrue(conflicts is not None)
|
||||
conflicts['.gitignore']
|
||||
del idx.conflicts['.gitignore']
|
||||
self.assertRaises(KeyError, conflicts.__getitem__, '.gitignore')
|
||||
self.assertTrue(idx.conflicts is None)
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -30,22 +30,36 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import sys
|
||||
|
||||
from pygit2 import GIT_OBJ_COMMIT, Signature, Oid
|
||||
from . import utils
|
||||
|
||||
# pypy raises TypeError on writing to read-only, so we need to check
|
||||
# and change the test accordingly
|
||||
# pypy (in python2 mode) raises TypeError on writing to read-only, so
|
||||
# we need to check and change the test accordingly
|
||||
try:
|
||||
import __pypy__
|
||||
import __pypy__, sys
|
||||
pypy2 = sys.version_info[0] < 3
|
||||
except ImportError:
|
||||
__pypy__ = None
|
||||
pypy2 = False
|
||||
|
||||
COMMIT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10'
|
||||
|
||||
|
||||
class CommitTest(utils.BareRepoTestCase):
|
||||
|
||||
@unittest.skipIf(__pypy__ is not None, "skip refcounts checks in pypy")
|
||||
def test_commit_refcount(self):
|
||||
commit = self.repo[COMMIT_SHA]
|
||||
start = sys.getrefcount(commit)
|
||||
tree = commit.tree
|
||||
del tree
|
||||
end = sys.getrefcount(commit)
|
||||
self.assertEqual(start, end)
|
||||
|
||||
|
||||
def test_read_commit(self):
|
||||
commit = self.repo[COMMIT_SHA]
|
||||
self.assertEqual(COMMIT_SHA, str(commit.id))
|
||||
@ -138,7 +152,7 @@ class CommitTest(utils.BareRepoTestCase):
|
||||
|
||||
commit = self.repo[COMMIT_SHA]
|
||||
|
||||
error_type = AttributeError if not __pypy__ else TypeError
|
||||
error_type = AttributeError if not pypy2 else TypeError
|
||||
self.assertRaises(error_type, setattr, commit, 'message', message)
|
||||
self.assertRaises(error_type, setattr, commit, 'committer', committer)
|
||||
self.assertRaises(error_type, setattr, commit, 'author', author)
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -97,7 +97,7 @@ class ConfigTest(utils.RepoTestCase):
|
||||
|
||||
self.assertRaises(TypeError, lambda: config[()])
|
||||
self.assertRaises(TypeError, lambda: config[-4])
|
||||
self.assertRaisesWithArg(ValueError, "Invalid config item name 'abc'",
|
||||
self.assertRaisesWithArg(ValueError, "invalid config item name 'abc'",
|
||||
lambda: config['abc'])
|
||||
self.assertRaisesWithArg(KeyError, 'abc.def',
|
||||
lambda: config['abc.def'])
|
||||
@ -153,7 +153,7 @@ class ConfigTest(utils.RepoTestCase):
|
||||
new_file.write("[this]\n\tthat = foobar\n\tthat = foobeer\n")
|
||||
new_file.close()
|
||||
|
||||
config.add_file(CONFIG_FILENAME, 5)
|
||||
config.add_file(CONFIG_FILENAME, 6)
|
||||
self.assertTrue('this.that' in config)
|
||||
l = config.get_multivar('this.that', 'foo.*')
|
||||
self.assertEqual(2, len(list(l)))
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2014 The pygit2 contributors
|
||||
# Copyright 2010-2017 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,
|
||||
@ -31,6 +31,7 @@
|
||||
import unittest
|
||||
import pygit2
|
||||
from pygit2 import GIT_CREDTYPE_USERPASS_PLAINTEXT
|
||||
from pygit2 import UserPass, Keypair, KeypairFromAgent
|
||||
from pygit2 import UserPass, Keypair
|
||||
from . import utils
|
||||
|
||||
@ -60,34 +61,46 @@ class CredentialCreateTest(utils.NoRepoTestCase):
|
||||
cred = Keypair(username, pubkey, privkey, passphrase)
|
||||
self.assertEqual((username, pubkey, privkey, passphrase), cred.credential_tuple)
|
||||
|
||||
def test_ssh_agent(self):
|
||||
username = "git"
|
||||
|
||||
cred = KeypairFromAgent(username)
|
||||
self.assertEqual((username, None, None, None), cred.credential_tuple)
|
||||
|
||||
|
||||
class CredentialCallback(utils.RepoTestCase):
|
||||
def test_callback(self):
|
||||
def credentials_cb(url, username, allowed):
|
||||
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
|
||||
raise Exception("I don't know the password")
|
||||
class MyCallbacks(pygit2.RemoteCallbacks):
|
||||
@staticmethod
|
||||
def credentials(url, username, allowed):
|
||||
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
|
||||
raise Exception("I don't know the password")
|
||||
|
||||
remote = self.repo.create_remote("github", "https://github.com/github/github")
|
||||
remote.credentials = credentials_cb
|
||||
url = "https://github.com/github/github"
|
||||
remote = self.repo.create_remote("github", url)
|
||||
|
||||
self.assertRaises(Exception, remote.fetch)
|
||||
self.assertRaises(Exception, lambda: remote.fetch(callbacks=MyCallbacks()))
|
||||
|
||||
def test_bad_cred_type(self):
|
||||
def credentials_cb(url, username, allowed):
|
||||
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
|
||||
return Keypair("git", "foo.pub", "foo", "sekkrit")
|
||||
class MyCallbacks(pygit2.RemoteCallbacks):
|
||||
@staticmethod
|
||||
def credentials(url, username, allowed):
|
||||
self.assertTrue(allowed & GIT_CREDTYPE_USERPASS_PLAINTEXT)
|
||||
return Keypair("git", "foo.pub", "foo", "sekkrit")
|
||||
|
||||
remote = self.repo.create_remote("github", "https://github.com/github/github")
|
||||
remote.credentials = credentials_cb
|
||||
|
||||
self.assertRaises(TypeError, remote.fetch)
|
||||
url = "https://github.com/github/github"
|
||||
remote = self.repo.create_remote("github", url)
|
||||
self.assertRaises(TypeError, lambda: remote.fetch(callbacks=MyCallbacks()))
|
||||
|
||||
class CallableCredentialTest(utils.RepoTestCase):
|
||||
|
||||
def test_user_pass(self):
|
||||
remote = self.repo.create_remote("bb", "https://bitbucket.org/libgit2/testgitrepository.git")
|
||||
remote.credentials = UserPass("libgit2", "libgit2")
|
||||
credentials = UserPass("libgit2", "libgit2")
|
||||
callbacks = pygit2.RemoteCallbacks(credentials=credentials)
|
||||
|
||||
remote.fetch()
|
||||
url = "https://bitbucket.org/libgit2/testgitrepository.git"
|
||||
remote = self.repo.create_remote("bb", url)
|
||||
remote.fetch(callbacks=callbacks)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
106
test/test_describe.py
Normal file
106
test/test_describe.py
Normal file
@ -0,0 +1,106 @@
|
||||
# -*- coding: UTF-8 -*-
|
||||
#
|
||||
# Copyright 2010-2017 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.
|
||||
|
||||
"""Tests for describing commits."""
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
|
||||
from pygit2 import GIT_DESCRIBE_DEFAULT, GIT_DESCRIBE_TAGS, GIT_DESCRIBE_ALL
|
||||
import pygit2
|
||||
from . import utils
|
||||
|
||||
|
||||
def add_tag(repo, name, target):
|
||||
message = 'Example tag.\n'
|
||||
tagger = pygit2.Signature('John Doe', 'jdoe@example.com', 12347, 0)
|
||||
|
||||
sha = repo.create_tag(name, target, pygit2.GIT_OBJ_COMMIT, tagger, message)
|
||||
return sha
|
||||
|
||||
|
||||
class DescribeTest(utils.RepoTestCase):
|
||||
|
||||
def test_describe(self):
|
||||
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
|
||||
self.assertEqual('thetag-2-g2be5719', self.repo.describe())
|
||||
|
||||
def test_describe_without_ref(self):
|
||||
self.assertRaises(pygit2.GitError, self.repo.describe)
|
||||
|
||||
def test_describe_default_oid(self):
|
||||
self.assertEqual('2be5719', self.repo.describe(show_commit_oid_as_fallback=True))
|
||||
|
||||
def test_describe_strategies(self):
|
||||
self.assertEqual('heads/master', self.repo.describe(describe_strategy=GIT_DESCRIBE_ALL))
|
||||
|
||||
self.repo.create_reference('refs/tags/thetag', '4ec4389a8068641da2d6578db0419484972284c8')
|
||||
self.assertRaises(KeyError, self.repo.describe)
|
||||
self.assertEqual('thetag-2-g2be5719', self.repo.describe(describe_strategy=GIT_DESCRIBE_TAGS))
|
||||
|
||||
def test_describe_pattern(self):
|
||||
add_tag(self.repo, 'private/tag1', '5ebeeebb320790caf276b9fc8b24546d63316533')
|
||||
add_tag(self.repo, 'public/tag2', '4ec4389a8068641da2d6578db0419484972284c8')
|
||||
|
||||
self.assertEqual('public/tag2-2-g2be5719', self.repo.describe(pattern='public/*'))
|
||||
|
||||
def test_describe_committish(self):
|
||||
add_tag(self.repo, 'thetag', 'acecd5ea2924a4b900e7e149496e1f4b57976e51')
|
||||
self.assertEqual('thetag-4-g2be5719', self.repo.describe(committish='HEAD'))
|
||||
self.assertEqual('thetag-1-g5ebeeeb', self.repo.describe(committish='HEAD^'))
|
||||
|
||||
self.assertEqual('thetag-4-g2be5719', self.repo.describe(committish=self.repo.head))
|
||||
|
||||
self.assertEqual('thetag-1-g6aaa262', self.repo.describe(committish='6aaa262e655dd54252e5813c8e5acd7780ed097d'))
|
||||
self.assertEqual('thetag-1-g6aaa262', self.repo.describe(committish='6aaa262'))
|
||||
|
||||
def test_describe_follows_first_branch_only(self):
|
||||
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
|
||||
self.assertRaises(KeyError, self.repo.describe, only_follow_first_parent=True)
|
||||
|
||||
def test_describe_abbreviated_size(self):
|
||||
add_tag(self.repo, 'thetag', '4ec4389a8068641da2d6578db0419484972284c8')
|
||||
self.assertEqual('thetag-2-g2be5719152d4f82c', self.repo.describe(abbreviated_size=16))
|
||||
self.assertEqual('thetag', self.repo.describe(abbreviated_size=0))
|
||||
|
||||
def test_describe_long_format(self):
|
||||
add_tag(self.repo, 'thetag', '2be5719152d4f82c7302b1c0932d8e5f0a4a0e98')
|
||||
self.assertEqual('thetag-0-g2be5719', self.repo.describe(always_use_long_format=True))
|
||||
|
||||
|
||||
class DescribeDirtyWorkdirTest(utils.DirtyRepoTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(utils.DirtyRepoTestCase, self).setUp()
|
||||
add_tag(self.repo, 'thetag', 'a763aa560953e7cfb87ccbc2f536d665aa4dff22')
|
||||
|
||||
def test_describe(self):
|
||||
self.assertEqual('thetag', self.repo.describe())
|
||||
|
||||
def test_describe_with_dirty_suffix(self):
|
||||
self.assertEqual('thetag-dirty', self.repo.describe(dirty_suffix='-dirty'))
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user