New upstream version 2.1.9
TANIGUCHI Takaki
5 years ago
0 | 0 | Metadata-Version: 1.2 |
1 | 1 | Name: GitPython |
2 | Version: 2.1.8 | |
2 | Version: 2.1.9 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: https://github.com/gitpython-developers/GitPython |
5 | 5 | Author: Sebastian Thiel, Michael Trier |
18 | 18 | Classifier: Operating System :: MacOS :: MacOS X |
19 | 19 | Classifier: Programming Language :: Python |
20 | 20 | Classifier: Programming Language :: Python :: 2 |
21 | Classifier: Programming Language :: Python :: 2.6 | |
22 | 21 | Classifier: Programming Language :: Python :: 2.7 |
23 | 22 | Classifier: Programming Language :: Python :: 3 |
24 | Classifier: Programming Language :: Python :: 3.3 | |
25 | 23 | Classifier: Programming Language :: Python :: 3.4 |
26 | 24 | Classifier: Programming Language :: Python :: 3.5 |
27 | 25 | Classifier: Programming Language :: Python :: 3.6 |
28 | 26 | Requires: gitdb2 (>=2.0.0) |
29 | Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* | |
27 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* |
28 | 28 | git/db.py |
29 | 29 | git/diff.py |
30 | 30 | git/exc.py |
31 | git/odict.py | |
32 | 31 | git/remote.py |
33 | 32 | git/util.py |
34 | 33 | git/index/__init__.py |
0 | 0 | Metadata-Version: 1.2 |
1 | 1 | Name: GitPython |
2 | Version: 2.1.8 | |
2 | Version: 2.1.9 | |
3 | 3 | Summary: Python Git Library |
4 | 4 | Home-page: https://github.com/gitpython-developers/GitPython |
5 | 5 | Author: Sebastian Thiel, Michael Trier |
18 | 18 | Classifier: Operating System :: MacOS :: MacOS X |
19 | 19 | Classifier: Programming Language :: Python |
20 | 20 | Classifier: Programming Language :: Python :: 2 |
21 | Classifier: Programming Language :: Python :: 2.6 | |
22 | 21 | Classifier: Programming Language :: Python :: 2.7 |
23 | 22 | Classifier: Programming Language :: Python :: 3 |
24 | Classifier: Programming Language :: Python :: 3.3 | |
25 | 23 | Classifier: Programming Language :: Python :: 3.4 |
26 | 24 | Classifier: Programming Language :: Python :: 3.5 |
27 | 25 | Classifier: Programming Language :: Python :: 3.6 |
28 | 26 | Requires: gitdb2 (>=2.0.0) |
29 | Requires-Python: >=2.6, !=3.0.*, !=3.1.*, !=3.2.* | |
27 | Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* |
18 | 18 | the `GIT_PYTHON_GIT_EXECUTABLE=<path/to/git>` environment variable. |
19 | 19 | |
20 | 20 | * Git (1.7.x or newer) |
21 | * Python 2.7 to 3.6, while python 2.6 is supported on a *best-effort basis*. | |
21 | * Python 2.7 to 3.6. | |
22 | 22 | |
23 | 23 | The list of dependencies are listed in `./requirements.txt` and `./test-requirements.txt`. |
24 | 24 | The installer takes care of installing them for you. |
66 | 66 | For *Windows*, we do regularly test it on [Appveyor CI](https://www.appveyor.com/) |
67 | 67 | but not all test-cases pass - you may help improve them by exploring |
68 | 68 | [Issue #525](https://github.com/gitpython-developers/GitPython/issues/525). |
69 | ||
70 | #### Python 2.6 | |
71 | ||
72 | Python 2.6 is supported on best-effort basis; which means that it is likely to deteriorate over time. | |
73 | 69 | |
74 | 70 | ### RUNNING TESTS |
75 | 71 | |
131 | 127 | this project: |
132 | 128 | |
133 | 129 | ``` |
134 | curl https://pypi.python.org/packages/7e/13/2a556eb97dcf498c915e5e04bb82bf74e07bb8b7337ca2be49bfd9fb6313/GitPython-2.1.5-py2.py3-none-any.whl\#md5\=d3ecb26cb22753f4414f75f721f6f626z > gitpython.whl | |
135 | curl https://pypi.python.org/packages/7e/13/2a556eb97dcf498c915e5e04bb82bf74e07bb8b7337ca2be49bfd9fb6313/GitPython-2.1.5-py2.py3-none-any.whl.asc > gitpython-signature.asc | |
130 | curl https://pypi.python.org/packages/5b/38/0433c06feebbfbb51d644129dbe334031c33d55af0524326266f847ae907/GitPython-2.1.8-py2.py3-none-any.whl#md5=6b73ae86ee2dbab6da8652b2d875013a > gitpython.whl | |
131 | curl https://pypi.python.org/packages/5b/38/0433c06feebbfbb51d644129dbe334031c33d55af0524326266f847ae907/GitPython-2.1.8-py2.py3-none-any.whl.asc > gitpython-signature.asc | |
136 | 132 | gpg --verify gitpython-signature.asc gitpython.whl |
137 | 133 | ``` |
138 | 134 | |
139 | 135 | which outputs |
140 | 136 | |
141 | 137 | ``` |
142 | gpg: Signature made Sat Jun 10 20:22:49 2017 CEST using RSA key ID 3B07188F | |
143 | gpg: Good signature from "Sebastian Thiel (In Rust I trust!) <byronimo@gmail.com>" [unknown] | |
144 | gpg: WARNING: This key is not certified with a trusted signature! | |
145 | gpg: There is no indication that the signature belongs to the owner. | |
146 | Primary key fingerprint: 4477 ADC5 977D 7C60 D2A7 E378 9FEE 1C6A 3B07 188F | |
138 | gpg: Signature made Mon Dec 11 17:34:17 2017 CET | |
139 | gpg: using RSA key C3BC52BD76E2C23BAC6EC06A665F99FA9D99966C | |
140 | gpg: issuer "byronimo@gmail.com" | |
141 | gpg: Good signature from "Sebastian Thiel (I do trust in Rust!) <byronimo@gmail.com>" [ultimate] | |
147 | 142 | ``` |
148 | 143 | |
149 | 144 | You can verify that the keyid indeed matches the release-signature key provided in this |
163 | 158 | |
164 | 159 | ``` |
165 | 160 | gpg --import ./release-verification-key.asc |
166 | gpg --edit-key 9FEE1C6A3B07188F | |
161 | gpg --edit-key 88710E60 | |
162 | ||
167 | 163 | > sign |
168 | 164 | > save |
169 | ``` | |
170 | ||
171 | Afterwards verifying the tarball will yield the following: | |
172 | ``` | |
173 | $ gpg --verify gitpython-signature.asc gitpython.whl | |
174 | gpg: Signature made Sat Jun 10 20:22:49 2017 CEST using RSA key ID 3B07188F | |
175 | gpg: Good signature from "Sebastian Thiel (In Rust I trust!) <byronimo@gmail.com>" [ultimate] | |
176 | 165 | ``` |
177 | 166 | |
178 | 167 | ### LICENSE |
1 | 1 | Changelog |
2 | 2 | ========= |
3 | 3 | |
4 | 2.1.9 - Dropping support for Python 2.6 | |
5 | ======================================= | |
6 | ||
7 | see the following for (most) details: | |
8 | https://github.com/gitpython-developers/gitpython/milestone/24?closed=1 | |
9 | ||
10 | or run have a look at the difference between tags v2.1.8 and v2.1.9: | |
11 | https://github.com/gitpython-developers/GitPython/compare/2.1.8...2.1.9 | |
12 | ||
13 | ||
4 | 14 | 2.1.8 - bugfixes |
5 | 15 | ==================================== |
6 | 16 | |
7 | See the following for (most) details: | |
8 | https://github.com/gitpython-developers/GitPython/milestone/23?closed=1 | |
17 | see the following for (most) details: | |
18 | https://github.com/gitpython-developers/gitpython/milestone/23?closed=1 | |
9 | 19 | |
10 | 20 | or run have a look at the difference between tags v2.1.7 and v2.1.8: |
11 | 21 | https://github.com/gitpython-developers/GitPython/compare/2.1.7...2.1.8 |
160 | 170 | with large repositories. |
161 | 171 | * CRITICAL: fixed incorrect `Commit` object serialization when authored or commit date had timezones which were not |
162 | 172 | divisiblej by 3600 seconds. This would happen if the timezone was something like `+0530` for instance. |
163 | * A list of all additional fixes can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.2+-+Fixes%22+is%3Aclosed>`_ | |
173 | * A list of all additional fixes can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.2+-+Fixes%22+is%3Aclosed>`_ | |
164 | 174 | * CRITICAL: `Tree.cache` was removed without replacement. It is technically impossible to change individual trees and expect their serialization results to be consistent with what *git* expects. Instead, use the `IndexFile` facilities to adjust the content of the staging area, and write it out to the respective tree objects using `IndexFile.write_tree()` instead. |
165 | 175 | |
166 | 176 | 1.0.1 - Fixes |
167 | 177 | ============= |
168 | 178 | |
169 | * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.1+-+Fixes%22+is%3Aclosed>`_ | |
179 | * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v1.0.1+-+Fixes%22+is%3Aclosed>`_ | |
170 | 180 | |
171 | 181 | 1.0.0 - Notes |
172 | 182 | ============= |
190 | 200 | |
191 | 201 | - Those who support **GUI on windows** will now have to set `git.Git.USE_SHELL = True` to get the previous behaviour. |
192 | 202 | |
193 | * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.7+-+Fixes%22+is%3Aclosed>`_ | |
203 | * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.7+-+Fixes%22+is%3Aclosed>`_ | |
194 | 204 | |
195 | 205 | |
196 | 206 | 0.3.6 - Features |
206 | 216 | * Repo.working_tree_dir now returns None if it is bare. Previously it raised AssertionError. |
207 | 217 | * IndexFile.add() previously raised AssertionError when paths where used with bare repository, now it raises InvalidGitRepositoryError |
208 | 218 | |
209 | * Added `Repo.merge_base()` implementation. See the `respective issue on github <https://github.com/gitpython-developers/GitPython/issues/169>`_ | |
219 | * Added `Repo.merge_base()` implementation. See the `respective issue on GitHub <https://github.com/gitpython-developers/GitPython/issues/169>`_ | |
210 | 220 | * `[include]` sections in git configuration files are now respected |
211 | 221 | * Added `GitConfigParser.rename_section()` |
212 | 222 | * Added `Submodule.rename()` |
213 | * A list of all issues can be found `on github <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+>`_ | |
223 | * A list of all issues can be found `on GitHub <https://github.com/gitpython-developers/GitPython/issues?q=milestone%3A%22v0.3.6+-+Features%22+>`_ | |
214 | 224 | |
215 | 225 | 0.3.5 - Bugfixes |
216 | 226 | ================ |
13 | 13 | ============ |
14 | 14 | |
15 | 15 | * `Python`_ 2.7 or newer |
16 | Since GitPython 2.0.0. Please note that python 2.6 is still reasonably well supported, but might | |
17 | deteriorate over time. Support is provided on a best-effort basis only. | |
18 | 16 | * `Git`_ 1.7.0 or newer |
19 | 17 | It should also work with older versions, but it may be that some operations |
20 | 18 | involving remotes will not work as expected. |
74 | 72 | Another way assure proper cleanup of resources is to factor out GitPython into a |
75 | 73 | separate process which can be dropped periodically. |
76 | 74 | |
77 | Best-effort for Python 2.6 and Windows support | |
78 | ---------------------------------------------- | |
79 | ||
80 | This means that support for these platforms is likely to worsen over time | |
81 | as they are kept alive solely by their users, or not. | |
82 | ||
83 | 75 | Getting Started |
84 | 76 | =============== |
85 | 77 | |
123 | 115 | |
124 | 116 | Issue Tracker |
125 | 117 | ============= |
126 | The issue tracker is hosted by github: | |
118 | The issue tracker is hosted by GitHub: | |
127 | 119 | |
128 | 120 | https://github.com/gitpython-developers/GitPython/issues |
129 | 121 |
1 | 1 | ####### |
2 | 2 | Roadmap |
3 | 3 | ####### |
4 | The full list of milestones including associated tasks can be found on github: | |
4 | The full list of milestones including associated tasks can be found on GitHub: | |
5 | 5 | https://github.com/gitpython-developers/GitPython/issues |
6 | 6 | |
7 | 7 | Select the respective milestone to filter the list of issues accordingly. |
11 | 11 | import os.path as osp |
12 | 12 | |
13 | 13 | |
14 | __version__ = '2.1.8' | |
14 | __version__ = '2.1.9' | |
15 | 15 | |
16 | 16 | |
17 | 17 | #{ Initialization |
18 | 18 | def _init_externals(): |
19 | 19 | """Initialize external projects by putting them into the path""" |
20 | if __version__ == '2.1.8': | |
20 | if __version__ == '2.1.9': | |
21 | 21 | sys.path.insert(0, osp.join(osp.dirname(__file__), 'ext', 'gitdb')) |
22 | 22 | |
23 | 23 | try: |
16 | 16 | import subprocess |
17 | 17 | import sys |
18 | 18 | import threading |
19 | from collections import OrderedDict | |
19 | 20 | from textwrap import dedent |
20 | 21 | |
21 | 22 | from git.compat import ( |
30 | 31 | is_win, |
31 | 32 | ) |
32 | 33 | from git.exc import CommandError |
33 | from git.odict import OrderedDict | |
34 | 34 | from git.util import is_cygwin_git, cygpath, expand_path |
35 | 35 | |
36 | 36 | from .exc import ( |
43 | 43 | ) |
44 | 44 | |
45 | 45 | |
46 | execute_kwargs = set(('istream', 'with_extended_output', | |
47 | 'with_exceptions', 'as_process', 'stdout_as_string', | |
48 | 'output_stream', 'with_stdout', 'kill_after_timeout', | |
49 | 'universal_newlines', 'shell', 'env')) | |
46 | execute_kwargs = {'istream', 'with_extended_output', 'with_exceptions', | |
47 | 'as_process', 'stdout_as_string', 'output_stream', | |
48 | 'with_stdout', 'kill_after_timeout', 'universal_newlines', | |
49 | 'shell', 'env'} | |
50 | 50 | |
51 | 51 | log = logging.getLogger(__name__) |
52 | 52 | log.addHandler(logging.NullHandler()) |
124 | 124 | |
125 | 125 | |
126 | 126 | def slots_to_dict(self, exclude=()): |
127 | return dict((s, getattr(self, s)) for s in self.__slots__ if s not in exclude) | |
127 | return {s: getattr(self, s) for s in self.__slots__ if s not in exclude} | |
128 | 128 | |
129 | 129 | |
130 | 130 | def dict_to_slots_and__excluded_are_none(self, d, excluded=()): |
142 | 142 | ## CREATE_NEW_PROCESS_GROUP is needed to allow killing it afterwards, |
143 | 143 | # see https://docs.python.org/3/library/subprocess.html#subprocess.Popen.send_signal |
144 | 144 | PROC_CREATIONFLAGS = (CREATE_NO_WINDOW | subprocess.CREATE_NEW_PROCESS_GROUP |
145 | if is_win and sys.version_info >= (2, 7) | |
146 | else 0) | |
145 | if is_win else 0) | |
147 | 146 | |
148 | 147 | |
149 | 148 | class Git(LazyMixin): |
485 | 484 | |
486 | 485 | def readlines(self, size=-1): |
487 | 486 | if self._nbr == self._size: |
488 | return list() | |
487 | return [] | |
489 | 488 | |
490 | 489 | # leave all additional logic to our readline method, we just check the size |
491 | out = list() | |
490 | out = [] | |
492 | 491 | nbr = 0 |
493 | 492 | while True: |
494 | 493 | line = self.readline() |
894 | 893 | |
895 | 894 | def transform_kwargs(self, split_single_char_options=True, **kwargs): |
896 | 895 | """Transforms Python style kwargs into git command line options.""" |
897 | args = list() | |
896 | args = [] | |
898 | 897 | kwargs = OrderedDict(sorted(kwargs.items(), key=lambda x: x[0])) |
899 | 898 | for k, v in kwargs.items(): |
900 | 899 | if isinstance(v, (list, tuple)): |
913 | 912 | return [arg_list.encode(defenc)] |
914 | 913 | return [str(arg_list)] |
915 | 914 | |
916 | outlist = list() | |
915 | outlist = [] | |
917 | 916 | for arg in arg_list: |
918 | 917 | if isinstance(arg_list, (list, tuple)): |
919 | 918 | outlist.extend(cls.__unpack_args(arg)) |
972 | 971 | :return: Same as ``execute``""" |
973 | 972 | # Handle optional arguments prior to calling transform_kwargs |
974 | 973 | # otherwise these'll end up in args, which is bad. |
975 | exec_kwargs = dict((k, v) for k, v in kwargs.items() if k in execute_kwargs) | |
976 | opts_kwargs = dict((k, v) for k, v in kwargs.items() if k not in execute_kwargs) | |
974 | exec_kwargs = {k: v for k, v in kwargs.items() if k in execute_kwargs} | |
975 | opts_kwargs = {k: v for k, v in kwargs.items() if k not in execute_kwargs} | |
977 | 976 | |
978 | 977 | insert_after_this_arg = opts_kwargs.pop('insert_kwargs_after', None) |
979 | 978 |
11 | 11 | import logging |
12 | 12 | import os |
13 | 13 | import re |
14 | from collections import OrderedDict | |
14 | 15 | |
15 | 16 | from git.compat import ( |
16 | 17 | string_types, |
20 | 21 | with_metaclass, |
21 | 22 | PY3 |
22 | 23 | ) |
23 | from git.odict import OrderedDict | |
24 | 24 | from git.util import LockFile |
25 | 25 | |
26 | 26 | import os.path as osp |
60 | 60 | :note: |
61 | 61 | Subclasses require a repo member as it is the case for Object instances, for practical |
62 | 62 | reasons we do not derive from Object.""" |
63 | __slots__ = tuple() | |
63 | __slots__ = () | |
64 | 64 | |
65 | 65 | # standin indicating you want to diff against the index |
66 | 66 | class Index(object): |
105 | 105 | :note: |
106 | 106 | On a bare repository, 'other' needs to be provided as Index or as |
107 | 107 | as Tree/Commit, or a git command error will occur""" |
108 | args = list() | |
108 | args = [] | |
109 | 109 | args.append("--abbrev=40") # we need full shas |
110 | 110 | args.append("--full-index") # get full index paths, not only filenames |
111 | 111 |
7 | 7 | import os |
8 | 8 | from stat import S_ISLNK |
9 | 9 | import subprocess |
10 | import sys | |
11 | 10 | import tempfile |
12 | 11 | |
13 | 12 | from git.compat import ( |
17 | 16 | force_bytes, |
18 | 17 | defenc, |
19 | 18 | mviter, |
20 | is_win | |
21 | 19 | ) |
22 | 20 | from git.exc import ( |
23 | 21 | GitCommandError, |
120 | 118 | ok = True |
121 | 119 | except OSError: |
122 | 120 | # in new repositories, there may be no index, which means we are empty |
123 | self.entries = dict() | |
121 | self.entries = {} | |
124 | 122 | return |
125 | 123 | finally: |
126 | 124 | if not ok: |
127 | 125 | lfd.rollback() |
128 | 126 | # END exception handling |
129 | 127 | |
130 | # Here it comes: on windows in python 2.5, memory maps aren't closed properly | |
131 | # Hence we are in trouble if we try to delete a file that is memory mapped, | |
132 | # which happens during read-tree. | |
133 | # In this case, we will just read the memory in directly. | |
134 | # Its insanely bad ... I am disappointed ! | |
135 | allow_mmap = (is_win or sys.version_info[1] > 5) | |
136 | stream = file_contents_ro(fd, stream=True, allow_mmap=allow_mmap) | |
128 | stream = file_contents_ro(fd, stream=True, allow_mmap=True) | |
137 | 129 | |
138 | 130 | try: |
139 | 131 | self._deserialize(stream) |
323 | 315 | if len(treeish) == 0 or len(treeish) > 3: |
324 | 316 | raise ValueError("Please specify between 1 and 3 treeish, got %i" % len(treeish)) |
325 | 317 | |
326 | arg_list = list() | |
318 | arg_list = [] | |
327 | 319 | # ignore that working tree and index possibly are out of date |
328 | 320 | if len(treeish) > 1: |
329 | 321 | # drop unmerged entries when reading our index and merging |
470 | 462 | are at stage 3 will not have a stage 3 entry. |
471 | 463 | """ |
472 | 464 | is_unmerged_blob = lambda t: t[0] != 0 |
473 | path_map = dict() | |
465 | path_map = {} | |
474 | 466 | for stage, blob in self.iter_blobs(is_unmerged_blob): |
475 | path_map.setdefault(blob.path, list()).append((stage, blob)) | |
467 | path_map.setdefault(blob.path, []).append((stage, blob)) | |
476 | 468 | # END for each unmerged blob |
477 | 469 | for l in mviter(path_map): |
478 | 470 | l.sort() |
575 | 567 | |
576 | 568 | def _preprocess_add_items(self, items): |
577 | 569 | """ Split the items into two lists of path strings and BaseEntries. """ |
578 | paths = list() | |
579 | entries = list() | |
570 | paths = [] | |
571 | entries = [] | |
580 | 572 | |
581 | 573 | for item in items: |
582 | 574 | if isinstance(item, string_types): |
609 | 601 | @unbare_repo |
610 | 602 | @git_working_dir |
611 | 603 | def _entries_for_paths(self, paths, path_rewriter, fprogress, entries): |
612 | entries_added = list() | |
604 | entries_added = [] | |
613 | 605 | if path_rewriter: |
614 | 606 | for path in paths: |
615 | 607 | if osp.isabs(path): |
741 | 733 | # automatically |
742 | 734 | # paths can be git-added, for everything else we use git-update-index |
743 | 735 | paths, entries = self._preprocess_add_items(items) |
744 | entries_added = list() | |
736 | entries_added = [] | |
745 | 737 | # This code needs a working tree, therefore we try not to run it unless required. |
746 | 738 | # That way, we are OK on a bare repository as well. |
747 | 739 | # If there are no paths, the rewriter has nothing to do either |
808 | 800 | def _items_to_rela_paths(self, items): |
809 | 801 | """Returns a list of repo-relative paths from the given items which |
810 | 802 | may be absolute or relative paths, entries or blobs""" |
811 | paths = list() | |
803 | paths = [] | |
812 | 804 | for item in items: |
813 | 805 | if isinstance(item, (BaseIndexEntry, (Blob, Submodule))): |
814 | 806 | paths.append(self._to_relative_path(item.path)) |
857 | 849 | been removed effectively. |
858 | 850 | This is interesting to know in case you have provided a directory or |
859 | 851 | globs. Paths are relative to the repository. """ |
860 | args = list() | |
852 | args = [] | |
861 | 853 | if not working_tree: |
862 | 854 | args.append("--cached") |
863 | 855 | args.append("--") |
896 | 888 | |
897 | 889 | :raise ValueError: If only one item was given |
898 | 890 | GitCommandError: If git could not handle your request""" |
899 | args = list() | |
891 | args = [] | |
900 | 892 | if skip_errors: |
901 | 893 | args.append('-k') |
902 | 894 | |
909 | 901 | |
910 | 902 | # first execute rename in dryrun so the command tells us what it actually does |
911 | 903 | # ( for later output ) |
912 | out = list() | |
904 | out = [] | |
913 | 905 | mvlines = self.repo.git.mv(args, paths, **kwargs).splitlines() |
914 | 906 | |
915 | 907 | # parse result - first 0:n/2 lines are 'checking ', the remaining ones |
1040 | 1032 | # line contents: |
1041 | 1033 | stderr = stderr.decode(defenc) |
1042 | 1034 | # git-checkout-index: this already exists |
1043 | failed_files = list() | |
1044 | failed_reasons = list() | |
1045 | unknown_lines = list() | |
1035 | failed_files = [] | |
1036 | failed_reasons = [] | |
1037 | unknown_lines = [] | |
1046 | 1038 | endings = (' already exists', ' is not in the cache', ' does not exist at stage', ' is unmerged') |
1047 | 1039 | for line in stderr.splitlines(): |
1048 | 1040 | if not line.startswith("git checkout-index: ") and not line.startswith("git-checkout-index: "): |
1105 | 1097 | proc = self.repo.git.checkout_index(args, **kwargs) |
1106 | 1098 | # FIXME: Reading from GIL! |
1107 | 1099 | make_exc = lambda: GitCommandError(("git-checkout-index",) + tuple(args), 128, proc.stderr.read()) |
1108 | checked_out_files = list() | |
1100 | checked_out_files = [] | |
1109 | 1101 | |
1110 | 1102 | for path in paths: |
1111 | 1103 | co_path = to_native_path_linux(self._to_relative_path(path)) |
186 | 186 | * content_sha is a 20 byte sha on all cache file contents""" |
187 | 187 | version, num_entries = read_header(stream) |
188 | 188 | count = 0 |
189 | entries = dict() | |
189 | entries = {} | |
190 | 190 | |
191 | 191 | read = stream.read |
192 | 192 | tell = stream.tell |
235 | 235 | :param sl: slice indicating the range we should process on the entries list |
236 | 236 | :return: tuple(binsha, list(tree_entry, ...)) a tuple of a sha and a list of |
237 | 237 | tree entries being a tuple of hexsha, mode, name""" |
238 | tree_items = list() | |
238 | tree_items = [] | |
239 | 239 | tree_items_append = tree_items.append |
240 | 240 | ci = sl.start |
241 | 241 | end = sl.stop |
294 | 294 | :param tree_shas: 1, 2 or 3 trees as identified by their binary 20 byte shas |
295 | 295 | If 1 or two, the entries will effectively correspond to the last given tree |
296 | 296 | If 3 are given, a 3 way merge is performed""" |
297 | out = list() | |
297 | out = [] | |
298 | 298 | out_append = out.append |
299 | 299 | |
300 | 300 | # one and two way is the same for us, as we don't have to handle an existing |
19 | 19 | file_mode = 0o100644 |
20 | 20 | link_mode = 0o120000 |
21 | 21 | |
22 | __slots__ = tuple() | |
22 | __slots__ = () | |
23 | 23 | |
24 | 24 | @property |
25 | 25 | def mime_type(self): |
315 | 315 | parent_commits = [repo.head.commit] |
316 | 316 | except ValueError: |
317 | 317 | # empty repositories have no head commit |
318 | parent_commits = list() | |
318 | parent_commits = [] | |
319 | 319 | # END handle parent commits |
320 | 320 | else: |
321 | 321 | for p in parent_commits: |
449 | 449 | readline = stream.readline |
450 | 450 | self.tree = Tree(self.repo, hex_to_bin(readline().split()[1]), Tree.tree_id << 12, '') |
451 | 451 | |
452 | self.parents = list() | |
452 | self.parents = [] | |
453 | 453 | next_line = None |
454 | 454 | while True: |
455 | 455 | parent_line = readline() |
49 | 49 | space_ord = ord(' ') |
50 | 50 | len_data = len(data) |
51 | 51 | i = 0 |
52 | out = list() | |
52 | out = [] | |
53 | 53 | while i < len_data: |
54 | 54 | mode = 0 |
55 | 55 | |
131 | 131 | :param path_prefix: a prefix to be added to the returned paths on this level, |
132 | 132 | set it '' for the first iteration |
133 | 133 | :note: The ordering of the returned items will be partially lost""" |
134 | trees_data = list() | |
134 | trees_data = [] | |
135 | 135 | nt = len(tree_shas) |
136 | 136 | for tree_sha in tree_shas: |
137 | 137 | if tree_sha is None: |
138 | data = list() | |
138 | data = [] | |
139 | 139 | else: |
140 | 140 | data = tree_entries_from_data(odb.stream(tree_sha).read()) |
141 | 141 | # END handle muted trees |
142 | 142 | trees_data.append(data) |
143 | 143 | # END for each sha to get data for |
144 | 144 | |
145 | out = list() | |
145 | out = [] | |
146 | 146 | out_append = out.append |
147 | 147 | |
148 | 148 | # find all matching entries and recursively process them together if the match |
192 | 192 | * [1] mode as int |
193 | 193 | * [2] path relative to the repository |
194 | 194 | :param path_prefix: prefix to prepend to the front of all returned paths""" |
195 | entries = list() | |
195 | entries = [] | |
196 | 196 | data = tree_entries_from_data(odb.stream(tree_sha).read()) |
197 | 197 | |
198 | 198 | # unpacking/packing is faster than accessing individual items |
2 | 2 | import logging |
3 | 3 | import os |
4 | 4 | import stat |
5 | try: | |
6 | from unittest import SkipTest | |
7 | except ImportError: | |
8 | from unittest2 import SkipTest | |
5 | from unittest import SkipTest | |
9 | 6 | import uuid |
10 | 7 | |
11 | 8 | import git |
62 | 59 | CLONE, FETCH, UPDWKTREE = [1 << x for x in range(RemoteProgress._num_op_codes, RemoteProgress._num_op_codes + 3)] |
63 | 60 | _num_op_codes = RemoteProgress._num_op_codes + 3 |
64 | 61 | |
65 | __slots__ = tuple() | |
62 | __slots__ = () | |
66 | 63 | |
67 | 64 | |
68 | 65 | BEGIN = UpdateProgress.BEGIN |
141 | 138 | try: |
142 | 139 | return type(self).list_items(item.module()) |
143 | 140 | except InvalidGitRepositoryError: |
144 | return list() | |
141 | return [] | |
145 | 142 | # END handle intermediate items |
146 | 143 | |
147 | 144 | @classmethod |
21 | 21 | 1 << x for x in range(UpdateProgress._num_op_codes, UpdateProgress._num_op_codes + 4)] |
22 | 22 | _num_op_codes = UpdateProgress._num_op_codes + 4 |
23 | 23 | |
24 | __slots__ = tuple() | |
24 | __slots__ = () | |
25 | 25 | |
26 | 26 | |
27 | 27 | BEGIN = RootUpdateProgress.BEGIN |
37 | 37 | """A (virtual) Root of all submodules in the given repository. It can be used |
38 | 38 | to more easily traverse all submodules of the master repository""" |
39 | 39 | |
40 | __slots__ = tuple() | |
40 | __slots__ = () | |
41 | 41 | |
42 | 42 | k_root_name = '__ROOT__' |
43 | 43 |
188 | 188 | def _get_intermediate_items(cls, index_object): |
189 | 189 | if index_object.type == "tree": |
190 | 190 | return tuple(index_object._iter_convert_to_object(index_object._cache)) |
191 | return tuple() | |
191 | return () | |
192 | 192 | |
193 | 193 | def _set_cache_(self, attr): |
194 | 194 | if attr == "_cache": |
152 | 152 | offset = utctz_to_altz(offset) |
153 | 153 | |
154 | 154 | # now figure out the date and time portion - split time |
155 | date_formats = list() | |
155 | date_formats = [] | |
156 | 156 | splitter = -1 |
157 | 157 | if ',' in string_date: |
158 | 158 | date_formats.append("%a, %d %b %Y") |
247 | 247 | into one direction. |
248 | 248 | Subclasses only need to implement one function. |
249 | 249 | Instances of the Subclass must be hashable""" |
250 | __slots__ = tuple() | |
250 | __slots__ = () | |
251 | 251 | |
252 | 252 | @classmethod |
253 | 253 | def _get_intermediate_items(cls, item): |
343 | 343 | class Serializable(object): |
344 | 344 | |
345 | 345 | """Defines methods to serialize and deserialize objects from and into a data stream""" |
346 | __slots__ = tuple() | |
346 | __slots__ = () | |
347 | 347 | |
348 | 348 | def _serialize(self, stream): |
349 | 349 | """Serialize the data of this object into the given data stream |
0 | try: | |
1 | from collections import OrderedDict | |
2 | except ImportError: | |
3 | try: | |
4 | from ordereddict import OrderedDict | |
5 | except ImportError: | |
6 | import warnings | |
7 | warnings.warn("git-python needs the ordereddict module installed in python below 2.6 and below.") | |
8 | warnings.warn("Using standard dictionary as substitute, and cause reordering when writing git config") | |
9 | OrderedDict = dict |
19 | 19 | HEAD reference.""" |
20 | 20 | _HEAD_NAME = 'HEAD' |
21 | 21 | _ORIG_HEAD_NAME = 'ORIG_HEAD' |
22 | __slots__ = tuple() | |
22 | __slots__ = () | |
23 | 23 | |
24 | 24 | def __init__(self, repo, path=_HEAD_NAME): |
25 | 25 | if path != self._HEAD_NAME: |
31 | 31 | |
32 | 32 | """Named tuple allowing easy access to the revlog data fields""" |
33 | 33 | _re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') |
34 | __slots__ = tuple() | |
34 | __slots__ = () | |
35 | 35 | |
36 | 36 | def __repr__(self): |
37 | 37 | """Representation of ourselves in git reflog format""" |
47 | 47 | """:return: a string suitable to be placed in a reflog file""" |
48 | 48 | act = self.actor |
49 | 49 | time = self.time |
50 | return u"{0} {1} {2} <{3}> {4!s} {5}\t{6}\n".format(self.oldhexsha, | |
51 | self.newhexsha, | |
52 | act.name, | |
53 | act.email, | |
54 | time[0], | |
55 | altz_to_utctz_str(time[1]), | |
56 | self.message) | |
50 | return u"{} {} {} <{}> {!s} {}\t{}\n".format(self.oldhexsha, | |
51 | self.newhexsha, | |
52 | act.name, | |
53 | act.email, | |
54 | time[0], | |
55 | altz_to_utctz_str(time[1]), | |
56 | self.message) | |
57 | 57 | |
58 | 58 | @property |
59 | 59 | def oldhexsha(self): |
26 | 26 | |
27 | 27 | """Represents a named reference to any object. Subclasses may apply restrictions though, |
28 | 28 | i.e. Heads can only point to commits.""" |
29 | __slots__ = tuple() | |
29 | __slots__ = () | |
30 | 30 | _points_to_commits_only = False |
31 | 31 | _resolve_ref_on_create = True |
32 | 32 | _common_path_default = "refs" |
443 | 443 | pack_file_path = cls._get_packed_refs_path(repo) |
444 | 444 | try: |
445 | 445 | with open(pack_file_path, 'rb') as reader: |
446 | new_lines = list() | |
446 | new_lines = [] | |
447 | 447 | made_change = False |
448 | 448 | dropped_last_line = False |
449 | 449 | for line in reader: |
16 | 16 | if tagref.tag is not None: |
17 | 17 | print(tagref.tag.message)""" |
18 | 18 | |
19 | __slots__ = tuple() | |
19 | __slots__ = () | |
20 | 20 | _common_path_default = "refs/tags" |
21 | 21 | |
22 | 22 | @property |
541 | 541 | if ' Push URL:' in line: |
542 | 542 | yield line.split(': ')[-1] |
543 | 543 | except GitCommandError as ex: |
544 | if any([msg in str(ex) for msg in ['correct access rights', 'cannot run ssh']]): | |
544 | if any(msg in str(ex) for msg in ['correct access rights', 'cannot run ssh']): | |
545 | 545 | # If ssh is not setup to access this repository, see issue 694 |
546 | 546 | result = Git().execute( |
547 | 547 | ['git', 'config', '--get', 'remote.%s.url' % self.name] |
662 | 662 | # lines which are no progress are fetch info lines |
663 | 663 | # this also waits for the command to finish |
664 | 664 | # Skip some progress lines that don't provide relevant information |
665 | fetch_info_lines = list() | |
665 | fetch_info_lines = [] | |
666 | 666 | # Basically we want all fetch info lines which appear to be in regular form, and thus have a |
667 | 667 | # command character. Everything else we ignore, |
668 | 668 | cmds = set(FetchInfo._flag_map.keys()) |
484 | 484 | def iter_commits(self, rev=None, paths='', **kwargs): |
485 | 485 | """A list of Commit objects representing the history of a given ref/commit |
486 | 486 | |
487 | :parm rev: | |
487 | :param rev: | |
488 | 488 | revision specifier, see git-rev-parse for viable options. |
489 | 489 | If None, the active branch will be used. |
490 | 490 | |
491 | :parm paths: | |
491 | :param paths: | |
492 | 492 | is an optional path or a list of paths to limit the returned commits to |
493 | 493 | Commits that do not contain that path or the paths will not be returned. |
494 | 494 | |
495 | :parm kwargs: | |
495 | :param kwargs: | |
496 | 496 | Arguments to be passed to git-rev-list - common ones are |
497 | 497 | max_count and skip |
498 | 498 | |
518 | 518 | raise ValueError("Please specify at least two revs, got only %i" % len(rev)) |
519 | 519 | # end handle input |
520 | 520 | |
521 | res = list() | |
521 | res = [] | |
522 | 522 | try: |
523 | 523 | lines = self.git.merge_base(*rev, **kwargs).splitlines() |
524 | 524 | except GitCommandError as err: |
579 | 579 | alts = f.read().decode(defenc) |
580 | 580 | return alts.strip().splitlines() |
581 | 581 | else: |
582 | return list() | |
582 | return [] | |
583 | 583 | |
584 | 584 | def _set_alternates(self, alts): |
585 | 585 | """Sets the alternates |
586 | 586 | |
587 | :parm alts: | |
587 | :param alts: | |
588 | 588 | is the array of string paths representing the alternates at which |
589 | 589 | git should look for objects, i.e. /home/user/repo/.git/objects |
590 | 590 | |
663 | 663 | **kwargs) |
664 | 664 | # Untracked files preffix in porcelain mode |
665 | 665 | prefix = "?? " |
666 | untracked_files = list() | |
666 | untracked_files = [] | |
667 | 667 | for line in proc.stdout: |
668 | 668 | line = line.decode(defenc) |
669 | 669 | if not line.startswith(prefix): |
694 | 694 | Unlike .blame(), this does not return the actual file's contents, only |
695 | 695 | a stream of BlameEntry tuples. |
696 | 696 | |
697 | :parm rev: revision specifier, see git-rev-parse for viable options. | |
697 | :param rev: revision specifier, see git-rev-parse for viable options. | |
698 | 698 | :return: lazy iterator of BlameEntry tuples, where the commit |
699 | 699 | indicates the commit to blame for the line, and range |
700 | 700 | indicates a span of line numbers in the resulting file. |
703 | 703 | should get a continuous range spanning all line numbers in the file. |
704 | 704 | """ |
705 | 705 | data = self.git.blame(rev, '--', file, p=True, incremental=True, stdout_as_string=False, **kwargs) |
706 | commits = dict() | |
706 | commits = {} | |
707 | 707 | |
708 | 708 | stream = (line for line in data.split(b'\n') if line) |
709 | 709 | while True: |
715 | 715 | if hexsha not in commits: |
716 | 716 | # Now read the next few lines and build up a dict of properties |
717 | 717 | # for this commit |
718 | props = dict() | |
718 | props = {} | |
719 | 719 | while True: |
720 | 720 | line = next(stream) |
721 | 721 | if line == b'boundary': |
756 | 756 | def blame(self, rev, file, incremental=False, **kwargs): |
757 | 757 | """The blame information for the given file at the given revision. |
758 | 758 | |
759 | :parm rev: revision specifier, see git-rev-parse for viable options. | |
759 | :param rev: revision specifier, see git-rev-parse for viable options. | |
760 | 760 | :return: |
761 | 761 | list: [git.Commit, list: [<line>]] |
762 | 762 | A list of tuples associating a Commit object with a list of lines that |
766 | 766 | return self.blame_incremental(rev, file, **kwargs) |
767 | 767 | |
768 | 768 | data = self.git.blame(rev, '--', file, p=True, stdout_as_string=False, **kwargs) |
769 | commits = dict() | |
770 | blames = list() | |
769 | commits = {} | |
770 | blames = [] | |
771 | 771 | info = None |
772 | 772 | |
773 | 773 | keepends = True |
870 | 870 | or None in which case the repository will be created in the current |
871 | 871 | working directory |
872 | 872 | |
873 | :parm mkdir: | |
873 | :param mkdir: | |
874 | 874 | if specified will create the repository directory if it doesn't |
875 | 875 | already exists. Creates the directory with a mode=0755. |
876 | 876 | Only effective if a path is explicitly given |
885 | 885 | can lead to information disclosure, allowing attackers to |
886 | 886 | access the contents of environment variables |
887 | 887 | |
888 | :parm kwargs: | |
888 | :param kwargs: | |
889 | 889 | keyword arguments serving as additional options to the git-init command |
890 | 890 | |
891 | 891 | :return: ``git.Repo`` (the newly created repo)""" |
983 | 983 | def archive(self, ostream, treeish=None, prefix=None, **kwargs): |
984 | 984 | """Archive the tree at the given revision. |
985 | 985 | |
986 | :parm ostream: file compatible stream object to which the archive will be written as bytes | |
987 | :parm treeish: is the treeish name/id, defaults to active branch | |
988 | :parm prefix: is the optional prefix to prepend to each filename in the archive | |
989 | :parm kwargs: Additional arguments passed to git-archive | |
986 | :param ostream: file compatible stream object to which the archive will be written as bytes | |
987 | :param treeish: is the treeish name/id, defaults to active branch | |
988 | :param prefix: is the optional prefix to prepend to each filename in the archive | |
989 | :param kwargs: Additional arguments passed to git-archive | |
990 | 990 | |
991 | 991 | * Use the 'format' argument to define the kind of format. Use |
992 | 992 | specialized ostreams to write any format supported by python. |
1000 | 1000 | if prefix and 'prefix' not in kwargs: |
1001 | 1001 | kwargs['prefix'] = prefix |
1002 | 1002 | kwargs['output_stream'] = ostream |
1003 | path = kwargs.pop('path', list()) | |
1003 | path = kwargs.pop('path', []) | |
1004 | 1004 | if not isinstance(path, (tuple, list)): |
1005 | 1005 | path = [path] |
1006 | 1006 | # end assure paths is list |
14 | 14 | import tempfile |
15 | 15 | import textwrap |
16 | 16 | import time |
17 | import unittest | |
17 | 18 | |
18 | 19 | from git.compat import string_types, is_win |
19 | 20 | from git.util import rmtree, cwd |
21 | 22 | |
22 | 23 | import os.path as osp |
23 | 24 | |
24 | ||
25 | if sys.version_info[0:2] == (2, 6): | |
26 | import unittest2 as unittest | |
27 | else: | |
28 | import unittest | |
29 | 25 | |
30 | 26 | TestCase = unittest.TestCase |
31 | 27 | SkipTest = unittest.SkipTest |
347 | 343 | of the project history ( to assure tests don't fail for others ). |
348 | 344 | """ |
349 | 345 | |
350 | # On py26, unittest2 has assertRaisesRegex | |
351 | 346 | # On py3, unittest has assertRaisesRegex |
352 | 347 | # On py27, we use unittest, which names it differently: |
353 | 348 | if sys.version_info[0:2] == (2, 7): |
27 | 27 | # GET TREES |
28 | 28 | # walk all trees of all commits |
29 | 29 | st = time() |
30 | blobs_per_commit = list() | |
30 | blobs_per_commit = [] | |
31 | 31 | nt = 0 |
32 | 32 | for commit in commits: |
33 | 33 | tree = commit.tree |
34 | blobs = list() | |
34 | blobs = [] | |
35 | 35 | for item in tree.traverse(): |
36 | 36 | nt += 1 |
37 | 37 | if item.type == 'blob': |
68 | 68 | |
69 | 69 | # reading in chunks of 1 MiB |
70 | 70 | cs = 512 * 1000 |
71 | chunks = list() | |
71 | chunks = [] | |
72 | 72 | st = time() |
73 | 73 | ostream = ldb.stream(binsha) |
74 | 74 | while True: |
6 | 6 | import os |
7 | 7 | import sys |
8 | 8 | import tempfile |
9 | try: | |
10 | from unittest import SkipTest, skipIf | |
11 | except ImportError: | |
12 | from unittest2 import SkipTest, skipIf | |
9 | from unittest import SkipTest, skipIf | |
13 | 10 | |
14 | 11 | from git import ( |
15 | 12 | Blob, |
216 | 216 | |
217 | 217 | def test_diff_interface(self): |
218 | 218 | # test a few variations of the main diff routine |
219 | assertion_map = dict() | |
219 | assertion_map = {} | |
220 | 220 | for i, commit in enumerate(self.rorepo.iter_commits('0.1.6', max_count=2)): |
221 | 221 | diff_item = commit |
222 | 222 | if i % 2 == 0: |
172 | 172 | |
173 | 173 | # [14-test_init_repo_object] |
174 | 174 | # create a new submodule and check it out on the spot, setup to track master branch of `bare_repo` |
175 | # As our GitPython repository has submodules already that point to github, make sure we don't | |
175 | # As our GitPython repository has submodules already that point to GitHub, make sure we don't | |
176 | 176 | # interact with them |
177 | 177 | for sm in cloned_repo.submodules: |
178 | 178 | assert not sm.remove().exists() # after removal, the sm doesn't exist anymore |
1 | 1 | from stat import S_IFDIR, S_IFREG, S_IFLNK |
2 | 2 | from os import stat |
3 | 3 | import os.path as osp |
4 | ||
5 | try: | |
6 | from unittest import skipIf, SkipTest | |
7 | except ImportError: | |
8 | from unittest2 import skipIf, SkipTest | |
4 | from unittest import skipIf, SkipTest | |
9 | 5 | |
10 | 6 | from git import Git |
11 | 7 | from git.compat import PY3 |
214 | 210 | def _assert_tree_entries(self, entries, num_trees): |
215 | 211 | for entry in entries: |
216 | 212 | assert len(entry) == num_trees |
217 | paths = set(e[2] for e in entry if e) | |
213 | paths = {e[2] for e in entry if e} | |
218 | 214 | |
219 | 215 | # only one path per set of entries |
220 | 216 | assert len(paths) == 1 |
90 | 90 | |
91 | 91 | # order is undefined |
92 | 92 | res = self.git.transform_kwargs(**{'s': True, 't': True}) |
93 | self.assertEqual(set(['-s', '-t']), set(res)) | |
93 | self.assertEqual({'-s', '-t'}, set(res)) | |
94 | 94 | |
95 | 95 | def test_it_executes_git_to_shell_and_returns_result(self): |
96 | 96 | assert_match(r'^git version [\d\.]{2}.*$', self.git.execute(["git", "version"])) |
10 | 10 | S_ISLNK, |
11 | 11 | ST_MODE |
12 | 12 | ) |
13 | import sys | |
14 | 13 | import tempfile |
15 | try: | |
16 | from unittest import skipIf | |
17 | except ImportError: | |
18 | from unittest2 import skipIf | |
14 | from unittest import skipIf | |
19 | 15 | |
20 | 16 | from git import ( |
21 | 17 | IndexFile, |
100 | 96 | |
101 | 97 | def _reset_progress(self): |
102 | 98 | # maps paths to the count of calls |
103 | self._fprogress_map = dict() | |
99 | self._fprogress_map = {} | |
104 | 100 | |
105 | 101 | def _assert_entries(self, entries): |
106 | 102 | for entry in entries: |
130 | 126 | # test stage |
131 | 127 | index_merge = IndexFile(self.rorepo, fixture_path("index_merge")) |
132 | 128 | self.assertEqual(len(index_merge.entries), 106) |
133 | assert len(list(e for e in index_merge.entries.values() if e.stage != 0)) | |
129 | assert len([e for e in index_merge.entries.values() if e.stage != 0]) | |
134 | 130 | |
135 | 131 | # write the data - it must match the original |
136 | 132 | tmpfile = tempfile.mktemp() |
144 | 140 | if isinstance(tree, str): |
145 | 141 | tree = self.rorepo.commit(tree).tree |
146 | 142 | |
147 | blist = list() | |
143 | blist = [] | |
148 | 144 | for blob in tree.traverse(predicate=lambda e, d: e.type == "blob", branch_first=False): |
149 | 145 | assert (blob.path, 0) in index.entries |
150 | 146 | blist.append(blob) |
151 | 147 | # END for each blob in tree |
152 | 148 | if len(blist) != len(index.entries): |
153 | iset = set(k[0] for k in index.entries.keys()) | |
154 | bset = set(b.path for b in blist) | |
149 | iset = {k[0] for k in index.entries.keys()} | |
150 | bset = {b.path for b in blist} | |
155 | 151 | raise AssertionError("CMP Failed: Missing entries in index: %s, missing in tree: %s" % |
156 | 152 | (bset - iset, iset - bset)) |
157 | 153 | # END assertion message |
167 | 163 | except Exception as ex: |
168 | 164 | msg_py3 = "required argument is not an integer" |
169 | 165 | msg_py2 = "cannot convert argument to integer" |
170 | msg_py26 = "unsupported operand type(s) for &: 'str' and 'long'" | |
171 | assert msg_py2 in str(ex) or msg_py3 in str(ex) or \ | |
172 | msg_py26 in str(ex), str(ex) | |
166 | assert msg_py2 in str(ex) or msg_py3 in str(ex) | |
173 | 167 | |
174 | 168 | ## 2nd time should not fail due to stray lock file |
175 | 169 | try: |
179 | 173 | |
180 | 174 | @with_rw_repo('0.1.6') |
181 | 175 | def test_index_file_from_tree(self, rw_repo): |
182 | if sys.version_info < (2, 7): | |
183 | ## Skipped, not `assertRaisesRegexp` in py2.6 | |
184 | return | |
185 | 176 | common_ancestor_sha = "5117c9c8a4d3af19a9958677e45cda9269de1541" |
186 | 177 | cur_sha = "4b43ca7ff72d5f535134241e7c797ddc9c7a3573" |
187 | 178 | other_sha = "39f85c4358b7346fee22169da9cad93901ea9eb9" |
198 | 189 | |
199 | 190 | # merge three trees - here we have a merge conflict |
200 | 191 | three_way_index = IndexFile.from_tree(rw_repo, common_ancestor_sha, cur_sha, other_sha) |
201 | assert len(list(e for e in three_way_index.entries.values() if e.stage != 0)) | |
192 | assert len([e for e in three_way_index.entries.values() if e.stage != 0]) | |
202 | 193 | |
203 | 194 | # ITERATE BLOBS |
204 | 195 | merge_required = lambda t: t[0] != 0 |
234 | 225 | def test_index_merge_tree(self, rw_repo): |
235 | 226 | # A bit out of place, but we need a different repo for this: |
236 | 227 | self.assertNotEqual(self.rorepo, rw_repo) |
237 | self.assertEqual(len(set((self.rorepo, self.rorepo, rw_repo, rw_repo))), 2) | |
228 | self.assertEqual(len({self.rorepo, self.rorepo, rw_repo, rw_repo}), 2) | |
238 | 229 | |
239 | 230 | # SINGLE TREE MERGE |
240 | 231 | # current index is at the (virtual) cur_commit |
535 | 526 | |
536 | 527 | # same index, no parents |
537 | 528 | commit_message = "index without parents" |
538 | commit_no_parents = index.commit(commit_message, parent_commits=list(), head=True) | |
529 | commit_no_parents = index.commit(commit_message, parent_commits=[], head=True) | |
539 | 530 | self.assertEqual(commit_no_parents.message, commit_message) |
540 | 531 | self.assertEqual(len(commit_no_parents.parents), 0) |
541 | 532 | self.assertEqual(cur_head.commit, commit_no_parents) |
890 | 881 | _make_hook( |
891 | 882 | index.repo.git_dir, |
892 | 883 | 'commit-msg', |
893 | 'echo -n " {0}" >> "$1"'.format(from_hook_message) | |
884 | 'echo -n " {}" >> "$1"'.format(from_hook_message) | |
894 | 885 | ) |
895 | 886 | new_commit = index.commit(commit_message) |
896 | self.assertEqual(new_commit.message, u"{0} {1}".format(commit_message, from_hook_message)) | |
887 | self.assertEqual(new_commit.message, u"{} {}".format(commit_message, from_hook_message)) | |
897 | 888 | |
898 | 889 | @with_rw_repo('HEAD', bare=True) |
899 | 890 | def test_commit_msg_hook_fail(self, rw_repo): |
44 | 44 | TagReference(self.rorepo, "refs/invalid/tag", check_path=False) |
45 | 45 | |
46 | 46 | def test_tag_base(self): |
47 | tag_object_refs = list() | |
47 | tag_object_refs = [] | |
48 | 48 | for tag in self.rorepo.tags: |
49 | 49 | assert "refs/tags" in tag.path |
50 | 50 | assert tag.name |
5 | 5 | |
6 | 6 | import random |
7 | 7 | import tempfile |
8 | try: | |
9 | from unittest import skipIf | |
10 | except ImportError: | |
11 | from unittest2 import skipIf | |
8 | from unittest import skipIf | |
12 | 9 | |
13 | 10 | from git import ( |
14 | 11 | RemoteProgress, |
46 | 43 | |
47 | 44 | def __init__(self): |
48 | 45 | super(TestRemoteProgress, self).__init__() |
49 | self._seen_lines = list() | |
50 | self._stages_per_op = dict() | |
46 | self._seen_lines = [] | |
47 | self._stages_per_op = {} | |
51 | 48 | self._num_progress_messages = 0 |
52 | 49 | |
53 | 50 | def _parse_progress_line(self, line): |
8 | 8 | import itertools |
9 | 9 | import os |
10 | 10 | import pickle |
11 | import sys | |
12 | 11 | import tempfile |
13 | try: | |
14 | from unittest import skipIf, SkipTest | |
15 | except ImportError: | |
16 | from unittest2 import skipIf, SkipTest | |
12 | from unittest import skipIf, SkipTest | |
17 | 13 | |
18 | 14 | try: |
19 | 15 | import pathlib |
363 | 359 | |
364 | 360 | @patch.object(Git, '_call_process') |
365 | 361 | def test_should_display_blame_information(self, git): |
366 | if sys.version_info < (2, 7): | |
367 | ## Skipped, not `assertRaisesRegexp` in py2.6 | |
368 | return | |
369 | 362 | git.return_value = fixture('blame') |
370 | 363 | b = self.rorepo.blame('master', 'lib/git.py') |
371 | 364 | assert_equal(13, len(b)) |
521 | 514 | # this is only a preliminary test, more testing done in test_index |
522 | 515 | self.assertEqual(self.rorepo, self.rorepo) |
523 | 516 | self.assertFalse(self.rorepo != self.rorepo) |
524 | self.assertEqual(len(set((self.rorepo, self.rorepo))), 1) | |
517 | self.assertEqual(len({self.rorepo, self.rorepo}), 1) | |
525 | 518 | |
526 | 519 | @with_rw_directory |
527 | 520 | def test_tilde_and_env_vars_in_repo_path(self, rw_dir): |
791 | 784 | |
792 | 785 | def test_repo_odbtype(self): |
793 | 786 | target_type = GitCmdObjectDB |
794 | if sys.version_info[:2] < (2, 5): | |
795 | target_type = GitCmdObjectDB | |
796 | 787 | self.assertIsInstance(self.rorepo.odb, target_type) |
797 | 788 | |
798 | 789 | def test_submodules(self): |
2 | 2 | # the BSD License: http://www.opensource.org/licenses/bsd-license.php |
3 | 3 | import os |
4 | 4 | import sys |
5 | try: | |
6 | from unittest import skipIf | |
7 | except ImportError: | |
8 | from unittest2 import skipIf | |
5 | from unittest import skipIf | |
9 | 6 | |
10 | 7 | import git |
11 | 8 | from git.cmd import Git |
266 | 263 | self.failUnlessRaises(ValueError, csm.remove, module=False, configuration=False) |
267 | 264 | |
268 | 265 | # module() is supposed to point to gitdb, which has a child-submodule whose URL is still pointing |
269 | # to github. To save time, we will change it to | |
266 | # to GitHub. To save time, we will change it to | |
270 | 267 | csm.set_parent_commit(csm.repo.head.commit) |
271 | 268 | with csm.config_writer() as cw: |
272 | 269 | cw.set_value('url', self._small_repo_url()) |
5 | 5 | |
6 | 6 | from io import BytesIO |
7 | 7 | import sys |
8 | try: | |
9 | from unittest import skipIf | |
10 | except ImportError: | |
11 | from unittest2 import skipIf | |
8 | from unittest import skipIf | |
12 | 9 | |
13 | 10 | from git import ( |
14 | 11 | Tree, |
63 | 60 | def test_traverse(self): |
64 | 61 | root = self.rorepo.tree('0.1.6') |
65 | 62 | num_recursive = 0 |
66 | all_items = list() | |
63 | all_items = [] | |
67 | 64 | for obj in root.traverse(): |
68 | 65 | if "/" in obj.path: |
69 | 66 | num_recursive += 1 |
81 | 78 | # only choose trees |
82 | 79 | trees_only = lambda i, d: i.type == "tree" |
83 | 80 | trees = list(root.traverse(predicate=trees_only)) |
84 | assert len(trees) == len(list(i for i in root.traverse() if trees_only(i, 0))) | |
81 | assert len(trees) == len([i for i in root.traverse() if trees_only(i, 0)]) | |
85 | 82 | |
86 | 83 | # test prune |
87 | 84 | lib_folder = lambda t, d: t.path == "lib" |
90 | 87 | |
91 | 88 | # trees and blobs |
92 | 89 | assert len(set(trees) | set(root.trees)) == len(trees) |
93 | assert len(set(b for b in root if isinstance(b, Blob)) | set(root.blobs)) == len(root.blobs) | |
90 | assert len({b for b in root if isinstance(b, Blob)} | set(root.blobs)) == len(root.blobs) | |
94 | 91 | subitem = trees[0][0] |
95 | 92 | assert "/" in subitem.path |
96 | 93 | assert subitem.name == osp.basename(subitem.path) |
5 | 5 | |
6 | 6 | import tempfile |
7 | 7 | import time |
8 | try: | |
9 | from unittest import skipIf | |
10 | except ImportError: | |
11 | from unittest2 import skipIf | |
8 | from unittest import skipIf | |
12 | 9 | |
13 | 10 | |
14 | 11 | import ddt |
13 | 13 | import shutil |
14 | 14 | import stat |
15 | 15 | import time |
16 | try: | |
17 | from unittest import SkipTest | |
18 | except ImportError: | |
19 | from unittest2 import SkipTest | |
16 | from unittest import SkipTest | |
20 | 17 | |
21 | 18 | from gitdb.util import (# NOQA @IgnorePep8 |
22 | 19 | make_sha, |
371 | 368 | re_op_relative = re.compile(r"(remote: )?([\w\s]+):\s+(\d+)% \((\d+)/(\d+)\)(.*)") |
372 | 369 | |
373 | 370 | def __init__(self): |
374 | self._seen_ops = list() | |
371 | self._seen_ops = [] | |
375 | 372 | self._cur_line = None |
376 | 373 | self.error_lines = [] |
377 | 374 | self.other_lines = [] |
394 | 391 | return [] |
395 | 392 | |
396 | 393 | sub_lines = line.split('\r') |
397 | failed_lines = list() | |
394 | failed_lines = [] | |
398 | 395 | for sline in sub_lines: |
399 | 396 | # find escape characters and cut them away - regex will not work with |
400 | 397 | # them as they are non-ascii. As git might expect a tty, it will send them |
672 | 669 | """Create a Stat object from output retrieved by git-diff. |
673 | 670 | |
674 | 671 | :return: git.Stat""" |
675 | hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': dict()} | |
672 | hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': {}} | |
676 | 673 | for line in text.splitlines(): |
677 | 674 | (raw_insertions, raw_deletions, filename) = line.split("\t") |
678 | 675 | insertions = raw_insertions != '-' and int(raw_insertions) or 0 |
801 | 798 | def __init__(self, file_path, check_interval_s=0.3, max_block_time_s=MAXSIZE): |
802 | 799 | """Configure the instance |
803 | 800 | |
804 | :parm check_interval_s: | |
801 | :param check_interval_s: | |
805 | 802 | Period of time to sleep until the lock is checked the next time. |
806 | 803 | By default, it waits a nearly unlimited time |
807 | 804 | |
808 | :parm max_block_time_s: Maximum amount of seconds we may lock""" | |
805 | :param max_block_time_s: Maximum amount of seconds we may lock""" | |
809 | 806 | super(BlockingLockFile, self).__init__(file_path) |
810 | 807 | self._check_interval = check_interval_s |
811 | 808 | self._max_block_time = max_block_time_s |
919 | 916 | |
920 | 917 | """Defines an interface for iterable items which is to assure a uniform |
921 | 918 | way to retrieve and iterate items within the git repository""" |
922 | __slots__ = tuple() | |
919 | __slots__ = () | |
923 | 920 | _id_attribute_ = "attribute that most suitably identifies your instance" |
924 | 921 | |
925 | 922 | @classmethod |
8 | 8 | |
9 | 9 | from distutils.command.build_py import build_py as _build_py |
10 | 10 | from setuptools.command.sdist import sdist as _sdist |
11 | import pkg_resources | |
12 | import logging | |
13 | 11 | import os |
14 | 12 | import sys |
15 | 13 | from os import path |
46 | 44 | |
47 | 45 | |
48 | 46 | def _stamp_version(filename): |
49 | found, out = False, list() | |
47 | found, out = False, [] | |
50 | 48 | try: |
51 | 49 | with open(filename, 'r') as f: |
52 | 50 | for line in f: |
65 | 63 | |
66 | 64 | |
67 | 65 | install_requires = ['gitdb2 >= 2.0.0'] |
68 | extras_require = { | |
69 | ':python_version == "2.6"': ['ordereddict'], | |
70 | } | |
71 | 66 | test_requires = ['ddt>=1.1.1'] |
72 | if sys.version_info[:2] < (2, 7): | |
73 | test_requires.append('mock') | |
74 | ||
75 | try: | |
76 | if 'bdist_wheel' not in sys.argv: | |
77 | for key, value in extras_require.items(): | |
78 | if key.startswith(':') and pkg_resources.evaluate_marker(key[1:]): | |
79 | install_requires.extend(value) | |
80 | except Exception: | |
81 | logging.getLogger(__name__).exception( | |
82 | 'Something went wrong calculating platform specific dependencies, so ' | |
83 | "you're getting them all!" | |
84 | ) | |
85 | for key, value in extras_require.items(): | |
86 | if key.startswith(':'): | |
87 | install_requires.extend(value) | |
88 | 67 | # end |
89 | 68 | |
90 | 69 | setup( |
100 | 79 | package_data={'git.test': ['fixtures/*']}, |
101 | 80 | package_dir={'git': 'git'}, |
102 | 81 | license="BSD License", |
103 | python_requires='>=2.6, !=3.0.*, !=3.1.*, !=3.2.*', | |
82 | python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*', | |
104 | 83 | requires=['gitdb2 (>=2.0.0)'], |
105 | 84 | install_requires=install_requires, |
106 | 85 | test_requirements=test_requires + install_requires, |
125 | 104 | "Operating System :: MacOS :: MacOS X", |
126 | 105 | "Programming Language :: Python", |
127 | 106 | "Programming Language :: Python :: 2", |
128 | "Programming Language :: Python :: 2.6", | |
129 | 107 | "Programming Language :: Python :: 2.7", |
130 | 108 | "Programming Language :: Python :: 3", |
131 | "Programming Language :: Python :: 3.3", | |
132 | 109 | "Programming Language :: Python :: 3.4", |
133 | 110 | "Programming Language :: Python :: 3.5", |
134 | 111 | "Programming Language :: Python :: 3.6", |