diff options
-rw-r--r-- | .gitignore | 4 | ||||
-rw-r--r-- | .gitmodules | 2 | ||||
-rw-r--r-- | MANIFEST.in | 1 | ||||
-rw-r--r-- | README.md | 82 | ||||
-rw-r--r-- | VERSION | 2 | ||||
-rw-r--r-- | doc/source/changes.rst | 6 | ||||
-rw-r--r-- | etc/sublime-text/git-python.sublime-project | 64 | ||||
-rw-r--r-- | git/cmd.py | 22 | ||||
-rw-r--r-- | git/exc.py | 10 | ||||
m--------- | git/ext/gitdb | 0 | ||||
-rw-r--r-- | git/repo/base.py | 8 | ||||
-rw-r--r-- | git/test/test_git.py | 30 | ||||
-rw-r--r-- | requirements.txt | 2 | ||||
-rwxr-xr-x[-rw-r--r--] | setup.py | 30 | ||||
-rw-r--r-- | test-requirements.txt | 4 | ||||
-rw-r--r-- | tox.ini | 20 |
16 files changed, 189 insertions, 98 deletions
@@ -1,6 +1,7 @@ *.py[co] *.swp *~ +/*.egg-info /lib/GitPython.egg-info cover/ .coverage @@ -9,3 +10,6 @@ cover/ /doc/_build nbproject *.sublime-workspace + +/*egg-info +/.tox diff --git a/.gitmodules b/.gitmodules index 533fc59f..612c39d9 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "gitdb"] path = git/ext/gitdb - url = http://github.com/gitpython-developers/gitdb.git + url = https://github.com/gitpython-developers/gitdb.git diff --git a/MANIFEST.in b/MANIFEST.in index 89f5b92d..95b2e883 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -3,6 +3,7 @@ include LICENSE include CHANGES include AUTHORS include README +include requirements.txt graft git/test/fixtures graft git/test/performance @@ -13,21 +13,56 @@ The object database implementation is optimized for handling large quantities of - Tested with nose 1.3.0 * Mock by Michael Foord used for tests - Tested with 1.0.1 +* Coverage - used for tests coverage + +The list of dependencies are listed in /requirements.txt and /test-requirements.txt. The installer takes care of installing them for you though. ### INSTALL +[](https://pypi.python.org/pypi/GitPython/) +[](https://pypi.python.org/pypi/GitPython/) + If you have downloaded the source code: python setup.py install - -or if you want to obtain a copy more easily: + +or if you want to obtain a copy from the Pypi repository: pip install gitpython - + +Both commands will install the required package dependencies. + A distribution package can be obtained for manual installation at: http://pypi.python.org/pypi/GitPython +### RUNNING TESTS + +The easiest way to run test is by using [tox](https://pypi.python.org/pypi/tox) a wrapper around virtualenv. It will take care of setting up environnements with the proper dependencies installed and execute test commands. To install it simply: + + pip install tox + +Then run: + + tox + +### SOURCE + +GitPython's git repo is available on GitHub, which can be browsed at [github](https://github.com/gitpython-developers/GitPython) and cloned like that: + + git clone git://github.com/gitpython-developers/GitPython.git git-python + + +### INFRASTRUCTURE + +* [User Documentation](http://packages.python.org/GitPython/) +* [Mailing List](http://groups.google.com/group/git-python) +* [Issue Tracker](https://github.com/gitpython-developers/GitPython/issues) + +### LICENSE + +New BSD License. See the LICENSE file. + ### DEVELOPMENT STATUS [](https://travis-ci.org/gitpython-developers/GitPython) @@ -35,20 +70,21 @@ A distribution package can be obtained for manual installation at: The project was idle for 2 years, the last release (v0.3.2 RC1) was made on July 2011. Reason for this might have been the project's dependency on me as sole active maintainer, which is an issue in itself. -Now I am back and fully dedicated to pushing [OSS](https://github.com/Byron/bcore) forward in the realm of [digital content creation](http://gooseberry.blender.org/), and git-python will see some of my time as well. Therefore it will be moving forward, slowly but steadily. +Now that there seems to be a massive user base, this should be motivation enough to let git-python return to a proper state, which means -In short, I want to make a new release of 0.3 with all contributions and fixes included, foster community building to facilitate contributions. Everything else is future. +* no open pull requests +* no open issues describing bugs + +In short, I want to make a new release of 0.3 with all contributions and fixes included, foster community building to facilitate contributions. #### PRESENT GOALS The goals I have set for myself, in order, are as follows, all on branch 0.3. * bring the test suite back online to work with the most commonly used git version -* setup a travis test-matrix to test against a lower and upper git version as well * merge all open pull requests, may there be a test-case or not, back. If something breaks, fix it if possible or let the contributor know * conform git-python's structure and toolchain to the one used in my [other OSS projects](https://github.com/Byron/bcore) * evaluate all open issues and close them if possible -* create a new release of the 0.3 branch * evaluate python 3.3 compatibility and establish it if possible While that is happening, I will try hard to foster community around the project. This means being more responsive on the mailing list and in issues, as well as setting up clear guide lines about the [contribution](http://rfc.zeromq.org/spec:22) and maintenance workflow. @@ -63,35 +99,3 @@ There has been a lot of work in the master branch, which is the direction I want * make it work similarly to 0.3, but with the option to swap for at least one additional backend * make a 1.0 release * add backends as required - -### SOURCE - - -GitPython's git repo is available on GitHub, which can be browsed at: - -https://github.com/gitpython-developers/GitPython - -and cloned using: - -git clone git://github.com/gitpython-developers/GitPython.git git-python - - -### DOCUMENTATION - -The html-compiled documentation can be found at the following URL: - -http://packages.python.org/GitPython/ - -### MAILING LIST - -http://groups.google.com/group/git-python - -### ISSUE TRACKER - -Issues are tracked on github: - -https://github.com/gitpython-developers/GitPython/issues - -### LICENSE - -New BSD License. See the LICENSE file. @@ -1 +1 @@ -0.3.2 RC1 +0.3.2 diff --git a/doc/source/changes.rst b/doc/source/changes.rst index c1e65195..927f326c 100644 --- a/doc/source/changes.rst +++ b/doc/source/changes.rst @@ -2,6 +2,12 @@ Changelog ========= +0.3.2 +===== + +* Release of most recent version as non-RC build, just to allow pip to install the latest version right away. +* Have a look at the milestones (https://github.com/gitpython-developers/GitPython/milestones) to see what's next. + 0.3.2 RC1 ========= * **git** command wrapper diff --git a/etc/sublime-text/git-python.sublime-project b/etc/sublime-text/git-python.sublime-project index 5d981925..d3b69289 100644 --- a/etc/sublime-text/git-python.sublime-project +++ b/etc/sublime-text/git-python.sublime-project @@ -35,37 +35,37 @@ "gitdb/ext" ] }, - // SMMAP - //////// - { - "follow_symlinks": true, - "path": "../../git/ext/gitdb/gitdb/ext/smmap", - "file_exclude_patterns" : [ - "*.sublime-workspace", - ".git", - ".noseids", - ".coverage" - ], - "folder_exclude_patterns" : [ - ".git", - "cover", - ] - }, - // ASYNC - //////// - { - "follow_symlinks": true, - "path": "../../git/ext/gitdb/gitdb/ext/async", - "file_exclude_patterns" : [ - "*.sublime-workspace", - ".git", - ".noseids", - ".coverage" - ], - "folder_exclude_patterns" : [ - ".git", - "cover", - ] - }, + // // SMMAP + // //////// + // { + // "follow_symlinks": true, + // "path": "../../git/ext/gitdb/gitdb/ext/smmap", + // "file_exclude_patterns" : [ + // "*.sublime-workspace", + // ".git", + // ".noseids", + // ".coverage" + // ], + // "folder_exclude_patterns" : [ + // ".git", + // "cover", + // ] + // }, + // // ASYNC + // //////// + // { + // "follow_symlinks": true, + // "path": "../../git/ext/gitdb/gitdb/ext/async", + // "file_exclude_patterns" : [ + // "*.sublime-workspace", + // ".git", + // ".noseids", + // ".coverage" + // ], + // "folder_exclude_patterns" : [ + // ".git", + // "cover", + // ] + // }, ] } @@ -74,6 +74,9 @@ class Git(LazyMixin): self.args = args def __del__(self): + self.proc.stdout.close() + self.proc.stderr.close() + # did the process finish already so we have a return code ? if self.proc.poll() is not None: return @@ -85,6 +88,8 @@ class Git(LazyMixin): # try to kill it try: os.kill(self.proc.pid, 2) # interrupt signal + except OSError: + pass # ignore error when process already died except AttributeError: # try windows # for some reason, providing None for stdout/stderr still prints something. This is why @@ -101,6 +106,8 @@ class Git(LazyMixin): :raise GitCommandError: if the return status is not 0""" status = self.proc.wait() + self.proc.stdout.close() + self.proc.stderr.close() if status != 0: raise GitCommandError(self.args, status, self.proc.stderr.read()) # END status handling @@ -236,7 +243,7 @@ class Git(LazyMixin): if attr == '_version_info': # We only use the first 4 numbers, as everthing else could be strings in fact (on windows) version_numbers = self._call_process('version').split(' ')[2] - self._version_info = tuple(int(n) for n in version_numbers.split('.')[:4]) + self._version_info = tuple(int(n) for n in version_numbers.split('.')[:4] if n.isdigit()) else: super(Git, self)._set_cache_(attr) #END handle version info @@ -316,6 +323,9 @@ class Git(LazyMixin): if ouput_stream is True, the stdout value will be your output stream: * output_stream if extended_output = False * tuple(int(status), output_stream, str(stderr)) if extended_output = True + + Note git is executed with LC_MESSAGES="C" to ensure consitent + output regardless of system language. :raise GitCommandError: @@ -333,6 +343,7 @@ class Git(LazyMixin): # Start the process proc = Popen(command, + env={"LC_MESSAGES": "C"}, cwd=cwd, stdin=istream, stderr=PIPE, @@ -380,7 +391,10 @@ class Git(LazyMixin): # END handle debug printing if with_exceptions and status != 0: - raise GitCommandError(command, status, stderr_value) + if with_extended_output: + raise GitCommandError(command, status, stderr_value, stdout_value) + else: + raise GitCommandError(command, status, stderr_value) # Allow access to the command's status code if with_extended_output: @@ -410,12 +424,16 @@ class Git(LazyMixin): @classmethod def __unpack_args(cls, arg_list): if not isinstance(arg_list, (list,tuple)): + if isinstance(arg_list, unicode): + return [arg_list.encode('utf-8')] return [ str(arg_list) ] outlist = list() for arg in arg_list: if isinstance(arg_list, (list, tuple)): outlist.extend(cls.__unpack_args( arg )) + elif isinstance(arg_list, unicode): + outlist.append(arg_list.encode('utf-8')) # END recursion else: outlist.append(str(arg)) @@ -17,14 +17,18 @@ class NoSuchPathError(OSError): class GitCommandError(Exception): """ Thrown if execution of the git command fails with non-zero status code. """ - def __init__(self, command, status, stderr=None): + def __init__(self, command, status, stderr=None, stdout=None): self.stderr = stderr + self.stdout = stdout self.status = status self.command = command def __str__(self): - return ("'%s' returned exit status %i: %s" % - (' '.join(str(i) for i in self.command), self.status, self.stderr)) + ret = "'%s' returned exit status %i: %s" % \ + (' '.join(str(i) for i in self.command), self.status, self.stderr) + if self.stdout is not None: + ret += "\nstdout: %s" % self.stdout + return ret class CheckoutError( Exception ): diff --git a/git/ext/gitdb b/git/ext/gitdb -Subproject 39de1127459b73b862f2b779bb4565ad6b4bd62 +Subproject 2f2fe4eea8ba4f47e63a7392a1f27f74f5ee925 diff --git a/git/repo/base.py b/git/repo/base.py index 71492fe8..933c8c82 100644 --- a/git/repo/base.py +++ b/git/repo/base.py @@ -376,7 +376,7 @@ class Repo(object): if rev is None: return self.head.commit else: - return self.rev_parse(str(rev)+"^0") + return self.rev_parse(unicode(rev)+"^0") def iter_trees(self, *args, **kwargs): """:return: Iterator yielding Tree objects @@ -399,7 +399,7 @@ class Repo(object): if rev is None: return self.head.commit.tree else: - return self.rev_parse(str(rev)+"^{tree}") + return self.rev_parse(unicode(rev)+"^{tree}") def iter_commits(self, rev=None, paths='', **kwargs): """A list of Commit objects representing the history of a given ref/commit @@ -499,8 +499,8 @@ class Repo(object): default_args = ('--abbrev=40', '--full-index', '--raw') if index: # diff index against HEAD - if isfile(self.index.path) and self.head.is_valid() and \ - len(self.git.diff('HEAD', '--cached', *default_args)): + if isfile(self.index.path) and \ + len(self.git.diff('--cached', *default_args)): return True # END index handling if working_tree: diff --git a/git/test/test_git.py b/git/test/test_git.py index e67cb92b..cdea1d3e 100644 --- a/git/test/test_git.py +++ b/git/test/test_git.py @@ -4,7 +4,7 @@ # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php -import os, sys +import os from git.test.lib import ( TestBase, patch, raises, @@ -16,7 +16,7 @@ from git import ( Git, GitCommandError ) class TestGit(TestBase): - + @classmethod def setUp(cls): super(TestGit, cls).setUp() @@ -29,6 +29,14 @@ class TestGit(TestBase): assert_true(git.called) assert_equal(git.call_args, ((['git', 'version'],), {})) + def test_call_unpack_args_unicode(self): + args = Git._Git__unpack_args(u'Unicode' + unichr(40960)) + assert_equal(args, ['Unicode\xea\x80\x80']) + + def test_call_unpack_args(self): + args = Git._Git__unpack_args(['git', 'log', '--', u'Unicode' + unichr(40960)]) + assert_equal(args, ['git', 'log', '--', 'Unicode\xea\x80\x80']) + @raises(GitCommandError) def test_it_raises_errors(self): self.git.this_does_not_exist() @@ -56,9 +64,9 @@ class TestGit(TestBase): @patch.object(Git, 'execute') def test_it_ignores_false_kwargs(self, git): # this_should_not_be_ignored=False implies it *should* be ignored - output = self.git.version(pass_this_kwarg=False) + self.git.version(pass_this_kwarg=False) assert_true("pass_this_kwarg" not in git.call_args[1]) - + def test_persistent_cat_file_command(self): # read header only import subprocess as sp @@ -67,37 +75,37 @@ class TestGit(TestBase): g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") g.stdin.flush() obj_info = g.stdout.readline() - + # read header + data g = self.git.cat_file(batch=True, istream=sp.PIPE,as_process=True) g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") g.stdin.flush() obj_info_two = g.stdout.readline() assert obj_info == obj_info_two - + # read data - have to read it in one large chunk size = int(obj_info.split()[2]) data = g.stdout.read(size) - terminating_newline = g.stdout.read(1) + g.stdout.read(1) # now we should be able to read a new object g.stdin.write("b2339455342180c7cc1e9bba3e9f181f7baa5167\n") g.stdin.flush() assert g.stdout.readline() == obj_info - - + + # same can be achived using the respective command functions hexsha, typename, size = self.git.get_object_header(hexsha) hexsha, typename_two, size_two, data = self.git.get_object_data(hexsha) assert typename == typename_two and size == size_two - + def test_version(self): v = self.git.version_info assert isinstance(v, tuple) for n in v: assert isinstance(n, int) #END verify number types - + def test_cmd_override(self): prev_cmd = self.git.GIT_PYTHON_GIT_EXECUTABLE try: diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..c9260b12 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +GitPython +gitdb>=0.6.0 @@ -16,6 +16,8 @@ v = open(path.join(path.dirname(__file__), 'VERSION')) VERSION = v.readline().strip() v.close() +with open('requirements.txt') as reqs_file: + requirements = reqs_file.read().splitlines() class build_py(_build_py): def run(self): @@ -61,6 +63,7 @@ def _stamp_version(filename): else: print >> sys.stderr, "WARNING: Couldn't find version line in file %s" % filename +install_requires = ('gitdb >= 0.6.0',) setup(name = "GitPython", cmdclass={'build_py': build_py, 'sdist': sdist}, version = VERSION, @@ -73,18 +76,35 @@ setup(name = "GitPython", package_data = {'git.test' : ['fixtures/*']}, package_dir = {'git':'git'}, license = "BSD License", - install_requires='gitdb >= 0.5.1', + requires=('gitdb (>=0.6.0)', ), + install_requires=install_requires, + test_requirements = ('mock', 'nose') + install_requires, zip_safe=False, long_description = """\ GitPython is a python library used to interact with Git repositories""", - classifiers = [ + classifiers=[ + # Picked from + # http://pypi.python.org/pypi?:action=list_classifiers + #"Development Status :: 1 - Planning", + #"Development Status :: 2 - Pre-Alpha", + #"Development Status :: 3 - Alpha", "Development Status :: 4 - Beta", + # "Development Status :: 5 - Production/Stable", + #"Development Status :: 6 - Mature", + #"Development Status :: 7 - Inactive", + "Environment :: Console", "Intended Audience :: Developers", "License :: OSI Approved :: BSD License", "Operating System :: OS Independent", + "Operating System :: POSIX", + "Operating System :: Microsoft :: Windows", + "Operating System :: MacOS :: MacOS X", "Programming Language :: Python", - "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.6", - "Topic :: Software Development :: Libraries :: Python Modules", - ] + "Programming Language :: Python :: 2.7", + # "Programming Language :: Python :: 3", + # "Programming Language :: Python :: 3.3", + # "Programming Language :: Python :: 3.4", + ] ) diff --git a/test-requirements.txt b/test-requirements.txt new file mode 100644 index 00000000..d9425c03 --- /dev/null +++ b/test-requirements.txt @@ -0,0 +1,4 @@ +coverage +flake8 +nose +mock diff --git a/tox.ini b/tox.ini new file mode 100644 index 00000000..60bfb1d9 --- /dev/null +++ b/tox.ini @@ -0,0 +1,20 @@ +[tox] +envlist = py26,py27,flake8 + +[testenv] +commands = nosetests +deps = -r{toxinidir}/requirements.txt + -r{toxinidir}/test-requirements.txt + +[testenv:cover] +commands = nosetests --with-coverage + +[testenv:flake8] +commands = flake8 + +[testenv:venv] +commands = {posargs} + +[flake8] +#show-source = True +exclude = .tox,.venv,build,dist,doc,git/ext/ |