diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2009-10-11 16:49:05 +0200 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2009-10-11 16:49:05 +0200 |
commit | 9374a916588d9fe7169937ba262c86ad710cfa74 (patch) | |
tree | dfe77a02cfa3fbe34563326cea95e92694d21b9a | |
parent | 20f202d83bdf1f332a3cb8f010bcf8bf3c2807bd (diff) | |
download | gitpython-9374a916588d9fe7169937ba262c86ad710cfa74.tar.gz |
converted all spaces to tabs ( 4 spaces = 1 tab ) just to allow me and my editor to work with the files properly. Can convert it back for releaes
-rw-r--r-- | ez_setup.py | 322 | ||||
-rw-r--r-- | lib/git/__init__.py | 2 | ||||
-rw-r--r-- | lib/git/actor.py | 74 | ||||
-rw-r--r-- | lib/git/base.py | 488 | ||||
-rw-r--r-- | lib/git/blob.py | 306 | ||||
-rw-r--r-- | lib/git/cmd.py | 388 | ||||
-rw-r--r-- | lib/git/commit.py | 556 | ||||
-rw-r--r-- | lib/git/diff.py | 140 | ||||
-rw-r--r-- | lib/git/errors.py | 32 | ||||
-rw-r--r-- | lib/git/head.py | 106 | ||||
-rw-r--r-- | lib/git/repo.py | 918 | ||||
-rw-r--r-- | lib/git/stats.py | 102 | ||||
-rw-r--r-- | lib/git/tag.py | 224 | ||||
-rw-r--r-- | lib/git/tree.py | 188 | ||||
-rw-r--r-- | lib/git/utils.py | 24 | ||||
-rw-r--r-- | setup.py | 106 | ||||
-rw-r--r-- | test/git/test_actor.py | 28 | ||||
-rw-r--r-- | test/git/test_blob.py | 158 | ||||
-rw-r--r-- | test/git/test_commit.py | 394 | ||||
-rw-r--r-- | test/git/test_diff.py | 30 | ||||
-rw-r--r-- | test/git/test_git.py | 94 | ||||
-rw-r--r-- | test/git/test_head.py | 38 | ||||
-rw-r--r-- | test/git/test_repo.py | 402 | ||||
-rw-r--r-- | test/git/test_stats.py | 34 | ||||
-rw-r--r-- | test/git/test_tree.py | 234 | ||||
-rw-r--r-- | test/git/test_utils.py | 18 | ||||
-rw-r--r-- | test/testlib/__init__.py | 2 | ||||
-rw-r--r-- | test/testlib/asserts.py | 30 | ||||
-rw-r--r-- | test/testlib/helper.py | 8 |
29 files changed, 2723 insertions, 2723 deletions
diff --git a/ez_setup.py b/ez_setup.py index 3031ad0d..50d0075b 100644 --- a/ez_setup.py +++ b/ez_setup.py @@ -4,8 +4,8 @@ If you want to use setuptools in your package's setup.py, just include this file in the same directory with it, and add this to the top of your setup.py:: - from ez_setup import use_setuptools - use_setuptools() + from ez_setup import use_setuptools + use_setuptools() If you want to require a specific version of setuptools, set a download mirror, or use an alternate download directory, you can do so by supplying @@ -15,106 +15,106 @@ This file can also be run as a script to install or upgrade setuptools. """ import sys DEFAULT_VERSION = "0.6c3" -DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] +DEFAULT_URL = "http://cheeseshop.python.org/packages/%s/s/setuptools/" % sys.version[:3] md5_data = { - 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', - 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', - 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', - 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', - 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', - 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', - 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', - 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', - 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', - 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', - 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', - 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', - 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', - 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', - 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', + 'setuptools-0.6b1-py2.3.egg': '8822caf901250d848b996b7f25c6e6ca', + 'setuptools-0.6b1-py2.4.egg': 'b79a8a403e4502fbb85ee3f1941735cb', + 'setuptools-0.6b2-py2.3.egg': '5657759d8a6d8fc44070a9d07272d99b', + 'setuptools-0.6b2-py2.4.egg': '4996a8d169d2be661fa32a6e52e4f82a', + 'setuptools-0.6b3-py2.3.egg': 'bb31c0fc7399a63579975cad9f5a0618', + 'setuptools-0.6b3-py2.4.egg': '38a8c6b3d6ecd22247f179f7da669fac', + 'setuptools-0.6b4-py2.3.egg': '62045a24ed4e1ebc77fe039aa4e6f7e5', + 'setuptools-0.6b4-py2.4.egg': '4cb2a185d228dacffb2d17f103b3b1c4', + 'setuptools-0.6c1-py2.3.egg': 'b3f2b5539d65cb7f74ad79127f1a908c', + 'setuptools-0.6c1-py2.4.egg': 'b45adeda0667d2d2ffe14009364f2a4b', + 'setuptools-0.6c2-py2.3.egg': 'f0064bf6aa2b7d0f3ba0b43f20817c27', + 'setuptools-0.6c2-py2.4.egg': '616192eec35f47e8ea16cd6a122b7277', + 'setuptools-0.6c3-py2.3.egg': 'f181fa125dfe85a259c9cd6f1d7b78fa', + 'setuptools-0.6c3-py2.4.egg': 'e0ed74682c998bfb73bf803a50e7b71e', + 'setuptools-0.6c3-py2.5.egg': 'abef16fdd61955514841c7c6bd98965e', } import sys, os def _validate_md5(egg_name, data): - if egg_name in md5_data: - from md5 import md5 - digest = md5(data).hexdigest() - if digest != md5_data[egg_name]: - print >>sys.stderr, ( - "md5 validation of %s failed! (Possible download problem?)" - % egg_name - ) - sys.exit(2) - return data + if egg_name in md5_data: + from md5 import md5 + digest = md5(data).hexdigest() + if digest != md5_data[egg_name]: + print >>sys.stderr, ( + "md5 validation of %s failed! (Possible download problem?)" + % egg_name + ) + sys.exit(2) + return data def use_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - download_delay=15 + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + download_delay=15 ): - """Automatically find/download setuptools and make it available on sys.path - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end with - a '/'). `to_dir` is the directory where setuptools will be downloaded, if - it is not already available. If `download_delay` is specified, it should - be the number of seconds that will be paused before initiating a download, - should one be required. If an older version of setuptools is installed, - this routine will print a message to ``sys.stderr`` and raise SystemExit in - an attempt to abort the calling script. - """ - try: - import setuptools - if setuptools.__version__ == '0.0.1': - print >>sys.stderr, ( - "You have an obsolete version of setuptools installed. Please\n" - "remove it from your system entirely before rerunning this script." - ) - sys.exit(2) - except ImportError: - egg = download_setuptools(version, download_base, to_dir, download_delay) - sys.path.insert(0, egg) - import setuptools; setuptools.bootstrap_install_from = egg - - import pkg_resources - try: - pkg_resources.require("setuptools>="+version) - - except pkg_resources.VersionConflict, e: - # XXX could we install in a subprocess here? - print >>sys.stderr, ( - "The required version of setuptools (>=%s) is not available, and\n" - "can't be installed while this script is running. Please install\n" - " a more recent version first.\n\n(Currently using %r)" - ) % (version, e.args[0]) - sys.exit(2) + """Automatically find/download setuptools and make it available on sys.path + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end with + a '/'). `to_dir` is the directory where setuptools will be downloaded, if + it is not already available. If `download_delay` is specified, it should + be the number of seconds that will be paused before initiating a download, + should one be required. If an older version of setuptools is installed, + this routine will print a message to ``sys.stderr`` and raise SystemExit in + an attempt to abort the calling script. + """ + try: + import setuptools + if setuptools.__version__ == '0.0.1': + print >>sys.stderr, ( + "You have an obsolete version of setuptools installed. Please\n" + "remove it from your system entirely before rerunning this script." + ) + sys.exit(2) + except ImportError: + egg = download_setuptools(version, download_base, to_dir, download_delay) + sys.path.insert(0, egg) + import setuptools; setuptools.bootstrap_install_from = egg + + import pkg_resources + try: + pkg_resources.require("setuptools>="+version) + + except pkg_resources.VersionConflict, e: + # XXX could we install in a subprocess here? + print >>sys.stderr, ( + "The required version of setuptools (>=%s) is not available, and\n" + "can't be installed while this script is running. Please install\n" + " a more recent version first.\n\n(Currently using %r)" + ) % (version, e.args[0]) + sys.exit(2) def download_setuptools( - version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, - delay = 15 + version=DEFAULT_VERSION, download_base=DEFAULT_URL, to_dir=os.curdir, + delay = 15 ): - """Download setuptools from a specified location and return its filename - - `version` should be a valid setuptools version number that is available - as an egg for download under the `download_base` URL (which should end - with a '/'). `to_dir` is the directory where the egg will be downloaded. - `delay` is the number of seconds to pause before an actual download attempt. - """ - import urllib2, shutil - egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) - url = download_base + egg_name - saveto = os.path.join(to_dir, egg_name) - src = dst = None - if not os.path.exists(saveto): # Avoid repeated downloads - try: - from distutils import log - if delay: - log.warn(""" + """Download setuptools from a specified location and return its filename + + `version` should be a valid setuptools version number that is available + as an egg for download under the `download_base` URL (which should end + with a '/'). `to_dir` is the directory where the egg will be downloaded. + `delay` is the number of seconds to pause before an actual download attempt. + """ + import urllib2, shutil + egg_name = "setuptools-%s-py%s.egg" % (version,sys.version[:3]) + url = download_base + egg_name + saveto = os.path.join(to_dir, egg_name) + src = dst = None + if not os.path.exists(saveto): # Avoid repeated downloads + try: + from distutils import log + if delay: + log.warn(""" --------------------------------------------------------------------------- This script requires setuptools version %s to run (even to display -help). I will attempt to download it for you (from +help). I will attempt to download it for you (from %s), but you may need to enable firewall access for this script first. I will start the download in %d seconds. @@ -125,96 +125,96 @@ I will start the download in %d seconds. and place it in this directory before rerunning this script.) ---------------------------------------------------------------------------""", - version, download_base, delay, url - ); from time import sleep; sleep(delay) - log.warn("Downloading %s", url) - src = urllib2.urlopen(url) - # Read/write all in one block, so we don't create a corrupt file - # if the download is interrupted. - data = _validate_md5(egg_name, src.read()) - dst = open(saveto,"wb"); dst.write(data) - finally: - if src: src.close() - if dst: dst.close() - return os.path.realpath(saveto) + version, download_base, delay, url + ); from time import sleep; sleep(delay) + log.warn("Downloading %s", url) + src = urllib2.urlopen(url) + # Read/write all in one block, so we don't create a corrupt file + # if the download is interrupted. + data = _validate_md5(egg_name, src.read()) + dst = open(saveto,"wb"); dst.write(data) + finally: + if src: src.close() + if dst: dst.close() + return os.path.realpath(saveto) def main(argv, version=DEFAULT_VERSION): - """Install or upgrade setuptools and EasyInstall""" - - try: - import setuptools - except ImportError: - egg = None - try: - egg = download_setuptools(version, delay=0) - sys.path.insert(0,egg) - from setuptools.command.easy_install import main - return main(list(argv)+[egg]) # we're done here - finally: - if egg and os.path.exists(egg): - os.unlink(egg) - else: - if setuptools.__version__ == '0.0.1': - # tell the user to uninstall obsolete version - use_setuptools(version) - - req = "setuptools>="+version - import pkg_resources - try: - pkg_resources.require(req) - except pkg_resources.VersionConflict: - try: - from setuptools.command.easy_install import main - except ImportError: - from easy_install import main - main(list(argv)+[download_setuptools(delay=0)]) - sys.exit(0) # try to force an exit - else: - if argv: - from setuptools.command.easy_install import main - main(argv) - else: - print "Setuptools version",version,"or greater has been installed." - print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' + """Install or upgrade setuptools and EasyInstall""" + + try: + import setuptools + except ImportError: + egg = None + try: + egg = download_setuptools(version, delay=0) + sys.path.insert(0,egg) + from setuptools.command.easy_install import main + return main(list(argv)+[egg]) # we're done here + finally: + if egg and os.path.exists(egg): + os.unlink(egg) + else: + if setuptools.__version__ == '0.0.1': + # tell the user to uninstall obsolete version + use_setuptools(version) + + req = "setuptools>="+version + import pkg_resources + try: + pkg_resources.require(req) + except pkg_resources.VersionConflict: + try: + from setuptools.command.easy_install import main + except ImportError: + from easy_install import main + main(list(argv)+[download_setuptools(delay=0)]) + sys.exit(0) # try to force an exit + else: + if argv: + from setuptools.command.easy_install import main + main(argv) + else: + print "Setuptools version",version,"or greater has been installed." + print '(Run "ez_setup.py -U setuptools" to reinstall or upgrade.)' def update_md5(filenames): - """Update our built-in md5 registry""" + """Update our built-in md5 registry""" - import re - from md5 import md5 + import re + from md5 import md5 - for name in filenames: - base = os.path.basename(name) - f = open(name,'rb') - md5_data[base] = md5(f.read()).hexdigest() - f.close() + for name in filenames: + base = os.path.basename(name) + f = open(name,'rb') + md5_data[base] = md5(f.read()).hexdigest() + f.close() - data = [" %r: %r,\n" % it for it in md5_data.items()] - data.sort() - repl = "".join(data) + data = [" %r: %r,\n" % it for it in md5_data.items()] + data.sort() + repl = "".join(data) - import inspect - srcfile = inspect.getsourcefile(sys.modules[__name__]) - f = open(srcfile, 'rb'); src = f.read(); f.close() + import inspect + srcfile = inspect.getsourcefile(sys.modules[__name__]) + f = open(srcfile, 'rb'); src = f.read(); f.close() - match = re.search("\nmd5_data = {\n([^}]+)}", src) - if not match: - print >>sys.stderr, "Internal error!" - sys.exit(2) + match = re.search("\nmd5_data = {\n([^}]+)}", src) + if not match: + print >>sys.stderr, "Internal error!" + sys.exit(2) - src = src[:match.start(1)] + repl + src[match.end(1):] - f = open(srcfile,'w') - f.write(src) - f.close() + src = src[:match.start(1)] + repl + src[match.end(1):] + f = open(srcfile,'w') + f.write(src) + f.close() if __name__=='__main__': - if len(sys.argv)>2 and sys.argv[1]=='--md5update': - update_md5(sys.argv[2:]) - else: - main(sys.argv[1:]) + if len(sys.argv)>2 and sys.argv[1]=='--md5update': + update_md5(sys.argv[2:]) + else: + main(sys.argv[1:]) diff --git a/lib/git/__init__.py b/lib/git/__init__.py index 28d14d0c..45cb4673 100644 --- a/lib/git/__init__.py +++ b/lib/git/__init__.py @@ -24,4 +24,4 @@ from git.utils import dashify from git.utils import touch __all__ = [ name for name, obj in locals().items() - if not (name.startswith('_') or inspect.ismodule(obj)) ] + if not (name.startswith('_') or inspect.ismodule(obj)) ] diff --git a/lib/git/actor.py b/lib/git/actor.py index 28f50e73..f1aeda9b 100644 --- a/lib/git/actor.py +++ b/lib/git/actor.py @@ -7,40 +7,40 @@ import re class Actor(object): - """Actors hold information about a person acting on the repository. They - can be committers and authors or anything with a name and an email as - mentioned in the git log entries.""" - # precompiled regex - name_only_regex = re.compile( r'<.+>' ) - name_email_regex = re.compile( r'(.*) <(.+?)>' ) - - def __init__(self, name, email): - self.name = name - self.email = email - - def __str__(self): - return self.name - - def __repr__(self): - return '<git.Actor "%s <%s>">' % (self.name, self.email) - - @classmethod - def from_string(cls, string): - """ - Create an Actor from a string. - - ``str`` - is the string, which is expected to be in regular git format - - Format - John Doe <jdoe@example.com> - - Returns - Actor - """ - if cls.name_only_regex.search(string): - m = cls.name_email_regex.search(string) - name, email = m.groups() - return Actor(name, email) - else: - return Actor(string, None) + """Actors hold information about a person acting on the repository. They + can be committers and authors or anything with a name and an email as + mentioned in the git log entries.""" + # precompiled regex + name_only_regex = re.compile( r'<.+>' ) + name_email_regex = re.compile( r'(.*) <(.+?)>' ) + + def __init__(self, name, email): + self.name = name + self.email = email + + def __str__(self): + return self.name + + def __repr__(self): + return '<git.Actor "%s <%s>">' % (self.name, self.email) + + @classmethod + def from_string(cls, string): + """ + Create an Actor from a string. + + ``str`` + is the string, which is expected to be in regular git format + + Format + John Doe <jdoe@example.com> + + Returns + Actor + """ + if cls.name_only_regex.search(string): + m = cls.name_email_regex.search(string) + name, email = m.groups() + return Actor(name, email) + else: + return Actor(string, None) diff --git a/lib/git/base.py b/lib/git/base.py index 84dd0754..1f8e085d 100644 --- a/lib/git/base.py +++ b/lib/git/base.py @@ -6,249 +6,249 @@ import os class LazyMixin(object): - lazy_properties = [] - - __slots__ = "__baked__" - - def __init__(self): - self.__baked__ = False - - def __getattribute__(self, attr): - val = object.__getattribute__(self, attr) - if val is not None: - return val - else: - self.__prebake__() - return object.__getattribute__(self, attr) - - def __bake__(self): - """ This method should be overridden in the derived class. """ - raise NotImplementedError(" '__bake__' method has not been implemented.") - - def __prebake__(self): - if self.__baked__: - return - self.__bake__() - self.__baked__ = True - - def __bake_it__(self): - self.__baked__ = True - - + lazy_properties = [] + + __slots__ = "__baked__" + + def __init__(self): + self.__baked__ = False + + def __getattribute__(self, attr): + val = object.__getattribute__(self, attr) + if val is not None: + return val + else: + self.__prebake__() + return object.__getattribute__(self, attr) + + def __bake__(self): + """ This method should be overridden in the derived class. """ + raise NotImplementedError(" '__bake__' method has not been implemented.") + + def __prebake__(self): + if self.__baked__: + return + self.__bake__() + self.__baked__ = True + + def __bake_it__(self): + self.__baked__ = True + + class Object(LazyMixin): - """ - Implements an Object which may be Blobs, Trees, Commits and Tags - """ - TYPES = ("blob", "tree", "commit", "tag") - __slots__ = ("repo", "id", "size") - type = None # to be set by subclass - - def __init__(self, repo, id, size=None): - """ - Initialize an object by identifying it by its id. All keyword arguments - will be set on demand if None. - - ``repo`` - repository this object is located in - - ``id`` - SHA1 or ref suitable for git-rev-parse - - ``size`` - Size of the object's data in bytes - """ - super(Object,self).__init__() - self.repo = repo - self.id = id - self.size = size - - def __bake__(self): - """ - Retrieve object information - """ - self.size = int(self.repo.git.cat_file(self.id, s=True).rstrip()) - - def __eq__(self, other): - """ - Returns - True if the objects have the same SHA1 - """ - return self.id == other.id - - def __ne__(self, other): - """ - Returns - True if the objects do not have the same SHA1 - """ - return self.id != other.id - - def __hash__(self): - """ - Returns - Hash of our id allowing objects to be used in dicts and sets - """ - return hash(self.id) - - def __str__(self): - """ - Returns - string of our SHA1 as understood by all git commands - """ - return self.id - - def __repr__(self): - """ - Returns - string with pythonic representation of our object - """ - return '<git.%s "%s">' % (self.__class__.__name__, self.id) - - @classmethod - def get_type_by_name(cls, object_type_name): - """ - Returns - type suitable to handle the given object type name. - Use the type to create new instances. - - ``object_type_name`` - Member of TYPES - - Raises - ValueError: In case object_type_name is unknown - """ - if object_type_name == "commit": - import commit - return commit.Commit - elif object_type_name == "tag": - import tag - return tag.TagObject - elif object_type_name == "blob": - import blob - return blob.Blob - elif object_type_name == "tree": - import tree - return tree.Tree - else: - raise ValueError("Cannot handle unknown object type: %s" % object_type_name) - - + """ + Implements an Object which may be Blobs, Trees, Commits and Tags + """ + TYPES = ("blob", "tree", "commit", "tag") + __slots__ = ("repo", "id", "size") + type = None # to be set by subclass + + def __init__(self, repo, id, size=None): + """ + Initialize an object by identifying it by its id. All keyword arguments + will be set on demand if None. + + ``repo`` + repository this object is located in + + ``id`` + SHA1 or ref suitable for git-rev-parse + + ``size`` + Size of the object's data in bytes + """ + super(Object,self).__init__() + self.repo = repo + self.id = id + self.size = size + + def __bake__(self): + """ + Retrieve object information + """ + self.size = int(self.repo.git.cat_file(self.id, s=True).rstrip()) + + def __eq__(self, other): + """ + Returns + True if the objects have the same SHA1 + """ + return self.id == other.id + + def __ne__(self, other): + """ + Returns + True if the objects do not have the same SHA1 + """ + return self.id != other.id + + def __hash__(self): + """ + Returns + Hash of our id allowing objects to be used in dicts and sets + """ + return hash(self.id) + + def __str__(self): + """ + Returns + string of our SHA1 as understood by all git commands + """ + return self.id + + def __repr__(self): + """ + Returns + string with pythonic representation of our object + """ + return '<git.%s "%s">' % (self.__class__.__name__, self.id) + + @classmethod + def get_type_by_name(cls, object_type_name): + """ + Returns + type suitable to handle the given object type name. + Use the type to create new instances. + + ``object_type_name`` + Member of TYPES + + Raises + ValueError: In case object_type_name is unknown + """ + if object_type_name == "commit": + import commit + return commit.Commit + elif object_type_name == "tag": + import tag + return tag.TagObject + elif object_type_name == "blob": + import blob + return blob.Blob + elif object_type_name == "tree": + import tree + return tree.Tree + else: + raise ValueError("Cannot handle unknown object type: %s" % object_type_name) + + class Ref(object): - """ - Represents a named reference to any object - """ - __slots__ = ("path", "object") - - def __init__(self, path, object = None): - """ - Initialize this instance - - ``path`` - Path relative to the .git/ directory pointing to the ref in question, i.e. - refs/heads/master - - ``object`` - Object instance, will be retrieved on demand if None - """ - self.path = path - self.object = object - - def __str__(self): - return self.name() - - def __repr__(self): - return '<git.%s "%s">' % (self.__class__.__name__, self.path) - - def __eq__(self, other): - return self.path == other.path and self.object == other.object - - def __ne__(self, other): - return not ( self == other ) - - def __hash__(self): - return hash(self.path) - - @property - def name(self): - """ - Returns - Name of this reference - """ - return os.path.basename(self.path) - - @classmethod - def find_all(cls, repo, common_path = "refs", **kwargs): - """ - Find all refs in the repository - - ``repo`` - is the Repo - - ``common_path`` - Optional keyword argument to the path which is to be shared by all - returned Ref objects - - ``kwargs`` - Additional options given as keyword arguments, will be passed - to git-for-each-ref - - Returns - git.Ref[] - - List is sorted by committerdate - The returned objects are compatible to the Ref base, but represent the - actual type, such as Head or Tag - """ - - options = {'sort': "committerdate", - 'format': "%(refname)%00%(objectname)%00%(objecttype)%00%(objectsize)"} - - options.update(kwargs) - - output = repo.git.for_each_ref(common_path, **options) - return cls.list_from_string(repo, output) - - @classmethod - def list_from_string(cls, repo, text): - """ - Parse out ref information into a list of Ref compatible objects - - ``repo`` - is the Repo - ``text`` - is the text output from the git-for-each-ref command - - Returns - git.Ref[] - - list of Ref objects - """ - heads = [] - - for line in text.splitlines(): - heads.append(cls.from_string(repo, line)) - - return heads - - @classmethod - def from_string(cls, repo, line): - """ - Create a new Ref instance from the given string. - - ``repo`` - is the Repo - - ``line`` - is the formatted ref information - - Format:: - - name: [a-zA-Z_/]+ - <null byte> - id: [0-9A-Fa-f]{40} - - Returns - git.Head - """ - full_path, hexsha, type_name, object_size = line.split("\x00") - obj = Object.get_type_by_name(type_name)(repo, hexsha, object_size) - return cls(full_path, obj) + """ + Represents a named reference to any object + """ + __slots__ = ("path", "object") + + def __init__(self, path, object = None): + """ + Initialize this instance + + ``path`` + Path relative to the .git/ directory pointing to the ref in question, i.e. + refs/heads/master + + ``object`` + Object instance, will be retrieved on demand if None + """ + self.path = path + self.object = object + + def __str__(self): + return self.name() + + def __repr__(self): + return '<git.%s "%s">' % (self.__class__.__name__, self.path) + + def __eq__(self, other): + return self.path == other.path and self.object == other.object + + def __ne__(self, other): + return not ( self == other ) + + def __hash__(self): + return hash(self.path) + + @property + def name(self): + """ + Returns + Name of this reference + """ + return os.path.basename(self.path) + + @classmethod + def find_all(cls, repo, common_path = "refs", **kwargs): + """ + Find all refs in the repository + + ``repo`` + is the Repo + + ``common_path`` + Optional keyword argument to the path which is to be shared by all + returned Ref objects + + ``kwargs`` + Additional options given as keyword arguments, will be passed + to git-for-each-ref + + Returns + git.Ref[] + + List is sorted by committerdate + The returned objects are compatible to the Ref base, but represent the + actual type, such as Head or Tag + """ + + options = {'sort': "committerdate", + 'format': "%(refname)%00%(objectname)%00%(objecttype)%00%(objectsize)"} + + options.update(kwargs) + + output = repo.git.for_each_ref(common_path, **options) + return cls.list_from_string(repo, output) + + @classmethod + def list_from_string(cls, repo, text): + """ + Parse out ref information into a list of Ref compatible objects + + ``repo`` + is the Repo + ``text`` + is the text output from the git-for-each-ref command + + Returns + git.Ref[] + + list of Ref objects + """ + heads = [] + + for line in text.splitlines(): + heads.append(cls.from_string(repo, line)) + + return heads + + @classmethod + def from_string(cls, repo, line): + """ + Create a new Ref instance from the given string. + + ``repo`` + is the Repo + + ``line`` + is the formatted ref information + + Format:: + + name: [a-zA-Z_/]+ + <null byte> + id: [0-9A-Fa-f]{40} + + Returns + git.Head + """ + full_path, hexsha, type_name, object_size = line.split("\x00") + obj = Object.get_type_by_name(type_name)(repo, hexsha, object_size) + return cls(full_path, obj) diff --git a/lib/git/blob.py b/lib/git/blob.py index 3ecd3a38..d1b928cd 100644 --- a/lib/git/blob.py +++ b/lib/git/blob.py @@ -13,159 +13,159 @@ from commit import Commit import base class Blob(base.Object): - """A Blob encapsulates a git blob object""" - DEFAULT_MIME_TYPE = "text/plain" - type = "blob" - __slots__ = ("mode", "path", "_data_stored") - - # precompiled regex - re_whitespace = re.compile(r'\s+') - re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') - re_author_committer_start = re.compile(r'^(author|committer)') - re_tab_full_line = re.compile(r'^\t(.*)$') - - def __init__(self, repo, id, mode=None, path=None): - """ - Create an unbaked Blob containing just the specified attributes - - ``repo`` - is the Repo - - ``id`` - is the git object id - - ``mode`` - is the file mode - - ``path`` - is the path to the file - - Returns - git.Blob - """ - super(Blob,self).__init__(repo, id, "blob") - self.mode = mode - self.path = path - self._data_stored = None - - @property - def data(self): - """ - The binary contents of this blob. - - Returns - str - - NOTE - The data will be cached after the first access. - """ - self._data_stored = self._data_stored or self.repo.git.cat_file(self.id, p=True, with_raw_output=True) - return self._data_stored - - @property - def mime_type(self): - """ - The mime type of this file (based on the filename) - - Returns - str - - NOTE - Defaults to 'text/plain' in case the actual file type is unknown. - """ - guesses = None - if self.path: - guesses = mimetypes.guess_type(self.path) - return guesses and guesses[0] or self.DEFAULT_MIME_TYPE - - @property - def basename(self): - """ - Returns - The basename of the Blobs file path - """ - return os.path.basename(self.path) - - @classmethod - def blame(cls, repo, commit, file): - """ - The blame information for the given file at the given commit - - Returns - list: [git.Commit, list: [<line>]] - A list of tuples associating a Commit object with a list of lines that - changed within the given commit. The Commit objects will be given in order - of appearance. - """ - data = repo.git.blame(commit, '--', file, p=True) - commits = {} - blames = [] - info = None - - for line in data.splitlines(): - parts = cls.re_whitespace.split(line, 1) - firstpart = parts[0] - if cls.re_hexsha_only.search(firstpart): - # handles - # 634396b2f541a9f2d58b00be1a07f0c358b999b3 1 1 7 - indicates blame-data start - # 634396b2f541a9f2d58b00be1a07f0c358b999b3 2 2 - digits = parts[-1].split(" ") - if len(digits) == 3: + """A Blob encapsulates a git blob object""" + DEFAULT_MIME_TYPE = "text/plain" + type = "blob" + __slots__ = ("mode", "path", "_data_stored") + + # precompiled regex + re_whitespace = re.compile(r'\s+') + re_hexsha_only = re.compile('^[0-9A-Fa-f]{40}$') + re_author_committer_start = re.compile(r'^(author|committer)') + re_tab_full_line = re.compile(r'^\t(.*)$') + + def __init__(self, repo, id, mode=None, path=None): + """ + Create an unbaked Blob containing just the specified attributes + + ``repo`` + is the Repo + + ``id`` + is the git object id + + ``mode`` + is the file mode + + ``path`` + is the path to the file + + Returns + git.Blob + """ + super(Blob,self).__init__(repo, id, "blob") + self.mode = mode + self.path = path + self._data_stored = None + + @property + def data(self): + """ + The binary contents of this blob. + + Returns + str + + NOTE + The data will be cached after the first access. + """ + self._data_stored = self._data_stored or self.repo.git.cat_file(self.id, p=True, with_raw_output=True) + return self._data_stored + + @property + def mime_type(self): + """ + The mime type of this file (based on the filename) + + Returns + str + + NOTE + Defaults to 'text/plain' in case the actual file type is unknown. + """ + guesses = None + if self.path: + guesses = mimetypes.guess_type(self.path) + return guesses and guesses[0] or self.DEFAULT_MIME_TYPE + + @property + def basename(self): + """ + Returns + The basename of the Blobs file path + """ + return os.path.basename(self.path) + + @classmethod + def blame(cls, repo, commit, file): + """ + The blame information for the given file at the given commit + + Returns + list: [git.Commit, list: [<line>]] + A list of tuples associating a Commit object with a list of lines that + changed within the given commit. The Commit objects will be given in order + of appearance. + """ + data = repo.git.blame(commit, '--', file, p=True) + commits = {} + blames = [] + info = None + + for line in data.splitlines(): + parts = cls.re_whitespace.split(line, 1) + firstpart = parts[0] + if cls.re_hexsha_only.search(firstpart): + # handles + # 634396b2f541a9f2d58b00be1a07f0c358b999b3 1 1 7 - indicates blame-data start + # 634396b2f541a9f2d58b00be1a07f0c358b999b3 2 2 + digits = parts[-1].split(" ") + if len(digits) == 3: info = {'id': firstpart} blames.append([None, []]) # END blame data initialization - else: - m = cls.re_author_committer_start.search(firstpart) - if m: - # handles: - # author Tom Preston-Werner - # author-mail <tom@mojombo.com> - # author-time 1192271832 - # author-tz -0700 - # committer Tom Preston-Werner - # committer-mail <tom@mojombo.com> - # committer-time 1192271832 - # committer-tz -0700 - IGNORED BY US - role = m.group(0) - if firstpart.endswith('-mail'): - info["%s_email" % role] = parts[-1] - elif firstpart.endswith('-time'): - info["%s_date" % role] = time.gmtime(int(parts[-1])) - elif role == firstpart: - info[role] = parts[-1] - # END distinguish mail,time,name - else: - # handle - # filename lib/grit.rb - # summary add Blob - # <and rest> - if firstpart.startswith('filename'): - info['filename'] = parts[-1] - elif firstpart.startswith('summary'): - info['summary'] = parts[-1] - elif firstpart == '': - if info: - sha = info['id'] - c = commits.get(sha) - if c is None: - c = Commit( repo, id=sha, - author=Actor.from_string(info['author'] + ' ' + info['author_email']), - authored_date=info['author_date'], - committer=Actor.from_string(info['committer'] + ' ' + info['committer_email']), - committed_date=info['committer_date'], - message=info['summary']) - commits[sha] = c - # END if commit objects needs initial creation - m = cls.re_tab_full_line.search(line) - text, = m.groups() - blames[-1][0] = c - blames[-1][1].append( text ) - info = None - # END if we collected commit info - # END distinguish filename,summary,rest - # END distinguish author|committer vs filename,summary,rest - # END distinguish hexsha vs other information - return blames - - def __repr__(self): - return '<git.Blob "%s">' % self.id + else: + m = cls.re_author_committer_start.search(firstpart) + if m: + # handles: + # author Tom Preston-Werner + # author-mail <tom@mojombo.com> + # author-time 1192271832 + # author-tz -0700 + # committer Tom Preston-Werner + # committer-mail <tom@mojombo.com> + # committer-time 1192271832 + # committer-tz -0700 - IGNORED BY US + role = m.group(0) + if firstpart.endswith('-mail'): + info["%s_email" % role] = parts[-1] + elif firstpart.endswith('-time'): + info["%s_date" % role] = time.gmtime(int(parts[-1])) + elif role == firstpart: + info[role] = parts[-1] + # END distinguish mail,time,name + else: + # handle + # filename lib/grit.rb + # summary add Blob + # <and rest> + if firstpart.startswith('filename'): + info['filename'] = parts[-1] + elif firstpart.startswith('summary'): + info['summary'] = parts[-1] + elif firstpart == '': + if info: + sha = info['id'] + c = commits.get(sha) + if c is None: + c = Commit( repo, id=sha, + author=Actor.from_string(info['author'] + ' ' + info['author_email']), + authored_date=info['author_date'], + committer=Actor.from_string(info['committer'] + ' ' + info['committer_email']), + committed_date=info['committer_date'], + message=info['summary']) + commits[sha] = c + # END if commit objects needs initial creation + m = cls.re_tab_full_line.search(line) + text, = m.groups() + blames[-1][0] = c + blames[-1][1].append( text ) + info = None + # END if we collected commit info + # END distinguish filename,summary,rest + # END distinguish author|committer vs filename,summary,rest + # END distinguish hexsha vs other information + return blames + + def __repr__(self): + return '<git.Blob "%s">' % self.id diff --git a/lib/git/cmd.py b/lib/git/cmd.py index 21e235b1..940e35d1 100644 --- a/lib/git/cmd.py +++ b/lib/git/cmd.py @@ -13,208 +13,208 @@ from errors import GitCommandError GIT_PYTHON_TRACE = os.environ.get("GIT_PYTHON_TRACE", False) execute_kwargs = ('istream', 'with_keep_cwd', 'with_extended_output', - 'with_exceptions', 'with_raw_output') + 'with_exceptions', 'with_raw_output') extra = {} if sys.platform == 'win32': - extra = {'shell': True} + extra = {'shell': True} class Git(object): - """ - The Git class manages communication with the Git binary. - + """ + The Git class manages communication with the Git binary. + It provides a convenient interface to calling the Git binary, such as in:: g = Git( git_dir ) - g.init() # calls 'git init' program + g.init() # calls 'git init' program rval = g.ls_files() # calls 'git ls-files' program ``Debugging`` - Set the GIT_PYTHON_TRACE environment variable print each invocation - of the command to stdout. - Set its value to 'full' to see details about the returned values. - """ - def __init__(self, git_dir=None): - """ - Initialize this instance with: - - ``git_dir`` - Git directory we should work in. If None, we always work in the current - directory as returned by os.getcwd() - """ - super(Git, self).__init__() - self.git_dir = git_dir - - def __getattr__(self, name): - """ - A convenience method as it allows to call the command as if it was - an object. - Returns - Callable object that will execute call _call_process with your arguments. - """ - if name[:1] == '_': - raise AttributeError(name) - return lambda *args, **kwargs: self._call_process(name, *args, **kwargs) - - @property - def get_dir(self): - """ - Returns - Git directory we are working on - """ - return self.git_dir - - def execute(self, command, - istream=None, - with_keep_cwd=False, - with_extended_output=False, - with_exceptions=True, - with_raw_output=False, - ): - """ - Handles executing the command on the shell and consumes and returns - the returned information (stdout) - - ``command`` - The command argument list to execute. - It should be a string, or a sequence of program arguments. The - program to execute is the first item in the args sequence or string. - - ``istream`` - Standard input filehandle passed to subprocess.Popen. - - ``with_keep_cwd`` - Whether to use the current working directory from os.getcwd(). - GitPython uses get_work_tree() as its working directory by - default and get_git_dir() for bare repositories. - - ``with_extended_output`` - Whether to return a (status, stdout, stderr) tuple. - - ``with_exceptions`` - Whether to raise an exception when git returns a non-zero status. - - ``with_raw_output`` - Whether to avoid stripping off trailing whitespace. - - Returns:: - - str(output) # extended_output = False (Default) - tuple(int(status), str(stdout), str(stderr)) # extended_output = True - - Raise - GitCommandError - - NOTE - If you add additional keyword arguments to the signature of this method, - you must update the execute_kwargs tuple housed in this module. - """ - if GIT_PYTHON_TRACE and not GIT_PYTHON_TRACE == 'full': - print ' '.join(command) - - # Allow the user to have the command executed in their working dir. - if with_keep_cwd or self.git_dir is None: - cwd = os.getcwd() - else: - cwd=self.git_dir - - # Start the process - proc = subprocess.Popen(command, - cwd=cwd, - stdin=istream, - stderr=subprocess.PIPE, - stdout=subprocess.PIPE, - **extra - ) - - # Wait for the process to return - try: - stdout_value = proc.stdout.read() - stderr_value = proc.stderr.read() - status = proc.wait() - finally: - proc.stdout.close() - proc.stderr.close() - - # Strip off trailing whitespace by default - if not with_raw_output: - stdout_value = stdout_value.rstrip() - stderr_value = stderr_value.rstrip() - - if with_exceptions and status != 0: - raise GitCommandError(command, status, stderr_value) - - if GIT_PYTHON_TRACE == 'full': - if stderr_value: - print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value) - elif stdout_value: - print "%s -> %d: '%s'" % (command, status, stdout_value) - else: - print "%s -> %d" % (command, status) - - # Allow access to the command's status code - if with_extended_output: - return (status, stdout_value, stderr_value) - else: - return stdout_value - - def transform_kwargs(self, **kwargs): - """ - Transforms Python style kwargs into git command line options. - """ - args = [] - for k, v in kwargs.items(): - if len(k) == 1: - if v is True: - args.append("-%s" % k) - elif type(v) is not bool: - args.append("-%s%s" % (k, v)) - else: - if v is True: - args.append("--%s" % dashify(k)) - elif type(v) is not bool: - args.append("--%s=%s" % (dashify(k), v)) - return args - - def _call_process(self, method, *args, **kwargs): - """ - Run the given git command with the specified arguments and return - the result as a String - - ``method`` - is the command. Contained "_" characters will be converted to dashes, - such as in 'ls_files' to call 'ls-files'. - - ``args`` - is the list of arguments - - ``kwargs`` - is a dict of keyword arguments. - This function accepts the same optional keyword arguments - as execute(). - - Examples:: - git.rev_list('master', max_count=10, header=True) - - Returns - Same as execute() - """ - - # Handle optional arguments prior to calling transform_kwargs - # otherwise these'll end up in args, which is bad. - _kwargs = {} - for kwarg in execute_kwargs: - try: - _kwargs[kwarg] = kwargs.pop(kwarg) - except KeyError: - pass - - # Prepare the argument list - opt_args = self.transform_kwargs(**kwargs) - ext_args = map(str, args) - args = opt_args + ext_args - - call = ["git", dashify(method)] - call.extend(args) - - return self.execute(call, **_kwargs) + Set the GIT_PYTHON_TRACE environment variable print each invocation + of the command to stdout. + Set its value to 'full' to see details about the returned values. + """ + def __init__(self, git_dir=None): + """ + Initialize this instance with: + + ``git_dir`` + Git directory we should work in. If None, we always work in the current + directory as returned by os.getcwd() + """ + super(Git, self).__init__() + self.git_dir = git_dir + + def __getattr__(self, name): + """ + A convenience method as it allows to call the command as if it was + an object. + Returns + Callable object that will execute call _call_process with your arguments. + """ + if name[:1] == '_': + raise AttributeError(name) + return lambda *args, **kwargs: self._call_process(name, *args, **kwargs) + + @property + def get_dir(self): + """ + Returns + Git directory we are working on + """ + return self.git_dir + + def execute(self, command, + istream=None, + with_keep_cwd=False, + with_extended_output=False, + with_exceptions=True, + with_raw_output=False, + ): + """ + Handles executing the command on the shell and consumes and returns + the returned information (stdout) + + ``command`` + The command argument list to execute. + It should be a string, or a sequence of program arguments. The + program to execute is the first item in the args sequence or string. + + ``istream`` + Standard input filehandle passed to subprocess.Popen. + + ``with_keep_cwd`` + Whether to use the current working directory from os.getcwd(). + GitPython uses get_work_tree() as its working directory by + default and get_git_dir() for bare repositories. + + ``with_extended_output`` + Whether to return a (status, stdout, stderr) tuple. + + ``with_exceptions`` + Whether to raise an exception when git returns a non-zero status. + + ``with_raw_output`` + Whether to avoid stripping off trailing whitespace. + + Returns:: + + str(output) # extended_output = False (Default) + tuple(int(status), str(stdout), str(stderr)) # extended_output = True + + Raise + GitCommandError + + NOTE + If you add additional keyword arguments to the signature of this method, + you must update the execute_kwargs tuple housed in this module. + """ + if GIT_PYTHON_TRACE and not GIT_PYTHON_TRACE == 'full': + print ' '.join(command) + + # Allow the user to have the command executed in their working dir. + if with_keep_cwd or self.git_dir is None: + cwd = os.getcwd() + else: + cwd=self.git_dir + + # Start the process + proc = subprocess.Popen(command, + cwd=cwd, + stdin=istream, + stderr=subprocess.PIPE, + stdout=subprocess.PIPE, + **extra + ) + + # Wait for the process to return + try: + stdout_value = proc.stdout.read() + stderr_value = proc.stderr.read() + status = proc.wait() + finally: + proc.stdout.close() + proc.stderr.close() + + # Strip off trailing whitespace by default + if not with_raw_output: + stdout_value = stdout_value.rstrip() + stderr_value = stderr_value.rstrip() + + if with_exceptions and status != 0: + raise GitCommandError(command, status, stderr_value) + + if GIT_PYTHON_TRACE == 'full': + if stderr_value: + print "%s -> %d: '%s' !! '%s'" % (command, status, stdout_value, stderr_value) + elif stdout_value: + print "%s -> %d: '%s'" % (command, status, stdout_value) + else: + print "%s -> %d" % (command, status) + + # Allow access to the command's status code + if with_extended_output: + return (status, stdout_value, stderr_value) + else: + return stdout_value + + def transform_kwargs(self, **kwargs): + """ + Transforms Python style kwargs into git command line options. + """ + args = [] + for k, v in kwargs.items(): + if len(k) == 1: + if v is True: + args.append("-%s" % k) + elif type(v) is not bool: + args.append("-%s%s" % (k, v)) + else: + if v is True: + args.append("--%s" % dashify(k)) + elif type(v) is not bool: + args.append("--%s=%s" % (dashify(k), v)) + return args + + def _call_process(self, method, *args, **kwargs): + """ + Run the given git command with the specified arguments and return + the result as a String + + ``method`` + is the command. Contained "_" characters will be converted to dashes, + such as in 'ls_files' to call 'ls-files'. + + ``args`` + is the list of arguments + + ``kwargs`` + is a dict of keyword arguments. + This function accepts the same optional keyword arguments + as execute(). + + Examples:: + git.rev_list('master', max_count=10, header=True) + + Returns + Same as execute() + """ + + # Handle optional arguments prior to calling transform_kwargs + # otherwise these'll end up in args, which is bad. + _kwargs = {} + for kwarg in execute_kwargs: + try: + _kwargs[kwarg] = kwargs.pop(kwarg) + except KeyError: + pass + + # Prepare the argument list + opt_args = self.transform_kwargs(**kwargs) + ext_args = map(str, args) + args = opt_args + ext_args + + call = ["git", dashify(method)] + call.extend(args) + + return self.execute(call, **_kwargs) diff --git a/lib/git/commit.py b/lib/git/commit.py index 73fb8e7a..1ae84799 100644 --- a/lib/git/commit.py +++ b/lib/git/commit.py @@ -14,281 +14,281 @@ import stats import base class Commit(base.Object): - """ - Wraps a git Commit object. - - This class will act lazily on some of its attributes and will query the - value on demand only if it involves calling the git binary. - """ - # precompiled regex - re_actor_epoch = re.compile(r'^.+? (.*) (\d+) .*$') - - # object configuration - type = "commit" - - def __init__(self, repo, id, tree=None, author=None, authored_date=None, - committer=None, committed_date=None, message=None, parents=None): - """ - Instantiate a new Commit. All keyword arguments taking None as default will - be implicitly set if id names a valid sha. - - The parameter documentation indicates the type of the argument after a colon ':'. - - ``id`` - is the sha id of the commit - - ``parents`` : list( Commit, ... ) - is a list of commit ids - - ``tree`` : Tree - is the corresponding tree id - - ``author`` : Actor - is the author string ( will be implicitly converted into an Actor object ) - - ``authored_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst ) - is the authored DateTime - - ``committer`` : Actor - is the committer string - - ``committed_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) - is the committed DateTime - - ``message`` : string - is the commit message - - Returns - git.Commit - """ - super(Commit,self).__init__(repo, id, "commit") - self.parents = None - self.tree = None - self.author = author - self.authored_date = authored_date - self.committer = committer - self.committed_date = committed_date - self.message = message - - if self.id: - if parents is not None: - self.parents = [Commit(repo, p) for p in parents] - if tree is not None: - self.tree = Tree(repo, id=tree) - - def __eq__(self, other): - return self.id == other.id - - def __ne__(self, other): - return self.id != other.id - - def __bake__(self): - """ - Called by LazyMixin superclass when the first uninitialized member needs - to be set as it is queried. - """ - super(Commit, self).__bake__() - temp = Commit.find_all(self.repo, self.id, max_count=1)[0] - self.parents = temp.parents - self.tree = temp.tree - self.author = temp.author - self.authored_date = temp.authored_date - self.committer = temp.committer - self.committed_date = temp.committed_date - self.message = temp.message - - @property - def id_abbrev(self): - """ - Returns - First 7 bytes of the commit's sha id as an abbreviation of the full string. - """ - return self.id[0:7] - - @property - def summary(self): - """ - Returns - First line of the commit message. - """ - return self.message.split('\n', 1)[0] - - @classmethod - def count(cls, repo, ref, path=''): - """ - Count the number of commits reachable from this ref - - ``repo`` - is the Repo - - ``ref`` - is the ref from which to begin (SHA1 or name) - - ``path`` - is an optinal path - - Returns - int - """ - return len(repo.git.rev_list(ref, '--', path).strip().splitlines()) - - @classmethod - def find_all(cls, repo, ref, path='', **kwargs): - """ - Find all commits matching the given criteria. - - ``repo`` - is the Repo - - ``ref`` - is the ref from which to begin (SHA1 or name) - - ``path`` - is an optinal path, if set only Commits that include the path - will be considered - - ``kwargs`` - optional keyword arguments to git where - ``max_count`` is the maximum number of commits to fetch - ``skip`` is the number of commits to skip - - Returns - git.Commit[] - """ - options = {'pretty': 'raw'} - options.update(kwargs) - - output = repo.git.rev_list(ref, '--', path, **options) - return cls.list_from_string(repo, output) - - @classmethod - def list_from_string(cls, repo, text): - """ - Parse out commit information into a list of Commit objects - - ``repo`` - is the Repo - - ``text`` - is the text output from the git-rev-list command (raw format) - - Returns - git.Commit[] - """ - lines = [l for l in text.splitlines() if l.strip('\r\n')] - - commits = [] - - while lines: - id = lines.pop(0).split()[1] - tree = lines.pop(0).split()[1] - - parents = [] - while lines and lines[0].startswith('parent'): - parents.append(lines.pop(0).split()[-1]) - author, authored_date = cls._actor(lines.pop(0)) - committer, committed_date = cls._actor(lines.pop(0)) - - messages = [] - while lines and lines[0].startswith(' '): - messages.append(lines.pop(0).strip()) - - message = '\n'.join(messages) - - commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date, - committer=committer, committed_date=committed_date, message=message)) - - return commits - - @classmethod - def diff(cls, repo, a, b=None, paths=None): - """ - Creates diffs between a tree and the index or between two trees: - - ``repo`` - is the Repo - - ``a`` - is a named commit - - ``b`` - is an optional named commit. Passing a list assumes you - wish to omit the second named commit and limit the diff to the - given paths. - - ``paths`` - is a list of paths to limit the diff to. - - Returns - git.Diff[]:: - - between tree and the index if only a is given - between two trees if a and b are given and are commits - """ - paths = paths or [] - - if isinstance(b, list): - paths = b - b = None - - if paths: - paths.insert(0, "--") - - if b: - paths.insert(0, b) - paths.insert(0, a) - text = repo.git.diff('-M', full_index=True, *paths) - return diff.Diff.list_from_string(repo, text) - - @property - def diffs(self): - """ - Returns - git.Diff[] - Diffs between this commit and its first parent or all changes if this - commit is the first commit and has no parent. - """ - if not self.parents: - d = self.repo.git.show(self.id, '-M', full_index=True, pretty='raw') - return diff.Diff.list_from_string(self.repo, d) - else: - return self.diff(self.repo, self.parents[0].id, self.id) - - @property - def stats(self): - """ - Create a git stat from changes between this commit and its first parent - or from all changes done if this is the very first commit. - - Return - git.Stats - """ - if not self.parents: - text = self.repo.git.diff_tree(self.id, '--', numstat=True, root=True) - text2 = "" - for line in text.splitlines()[1:]: - (insertions, deletions, filename) = line.split("\t") - text2 += "%s\t%s\t%s\n" % (insertions, deletions, filename) - text = text2 - else: - text = self.repo.git.diff(self.parents[0].id, self.id, '--', numstat=True) - return stats.Stats.list_from_string(self.repo, text) - - def __str__(self): - """ Convert commit to string which is SHA1 """ - return self.id - - def __repr__(self): - return '<git.Commit "%s">' % self.id - - @classmethod - def _actor(cls, line): - """ - Parse out the actor (author or committer) info - - Returns - [Actor, gmtime(acted at time)] - """ - m = cls.re_actor_epoch.search(line) - actor, epoch = m.groups() - return (Actor.from_string(actor), time.gmtime(int(epoch))) + """ + Wraps a git Commit object. + + This class will act lazily on some of its attributes and will query the + value on demand only if it involves calling the git binary. + """ + # precompiled regex + re_actor_epoch = re.compile(r'^.+? (.*) (\d+) .*$') + + # object configuration + type = "commit" + + def __init__(self, repo, id, tree=None, author=None, authored_date=None, + committer=None, committed_date=None, message=None, parents=None): + """ + Instantiate a new Commit. All keyword arguments taking None as default will + be implicitly set if id names a valid sha. + + The parameter documentation indicates the type of the argument after a colon ':'. + + ``id`` + is the sha id of the commit + + ``parents`` : list( Commit, ... ) + is a list of commit ids + + ``tree`` : Tree + is the corresponding tree id + + ``author`` : Actor + is the author string ( will be implicitly converted into an Actor object ) + + ``authored_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst ) + is the authored DateTime + + ``committer`` : Actor + is the committer string + + ``committed_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) + is the committed DateTime + + ``message`` : string + is the commit message + + Returns + git.Commit + """ + super(Commit,self).__init__(repo, id, "commit") + self.parents = None + self.tree = None + self.author = author + self.authored_date = authored_date + self.committer = committer + self.committed_date = committed_date + self.message = message + + if self.id: + if parents is not None: + self.parents = [Commit(repo, p) for p in parents] + if tree is not None: + self.tree = Tree(repo, id=tree) + + def __eq__(self, other): + return self.id == other.id + + def __ne__(self, other): + return self.id != other.id + + def __bake__(self): + """ + Called by LazyMixin superclass when the first uninitialized member needs + to be set as it is queried. + """ + super(Commit, self).__bake__() + temp = Commit.find_all(self.repo, self.id, max_count=1)[0] + self.parents = temp.parents + self.tree = temp.tree + self.author = temp.author + self.authored_date = temp.authored_date + self.committer = temp.committer + self.committed_date = temp.committed_date + self.message = temp.message + + @property + def id_abbrev(self): + """ + Returns + First 7 bytes of the commit's sha id as an abbreviation of the full string. + """ + return self.id[0:7] + + @property + def summary(self): + """ + Returns + First line of the commit message. + """ + return self.message.split('\n', 1)[0] + + @classmethod + def count(cls, repo, ref, path=''): + """ + Count the number of commits reachable from this ref + + ``repo`` + is the Repo + + ``ref`` + is the ref from which to begin (SHA1 or name) + + ``path`` + is an optinal path + + Returns + int + """ + return len(repo.git.rev_list(ref, '--', path).strip().splitlines()) + + @classmethod + def find_all(cls, repo, ref, path='', **kwargs): + """ + Find all commits matching the given criteria. + + ``repo`` + is the Repo + + ``ref`` + is the ref from which to begin (SHA1 or name) + + ``path`` + is an optinal path, if set only Commits that include the path + will be considered + + ``kwargs`` + optional keyword arguments to git where + ``max_count`` is the maximum number of commits to fetch + ``skip`` is the number of commits to skip + + Returns + git.Commit[] + """ + options = {'pretty': 'raw'} + options.update(kwargs) + + output = repo.git.rev_list(ref, '--', path, **options) + return cls.list_from_string(repo, output) + + @classmethod + def list_from_string(cls, repo, text): + """ + Parse out commit information into a list of Commit objects + + ``repo`` + is the Repo + + ``text`` + is the text output from the git-rev-list command (raw format) + + Returns + git.Commit[] + """ + lines = [l for l in text.splitlines() if l.strip('\r\n')] + + commits = [] + + while lines: + id = lines.pop(0).split()[1] + tree = lines.pop(0).split()[1] + + parents = [] + while lines and lines[0].startswith('parent'): + parents.append(lines.pop(0).split()[-1]) + author, authored_date = cls._actor(lines.pop(0)) + committer, committed_date = cls._actor(lines.pop(0)) + + messages = [] + while lines and lines[0].startswith(' '): + messages.append(lines.pop(0).strip()) + + message = '\n'.join(messages) + + commits.append(Commit(repo, id=id, parents=parents, tree=tree, author=author, authored_date=authored_date, + committer=committer, committed_date=committed_date, message=message)) + + return commits + + @classmethod + def diff(cls, repo, a, b=None, paths=None): + """ + Creates diffs between a tree and the index or between two trees: + + ``repo`` + is the Repo + + ``a`` + is a named commit + + ``b`` + is an optional named commit. Passing a list assumes you + wish to omit the second named commit and limit the diff to the + given paths. + + ``paths`` + is a list of paths to limit the diff to. + + Returns + git.Diff[]:: + + between tree and the index if only a is given + between two trees if a and b are given and are commits + """ + paths = paths or [] + + if isinstance(b, list): + paths = b + b = None + + if paths: + paths.insert(0, "--") + + if b: + paths.insert(0, b) + paths.insert(0, a) + text = repo.git.diff('-M', full_index=True, *paths) + return diff.Diff.list_from_string(repo, text) + + @property + def diffs(self): + """ + Returns + git.Diff[] + Diffs between this commit and its first parent or all changes if this + commit is the first commit and has no parent. + """ + if not self.parents: + d = self.repo.git.show(self.id, '-M', full_index=True, pretty='raw') + return diff.Diff.list_from_string(self.repo, d) + else: + return self.diff(self.repo, self.parents[0].id, self.id) + + @property + def stats(self): + """ + Create a git stat from changes between this commit and its first parent + or from all changes done if this is the very first commit. + + Return + git.Stats + """ + if not self.parents: + text = self.repo.git.diff_tree(self.id, '--', numstat=True, root=True) + text2 = "" + for line in text.splitlines()[1:]: + (insertions, deletions, filename) = line.split("\t") + text2 += "%s\t%s\t%s\n" % (insertions, deletions, filename) + text = text2 + else: + text = self.repo.git.diff(self.parents[0].id, self.id, '--', numstat=True) + return stats.Stats.list_from_string(self.repo, text) + + def __str__(self): + """ Convert commit to string which is SHA1 """ + return self.id + + def __repr__(self): + return '<git.Commit "%s">' % self.id + + @classmethod + def _actor(cls, line): + """ + Parse out the actor (author or committer) info + + Returns + [Actor, gmtime(acted at time)] + """ + m = cls.re_actor_epoch.search(line) + actor, epoch = m.groups() + return (Actor.from_string(actor), time.gmtime(int(epoch))) diff --git a/lib/git/diff.py b/lib/git/diff.py index 75450d70..ef58cb0e 100644 --- a/lib/git/diff.py +++ b/lib/git/diff.py @@ -8,30 +8,30 @@ import re import blob class Diff(object): - """ - A Diff contains diff information between two commits. - - It contains two sides a and b of the diff, members are prefixed with - "a" and "b" respectively to inidcate that. - - Diffs keep information about the changed blob objects, the file mode, renames, - deletions and new files. - - There are a few cases where None has to be expected as member variable value: - - ``New File``:: - - a_mode is None - a_blob is None - - ``Deleted File``:: - - b_mode is None - b_blob is NOne - """ - - # precompiled regex - re_header = re.compile(r""" + """ + A Diff contains diff information between two commits. + + It contains two sides a and b of the diff, members are prefixed with + "a" and "b" respectively to inidcate that. + + Diffs keep information about the changed blob objects, the file mode, renames, + deletions and new files. + + There are a few cases where None has to be expected as member variable value: + + ``New File``:: + + a_mode is None + a_blob is None + + ``Deleted File``:: + + b_mode is None + b_blob is NOne + """ + + # precompiled regex + re_header = re.compile(r""" #^diff[ ]--git [ ]a/(?P<a_path>\S+)[ ]b/(?P<b_path>\S+)\n (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n @@ -44,58 +44,58 @@ class Diff(object): (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+) \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? """, re.VERBOSE | re.MULTILINE) - re_is_null_hexsha = re.compile( r'^0{40}$' ) + re_is_null_hexsha = re.compile( r'^0{40}$' ) - def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode, - b_mode, new_file, deleted_file, rename_from, - rename_to, diff): - self.repo = repo + def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode, + b_mode, new_file, deleted_file, rename_from, + rename_to, diff): + self.repo = repo - if not a_blob_id or self.re_is_null_hexsha.search(a_blob_id): - self.a_blob = None - else: - self.a_blob = blob.Blob(repo, id=a_blob_id, mode=a_mode, path=a_path) - if not b_blob_id or self.re_is_null_hexsha.search(b_blob_id): - self.b_blob = None - else: - self.b_blob = blob.Blob(repo, id=b_blob_id, mode=b_mode, path=b_path) + if not a_blob_id or self.re_is_null_hexsha.search(a_blob_id): + self.a_blob = None + else: + self.a_blob = blob.Blob(repo, id=a_blob_id, mode=a_mode, path=a_path) + if not b_blob_id or self.re_is_null_hexsha.search(b_blob_id): + self.b_blob = None + else: + self.b_blob = blob.Blob(repo, id=b_blob_id, mode=b_mode, path=b_path) - self.a_mode = a_mode - self.b_mode = b_mode - self.new_file = new_file - self.deleted_file = deleted_file - self.rename_from = rename_from - self.rename_to = rename_to - self.renamed = rename_from != rename_to - self.diff = diff + self.a_mode = a_mode + self.b_mode = b_mode + self.new_file = new_file + self.deleted_file = deleted_file + self.rename_from = rename_from + self.rename_to = rename_to + self.renamed = rename_from != rename_to + self.diff = diff - @classmethod - def list_from_string(cls, repo, text): - """ - Create a new diff object from the given text - ``repo`` - is the repository we are operating on - it is required - - ``text`` - result of 'git diff' between two commits or one commit and the index - - Returns - git.Diff[] - """ - diffs = [] + @classmethod + def list_from_string(cls, repo, text): + """ + Create a new diff object from the given text + ``repo`` + is the repository we are operating on - it is required + + ``text`` + result of 'git diff' between two commits or one commit and the index + + Returns + git.Diff[] + """ + diffs = [] - diff_header = cls.re_header.match - for diff in ('\n' + text).split('\ndiff --git')[1:]: - header = diff_header(diff) + diff_header = cls.re_header.match + for diff in ('\n' + text).split('\ndiff --git')[1:]: + header = diff_header(diff) - a_path, b_path, similarity_index, rename_from, rename_to, \ - old_mode, new_mode, new_file_mode, deleted_file_mode, \ - a_blob_id, b_blob_id, b_mode = header.groups() - new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode) + a_path, b_path, similarity_index, rename_from, rename_to, \ + old_mode, new_mode, new_file_mode, deleted_file_mode, \ + a_blob_id, b_blob_id, b_mode = header.groups() + new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode) - diffs.append(Diff(repo, a_path, b_path, a_blob_id, b_blob_id, - old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode, - new_file, deleted_file, rename_from, rename_to, diff[header.end():])) + diffs.append(Diff(repo, a_path, b_path, a_blob_id, b_blob_id, + old_mode or deleted_file_mode, new_mode or new_file_mode or b_mode, + new_file, deleted_file, rename_from, rename_to, diff[header.end():])) - return diffs + return diffs diff --git a/lib/git/errors.py b/lib/git/errors.py index 45afb590..e9a637c0 100644 --- a/lib/git/errors.py +++ b/lib/git/errors.py @@ -8,25 +8,25 @@ Module containing all exceptions thrown througout the git package, """ class InvalidGitRepositoryError(Exception): - """ - Thrown if the given repository appears to have an invalid format. - """ + """ + Thrown if the given repository appears to have an invalid format. + """ class NoSuchPathError(OSError): - """ - Thrown if a path could not be access by the system. - """ + """ + Thrown if a path could not be access by the system. + """ class GitCommandError(Exception): - """ - Thrown if execution of the git command fails with non-zero status code. - """ - def __init__(self, command, status, stderr=None): - self.stderr = stderr - self.status = status - self.command = command + """ + Thrown if execution of the git command fails with non-zero status code. + """ + def __init__(self, command, status, stderr=None): + self.stderr = stderr + self.status = status + self.command = command - def __str__(self): - return repr("%s returned exit status %d" % - (str(self.command), self.status)) + def __str__(self): + return repr("%s returned exit status %d" % + (str(self.command), self.status)) diff --git a/lib/git/head.py b/lib/git/head.py index 3c3f13ac..f4e94637 100644 --- a/lib/git/head.py +++ b/lib/git/head.py @@ -8,56 +8,56 @@ import commit import base class Head(base.Ref): - """ - A Head is a named reference to a Commit. Every Head instance contains a name - and a Commit object. - - Examples:: - - >>> repo = Repo("/path/to/repo") - >>> head = repo.heads[0] - - >>> head.name - 'master' - - >>> head.commit - <git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455"> - - >>> head.commit.id - '1c09f116cbc2cb4100fb6935bb162daa4723f455' - """ - - def __init__(self, path, commit): - """ - Initialize a newly instanced Head - - ``path`` - is the path to the head ref, relative to the .git directory, i.e. - refs/heads/master - - `commit` - is the Commit object that the head points to - """ - super(Head, self).__init__(name, commit) - - - @property - def commit(self): - """ - Returns - Commit object the head points to - """ - return self.object - - @classmethod - def find_all(cls, repo, common_path = "refs/heads", **kwargs): - """ - Returns - git.Head[] - - For more documentation, please refer to git.base.Ref.find_all - """ - return super(Head,cls).find_all(repo, common_path, **kwargs) - - def __repr__(self): - return '<git.Head "%s">' % self.name + """ + A Head is a named reference to a Commit. Every Head instance contains a name + and a Commit object. + + Examples:: + + >>> repo = Repo("/path/to/repo") + >>> head = repo.heads[0] + + >>> head.name + 'master' + + >>> head.commit + <git.Commit "1c09f116cbc2cb4100fb6935bb162daa4723f455"> + + >>> head.commit.id + '1c09f116cbc2cb4100fb6935bb162daa4723f455' + """ + + def __init__(self, path, commit): + """ + Initialize a newly instanced Head + + ``path`` + is the path to the head ref, relative to the .git directory, i.e. + refs/heads/master + + `commit` + is the Commit object that the head points to + """ + super(Head, self).__init__(name, commit) + + + @property + def commit(self): + """ + Returns + Commit object the head points to + """ + return self.object + + @classmethod + def find_all(cls, repo, common_path = "refs/heads", **kwargs): + """ + Returns + git.Head[] + + For more documentation, please refer to git.base.Ref.find_all + """ + return super(Head,cls).find_all(repo, common_path, **kwargs) + + def __repr__(self): + return '<git.Head "%s">' % self.name diff --git a/lib/git/repo.py b/lib/git/repo.py index 811cf6f0..3c872218 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -17,496 +17,496 @@ from commit import Commit from tree import Tree class Repo(object): - """ - Represents a git repository and allows you to query references, - gather commit information, generate diffs, create and clone repositories query - the log. - """ - DAEMON_EXPORT_FILE = 'git-daemon-export-ok' - - def __init__(self, path=None): - """ - Create a new Repo instance - - ``path`` - is the path to either the root git directory or the bare git repo - - Examples:: - - repo = Repo("/Users/mtrier/Development/git-python") - repo = Repo("/Users/mtrier/Development/git-python.git") - - Raises - InvalidGitRepositoryError or NoSuchPathError - - Returns - ``git.Repo`` - """ - - epath = os.path.abspath(os.path.expanduser(path or os.getcwd())) - - if not os.path.exists(epath): - raise NoSuchPathError(epath) - - self.path = None - curpath = epath - while curpath: - if is_git_dir(curpath): - self.bare = True - self.path = curpath - self.wd = curpath - break - gitpath = os.path.join(curpath, '.git') - if is_git_dir(gitpath): - self.bare = False - self.path = gitpath - self.wd = curpath - break - curpath, dummy = os.path.split(curpath) - if not dummy: - break - - if self.path is None: - raise InvalidGitRepositoryError(epath) - - self.git = Git(self.wd) - - # Description property - def _get_description(self): - filename = os.path.join(self.path, 'description') - return file(filename).read().rstrip() - - def _set_description(self, descr): - filename = os.path.join(self.path, 'description') - file(filename, 'w').write(descr+'\n') - - description = property(_get_description, _set_description, - doc="the project's description") - del _get_description - del _set_description - - @property - def heads(self): - """ - A list of ``Head`` objects representing the branch heads in - this repo - - Returns - ``git.Head[]`` - """ - return Head.find_all(self) - - # alias heads - branches = heads - - @property - def tags(self): - """ - A list of ``Tag`` objects that are available in this repo - - Returns - ``git.Tag[]`` - """ - return Tag.find_all(self) - - def commits(self, start='master', path='', max_count=10, skip=0): - """ - A list of Commit objects representing the history of a given ref/commit - - ``start`` - is the branch/commit name (default 'master') - - ``path`` - is an optional path to limit the returned commits to - Commits that do not contain that path will not be returned. - - ``max_count`` - is the maximum number of commits to return (default 10) + """ + Represents a git repository and allows you to query references, + gather commit information, generate diffs, create and clone repositories query + the log. + """ + DAEMON_EXPORT_FILE = 'git-daemon-export-ok' - ``skip`` - is the number of commits to skip (default 0) which will effectively - move your commit-window by the given number. + def __init__(self, path=None): + """ + Create a new Repo instance - Returns - ``git.Commit[]`` - """ - options = {'max_count': max_count, - 'skip': skip} + ``path`` + is the path to either the root git directory or the bare git repo - return Commit.find_all(self, start, path, **options) + Examples:: - def commits_between(self, frm, to): - """ - The Commits objects that are reachable via ``to`` but not via ``frm`` - Commits are returned in chronological order. + repo = Repo("/Users/mtrier/Development/git-python") + repo = Repo("/Users/mtrier/Development/git-python.git") - ``from`` - is the branch/commit name of the younger item + Raises + InvalidGitRepositoryError or NoSuchPathError + + Returns + ``git.Repo`` + """ + + epath = os.path.abspath(os.path.expanduser(path or os.getcwd())) + + if not os.path.exists(epath): + raise NoSuchPathError(epath) + + self.path = None + curpath = epath + while curpath: + if is_git_dir(curpath): + self.bare = True + self.path = curpath + self.wd = curpath + break + gitpath = os.path.join(curpath, '.git') + if is_git_dir(gitpath): + self.bare = False + self.path = gitpath + self.wd = curpath + break + curpath, dummy = os.path.split(curpath) + if not dummy: + break + + if self.path is None: + raise InvalidGitRepositoryError(epath) + + self.git = Git(self.wd) + + # Description property + def _get_description(self): + filename = os.path.join(self.path, 'description') + return file(filename).read().rstrip() + + def _set_description(self, descr): + filename = os.path.join(self.path, 'description') + file(filename, 'w').write(descr+'\n') + + description = property(_get_description, _set_description, + doc="the project's description") + del _get_description + del _set_description + + @property + def heads(self): + """ + A list of ``Head`` objects representing the branch heads in + this repo + + Returns + ``git.Head[]`` + """ + return Head.find_all(self) + + # alias heads + branches = heads + + @property + def tags(self): + """ + A list of ``Tag`` objects that are available in this repo + + Returns + ``git.Tag[]`` + """ + return Tag.find_all(self) + + def commits(self, start='master', path='', max_count=10, skip=0): + """ + A list of Commit objects representing the history of a given ref/commit + + ``start`` + is the branch/commit name (default 'master') + + ``path`` + is an optional path to limit the returned commits to + Commits that do not contain that path will not be returned. + + ``max_count`` + is the maximum number of commits to return (default 10) + + ``skip`` + is the number of commits to skip (default 0) which will effectively + move your commit-window by the given number. + + Returns + ``git.Commit[]`` + """ + options = {'max_count': max_count, + 'skip': skip} + + return Commit.find_all(self, start, path, **options) + + def commits_between(self, frm, to): + """ + The Commits objects that are reachable via ``to`` but not via ``frm`` + Commits are returned in chronological order. + + ``from`` + is the branch/commit name of the younger item + + ``to`` + is the branch/commit name of the older item + + Returns + ``git.Commit[]`` + """ + return reversed(Commit.find_all(self, "%s..%s" % (frm, to))) + + def commits_since(self, start='master', path='', since='1970-01-01'): + """ + The Commits objects that are newer than the specified date. + Commits are returned in chronological order. + + ``start`` + is the branch/commit name (default 'master') + + ``path`` + is an optinal path to limit the returned commits to. + + + ``since`` + is a string represeting a date/time + + Returns + ``git.Commit[]`` + """ + options = {'since': since} + + return Commit.find_all(self, start, path, **options) + + def commit_count(self, start='master', path=''): + """ + The number of commits reachable by the given branch/commit + + ``start`` + is the branch/commit name (default 'master') + + ``path`` + is an optional path + Commits that do not contain the path will not contribute to the count. + + Returns + ``int`` + """ + return Commit.count(self, start, path) + + def commit(self, id, path = ''): + """ + The Commit object for the specified id - ``to`` - is the branch/commit name of the older item - - Returns - ``git.Commit[]`` - """ - return reversed(Commit.find_all(self, "%s..%s" % (frm, to))) - - def commits_since(self, start='master', path='', since='1970-01-01'): - """ - The Commits objects that are newer than the specified date. - Commits are returned in chronological order. + ``id`` + is the SHA1 identifier of the commit - ``start`` - is the branch/commit name (default 'master') + ``path`` + is an optional path, if set the returned commit must contain the path. - ``path`` - is an optinal path to limit the returned commits to. - + Returns + ``git.Commit`` + """ + options = {'max_count': 1} - ``since`` - is a string represeting a date/time + commits = Commit.find_all(self, id, path, **options) - Returns - ``git.Commit[]`` - """ - options = {'since': since} + if not commits: + raise ValueError, "Invalid identifier %s, or given path '%s' too restrictive" % ( id, path ) + return commits[0] - return Commit.find_all(self, start, path, **options) - - def commit_count(self, start='master', path=''): - """ - The number of commits reachable by the given branch/commit - - ``start`` - is the branch/commit name (default 'master') + def commit_deltas_from(self, other_repo, ref='master', other_ref='master'): + """ + Returns a list of commits that is in ``other_repo`` but not in self - ``path`` - is an optional path - Commits that do not contain the path will not contribute to the count. - - Returns - ``int`` - """ - return Commit.count(self, start, path) - - def commit(self, id, path = ''): - """ - The Commit object for the specified id - - ``id`` - is the SHA1 identifier of the commit - - ``path`` - is an optional path, if set the returned commit must contain the path. - - Returns - ``git.Commit`` - """ - options = {'max_count': 1} - - commits = Commit.find_all(self, id, path, **options) - - if not commits: - raise ValueError, "Invalid identifier %s, or given path '%s' too restrictive" % ( id, path ) - return commits[0] - - def commit_deltas_from(self, other_repo, ref='master', other_ref='master'): - """ - Returns a list of commits that is in ``other_repo`` but not in self - - Returns - git.Commit[] - """ - repo_refs = self.git.rev_list(ref, '--').strip().splitlines() - other_repo_refs = other_repo.git.rev_list(other_ref, '--').strip().splitlines() + Returns + git.Commit[] + """ + repo_refs = self.git.rev_list(ref, '--').strip().splitlines() + other_repo_refs = other_repo.git.rev_list(other_ref, '--').strip().splitlines() - diff_refs = list(set(other_repo_refs) - set(repo_refs)) - return map(lambda ref: Commit.find_all(other_repo, ref, max_count=1)[0], diff_refs) + diff_refs = list(set(other_repo_refs) - set(repo_refs)) + return map(lambda ref: Commit.find_all(other_repo, ref, max_count=1)[0], diff_refs) - def tree(self, treeish='master'): - """ - The Tree object for the given treeish reference + def tree(self, treeish='master'): + """ + The Tree object for the given treeish reference - ``treeish`` - is the reference (default 'master') + ``treeish`` + is the reference (default 'master') - Examples:: + Examples:: - repo.tree('master') + repo.tree('master') - Returns - ``git.Tree`` - """ - return Tree(self, id=treeish) + Returns + ``git.Tree`` + """ + return Tree(self, id=treeish) + + def blob(self, id): + """ + The Blob object for the given id + + ``id`` + is the SHA1 id of the blob + + Returns + ``git.Blob`` + """ + return Blob(self, id=id) + + def log(self, commit='master', path=None, **kwargs): + """ + The Commit for a treeish, and all commits leading to it. + + ``kwargs`` + keyword arguments specifying flags to be used in git-log command, + i.e.: max_count=1 to limit the amount of commits returned + + Returns + ``git.Commit[]`` + """ + options = {'pretty': 'raw'} + options.update(kwargs) + arg = [commit, '--'] + if path: + arg.append(path) + commits = self.git.log(*arg, **options) + return Commit.list_from_string(self, commits) + + def diff(self, a, b, *paths): + """ + The diff from commit ``a`` to commit ``b``, optionally restricted to the given file(s) + + ``a`` + is the base commit + ``b`` + is the other commit + + ``paths`` + is an optional list of file paths on which to restrict the diff + + Returns + ``str`` + """ + return self.git.diff(a, b, '--', *paths) + + def commit_diff(self, commit): + """ + The commit diff for the given commit + ``commit`` is the commit name/id - def blob(self, id): - """ - The Blob object for the given id - - ``id`` - is the SHA1 id of the blob - - Returns - ``git.Blob`` - """ - return Blob(self, id=id) - - def log(self, commit='master', path=None, **kwargs): - """ - The Commit for a treeish, and all commits leading to it. - - ``kwargs`` - keyword arguments specifying flags to be used in git-log command, - i.e.: max_count=1 to limit the amount of commits returned + Returns + ``git.Diff[]`` + """ + return Commit.diff(self, commit) - Returns - ``git.Commit[]`` - """ - options = {'pretty': 'raw'} - options.update(kwargs) - arg = [commit, '--'] - if path: - arg.append(path) - commits = self.git.log(*arg, **options) - return Commit.list_from_string(self, commits) + @classmethod + def init_bare(self, path, mkdir=True, **kwargs): + """ + Initialize a bare git repository at the given path - def diff(self, a, b, *paths): - """ - The diff from commit ``a`` to commit ``b``, optionally restricted to the given file(s) - - ``a`` - is the base commit - ``b`` - is the other commit + ``path`` + is the full path to the repo (traditionally ends with /<name>.git) - ``paths`` - is an optional list of file paths on which to restrict the diff - - Returns - ``str`` - """ - return self.git.diff(a, b, '--', *paths) + ``mkdir`` + if specified will create the repository directory if it doesn't + already exists. Creates the directory with a mode=0755. - def commit_diff(self, commit): - """ - The commit diff for the given commit - ``commit`` is the commit name/id + ``kwargs`` + keyword arguments serving as additional options to the git init command - Returns - ``git.Diff[]`` - """ - return Commit.diff(self, commit) + Examples:: - @classmethod - def init_bare(self, path, mkdir=True, **kwargs): - """ - Initialize a bare git repository at the given path + git.Repo.init_bare('/var/git/myrepo.git') - ``path`` - is the full path to the repo (traditionally ends with /<name>.git) - - ``mkdir`` - if specified will create the repository directory if it doesn't - already exists. Creates the directory with a mode=0755. - - ``kwargs`` - keyword arguments serving as additional options to the git init command - - Examples:: - - git.Repo.init_bare('/var/git/myrepo.git') - - Returns - ``git.Repo`` (the newly created repo) - """ - - if mkdir and not os.path.exists(path): - os.makedirs(path, 0755) - - git = Git(path) - output = git.init('--bare', **kwargs) - return Repo(path) - create = init_bare - - def fork_bare(self, path, **kwargs): - """ - Fork a bare git repository from this repo - - ``path`` - is the full path of the new repo (traditionally ends with /<name>.git) - - ``kwargs`` - keyword arguments to be given to the git clone command - - Returns - ``git.Repo`` (the newly forked repo) - """ - options = {'bare': True} - options.update(kwargs) - self.git.clone(self.path, path, **options) - return Repo(path) - - def archive_tar(self, treeish='master', prefix=None): - """ - Archive the given treeish - - ``treeish`` - is the treeish name/id (default 'master') - - ``prefix`` - is the optional prefix to prepend to each filename in the archive - - Examples:: - - >>> repo.archive_tar - <String containing tar archive> - - >>> repo.archive_tar('a87ff14') - <String containing tar archive for commit a87ff14> - - >>> repo.archive_tar('master', 'myproject/') - <String containing tar bytes archive, whose files are prefixed with 'myproject/'> - - Returns - str (containing bytes of tar archive) - """ - options = {} - if prefix: - options['prefix'] = prefix - return self.git.archive(treeish, **options) - - def archive_tar_gz(self, treeish='master', prefix=None): - """ - Archive and gzip the given treeish - - ``treeish`` - is the treeish name/id (default 'master') - - ``prefix`` - is the optional prefix to prepend to each filename in the archive - - Examples:: - - >>> repo.archive_tar_gz - <String containing tar.gz archive> - - >>> repo.archive_tar_gz('a87ff14') - <String containing tar.gz archive for commit a87ff14> - - >>> repo.archive_tar_gz('master', 'myproject/') - <String containing tar.gz archive and prefixed with 'myproject/'> - - Returns - str (containing the bytes of tar.gz archive) - """ - kwargs = {} - if prefix: - kwargs['prefix'] = prefix - resultstr = self.git.archive(treeish, **kwargs) - sio = StringIO.StringIO() - gf = gzip.GzipFile(fileobj=sio, mode ='wb') - gf.write(resultstr) - gf.close() - return sio.getvalue() - - def _get_daemon_export(self): - filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) - return os.path.exists(filename) - - def _set_daemon_export(self, value): - filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) - fileexists = os.path.exists(filename) - if value and not fileexists: - touch(filename) - elif not value and fileexists: - os.unlink(filename) - - daemon_export = property(_get_daemon_export, _set_daemon_export, - doc="If True, git-daemon may export this repository") - del _get_daemon_export - del _set_daemon_export - - def _get_alternates(self): - """ - The list of alternates for this repo from which objects can be retrieved - - Returns - list of strings being pathnames of alternates - """ - alternates_path = os.path.join(self.path, 'objects', 'info', 'alternates') - - if os.path.exists(alternates_path): - try: - f = open(alternates_path) - alts = f.read() - finally: - f.close() - return alts.strip().splitlines() - else: - return [] - - def _set_alternates(self, alts): - """ - Sets the alternates - - ``alts`` - is the array of string paths representing the alternates at which - git should look for objects, i.e. /home/user/repo/.git/objects + Returns + ``git.Repo`` (the newly created repo) + """ + + if mkdir and not os.path.exists(path): + os.makedirs(path, 0755) + + git = Git(path) + output = git.init('--bare', **kwargs) + return Repo(path) + create = init_bare + + def fork_bare(self, path, **kwargs): + """ + Fork a bare git repository from this repo + + ``path`` + is the full path of the new repo (traditionally ends with /<name>.git) + + ``kwargs`` + keyword arguments to be given to the git clone command + + Returns + ``git.Repo`` (the newly forked repo) + """ + options = {'bare': True} + options.update(kwargs) + self.git.clone(self.path, path, **options) + return Repo(path) + + def archive_tar(self, treeish='master', prefix=None): + """ + Archive the given treeish + + ``treeish`` + is the treeish name/id (default 'master') + + ``prefix`` + is the optional prefix to prepend to each filename in the archive + + Examples:: + + >>> repo.archive_tar + <String containing tar archive> + + >>> repo.archive_tar('a87ff14') + <String containing tar archive for commit a87ff14> + + >>> repo.archive_tar('master', 'myproject/') + <String containing tar bytes archive, whose files are prefixed with 'myproject/'> + + Returns + str (containing bytes of tar archive) + """ + options = {} + if prefix: + options['prefix'] = prefix + return self.git.archive(treeish, **options) + + def archive_tar_gz(self, treeish='master', prefix=None): + """ + Archive and gzip the given treeish + + ``treeish`` + is the treeish name/id (default 'master') + + ``prefix`` + is the optional prefix to prepend to each filename in the archive + + Examples:: + + >>> repo.archive_tar_gz + <String containing tar.gz archive> + + >>> repo.archive_tar_gz('a87ff14') + <String containing tar.gz archive for commit a87ff14> + + >>> repo.archive_tar_gz('master', 'myproject/') + <String containing tar.gz archive and prefixed with 'myproject/'> + + Returns + str (containing the bytes of tar.gz archive) + """ + kwargs = {} + if prefix: + kwargs['prefix'] = prefix + resultstr = self.git.archive(treeish, **kwargs) + sio = StringIO.StringIO() + gf = gzip.GzipFile(fileobj=sio, mode ='wb') + gf.write(resultstr) + gf.close() + return sio.getvalue() + + def _get_daemon_export(self): + filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) + return os.path.exists(filename) + + def _set_daemon_export(self, value): + filename = os.path.join(self.path, self.DAEMON_EXPORT_FILE) + fileexists = os.path.exists(filename) + if value and not fileexists: + touch(filename) + elif not value and fileexists: + os.unlink(filename) + + daemon_export = property(_get_daemon_export, _set_daemon_export, + doc="If True, git-daemon may export this repository") + del _get_daemon_export + del _set_daemon_export + + def _get_alternates(self): + """ + The list of alternates for this repo from which objects can be retrieved + + Returns + list of strings being pathnames of alternates + """ + alternates_path = os.path.join(self.path, 'objects', 'info', 'alternates') + + if os.path.exists(alternates_path): + try: + f = open(alternates_path) + alts = f.read() + finally: + f.close() + return alts.strip().splitlines() + else: + return [] + + def _set_alternates(self, alts): + """ + Sets the alternates + + ``alts`` + is the array of string paths representing the alternates at which + git should look for objects, i.e. /home/user/repo/.git/objects Raises NoSuchPathError - Returns - None - """ - for alt in alts: - if not os.path.exists(alt): - raise NoSuchPathError("Could not set alternates. Alternate path %s must exist" % alt) - - if not alts: - os.remove(os.path.join(self.path, 'objects', 'info', 'alternates')) - else: - try: - f = open(os.path.join(self.path, 'objects', 'info', 'alternates'), 'w') - f.write("\n".join(alts)) - finally: - f.close() - - alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") - - @property - def is_dirty(self): - """ - Return the status of the index. - - Returns - ``True``, if the index has any uncommitted changes, - otherwise ``False`` + Returns + None + """ + for alt in alts: + if not os.path.exists(alt): + raise NoSuchPathError("Could not set alternates. Alternate path %s must exist" % alt) + + if not alts: + os.remove(os.path.join(self.path, 'objects', 'info', 'alternates')) + else: + try: + f = open(os.path.join(self.path, 'objects', 'info', 'alternates'), 'w') + f.write("\n".join(alts)) + finally: + f.close() + + alternates = property(_get_alternates, _set_alternates, doc="Retrieve a list of alternates paths or set a list paths to be used as alternates") + + @property + def is_dirty(self): + """ + Return the status of the index. + + Returns + ``True``, if the index has any uncommitted changes, + otherwise ``False`` NOTE Working tree changes that have not been staged will not be detected ! - """ - if self.bare: - # Bare repositories with no associated working directory are - # always consired to be clean. - return False - - return len(self.git.diff('HEAD', '--').strip()) > 0 - - @property - def active_branch(self): - """ - The name of the currently active branch. - - Returns - str (the branch name) - """ - branch = self.git.symbolic_ref('HEAD').strip() - if branch.startswith('refs/heads/'): - branch = branch[len('refs/heads/'):] - - return branch - - def __repr__(self): - return '<git.Repo "%s">' % self.path + """ + if self.bare: + # Bare repositories with no associated working directory are + # always consired to be clean. + return False + + return len(self.git.diff('HEAD', '--').strip()) > 0 + + @property + def active_branch(self): + """ + The name of the currently active branch. + + Returns + str (the branch name) + """ + branch = self.git.symbolic_ref('HEAD').strip() + if branch.startswith('refs/heads/'): + branch = branch[len('refs/heads/'):] + + return branch + + def __repr__(self): + return '<git.Repo "%s">' % self.path diff --git a/lib/git/stats.py b/lib/git/stats.py index 307e2f2f..a39d1dab 100644 --- a/lib/git/stats.py +++ b/lib/git/stats.py @@ -5,55 +5,55 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php class Stats(object): - """ - Represents stat information as presented by git at the end of a merge. It is - created from the output of a diff operation. - - ``Example``:: - - c = Commit( sha1 ) - s = c.stats - s.total # full-stat-dict - s.files # dict( filepath : stat-dict ) - - ``stat-dict`` - - A dictionary with the following keys and values:: - - deletions = number of deleted lines as int - insertions = number of inserted lines as int - lines = total number of lines changed as int, or deletions + insertions - - ``full-stat-dict`` - - In addition to the items in the stat-dict, it features additional information:: - - files = number of changed files as int - - """ - def __init__(self, repo, total, files): - self.repo = repo - self.total = total - self.files = files + """ + Represents stat information as presented by git at the end of a merge. It is + created from the output of a diff operation. + + ``Example``:: + + c = Commit( sha1 ) + s = c.stats + s.total # full-stat-dict + s.files # dict( filepath : stat-dict ) + + ``stat-dict`` + + A dictionary with the following keys and values:: + + deletions = number of deleted lines as int + insertions = number of inserted lines as int + lines = total number of lines changed as int, or deletions + insertions + + ``full-stat-dict`` + + In addition to the items in the stat-dict, it features additional information:: + + files = number of changed files as int + + """ + def __init__(self, repo, total, files): + self.repo = repo + self.total = total + self.files = files - @classmethod - def list_from_string(cls, repo, text): - """ - Create a Stat object from output retrieved by git-diff. - - Returns - git.Stat - """ - hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': {}} - for line in text.splitlines(): - (raw_insertions, raw_deletions, filename) = line.split("\t") - insertions = raw_insertions != '-' and int(raw_insertions) or 0 - deletions = raw_deletions != '-' and int(raw_deletions) or 0 - hsh['total']['insertions'] += insertions - hsh['total']['deletions'] += deletions - hsh['total']['lines'] += insertions + deletions - hsh['total']['files'] += 1 - hsh['files'][filename.strip()] = {'insertions': insertions, - 'deletions': deletions, - 'lines': insertions + deletions} - return Stats(repo, hsh['total'], hsh['files']) + @classmethod + def list_from_string(cls, repo, text): + """ + Create a Stat object from output retrieved by git-diff. + + Returns + git.Stat + """ + hsh = {'total': {'insertions': 0, 'deletions': 0, 'lines': 0, 'files': 0}, 'files': {}} + for line in text.splitlines(): + (raw_insertions, raw_deletions, filename) = line.split("\t") + insertions = raw_insertions != '-' and int(raw_insertions) or 0 + deletions = raw_deletions != '-' and int(raw_deletions) or 0 + hsh['total']['insertions'] += insertions + hsh['total']['deletions'] += deletions + hsh['total']['lines'] += insertions + deletions + hsh['total']['files'] += 1 + hsh['files'][filename.strip()] = {'insertions': insertions, + 'deletions': deletions, + 'lines': insertions + deletions} + return Stats(repo, hsh['total'], hsh['files']) diff --git a/lib/git/tag.py b/lib/git/tag.py index 0c4122ab..4266a7a9 100644 --- a/lib/git/tag.py +++ b/lib/git/tag.py @@ -8,121 +8,121 @@ import commit import base class TagRef(base.Ref): - """ - Class representing a lightweight tag reference which either points to a commit - or to a tag object. In the latter case additional information, like the signature - or the tag-creator, is available. - - This tag object will always point to a commit object, but may carray additional - information in a tag object:: - - tagref = TagRef.find_all(repo)[0] - print tagref.commit.message - if tagref.tag is not None: - print tagref.tag.message - """ - - __slots__ = "tag" - - def __init__(self, path, commit_or_tag): - """ - Initialize a newly instantiated Tag + """ + Class representing a lightweight tag reference which either points to a commit + or to a tag object. In the latter case additional information, like the signature + or the tag-creator, is available. + + This tag object will always point to a commit object, but may carray additional + information in a tag object:: + + tagref = TagRef.find_all(repo)[0] + print tagref.commit.message + if tagref.tag is not None: + print tagref.tag.message + """ + + __slots__ = "tag" + + def __init__(self, path, commit_or_tag): + """ + Initialize a newly instantiated Tag - ``path`` - is the full path to the tag + ``path`` + is the full path to the tag - ``commit_or_tag`` - is the Commit or TagObject that this tag ref points to - """ - super(TagRef, self).__init__(path, commit_or_tag) - self.tag = None - - if commit_or_tag.type == "tag": - self.tag = commit_or_tag - # END tag object handling - - @property - def commit(self): - """ - Returns - Commit object the tag ref points to - """ - if self.object.type == "commit": - return self.object - # it is a tag object - return self.object.object + ``commit_or_tag`` + is the Commit or TagObject that this tag ref points to + """ + super(TagRef, self).__init__(path, commit_or_tag) + self.tag = None + + if commit_or_tag.type == "tag": + self.tag = commit_or_tag + # END tag object handling + + @property + def commit(self): + """ + Returns + Commit object the tag ref points to + """ + if self.object.type == "commit": + return self.object + # it is a tag object + return self.object.object - @classmethod - def find_all(cls, repo, common_path = "refs/tags", **kwargs): - """ - Returns - git.Tag[] - - For more documentation, please refer to git.base.Ref.find_all - """ - return super(TagRef,cls).find_all(repo, common_path, **kwargs) - - + @classmethod + def find_all(cls, repo, common_path = "refs/tags", **kwargs): + """ + Returns + git.Tag[] + + For more documentation, please refer to git.base.Ref.find_all + """ + return super(TagRef,cls).find_all(repo, common_path, **kwargs) + + # provide an alias Tag = TagRef - + class TagObject(base.Object): - """ - Non-Lightweight tag carrying additional information about an object we are pointing - to. - """ - type = "tag" - __slots__ = ( "object", "tag", "tagger", "tagged_date", "message" ) - - def __init__(self, repo, id, size=None, object=None, tag=None, - tagger=None, tagged_date=None, message=None): - """ - Initialize a tag object with additional data - - ``repo`` - repository this object is located in - - ``id`` - SHA1 or ref suitable for git-rev-parse - - ``size`` - Size of the object's data in bytes - - ``object`` - Object instance of object we are pointing to - - ``tag`` - name of this tag - - ``tagger`` - Actor identifying the tagger - - ``tagged_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) - is the DateTime of the tag creation - """ - super(TagObject, self).__init__(repo, id , size) - self.object = object - self.tag = tag - self.tagger = tagger - self.tagged_date = tagged_date - self.message = message - - def __bake__(self): - super(TagObject, self).__bake__() - - output = self.repo.git.cat_file(self.type,self.id) - lines = output.split("\n") - - obj, hexsha = lines[0].split(" ") # object <hexsha> - type_token, type_name = lines[1].split(" ") # type <type_name> - self.object = base.Object.get_type_by_name(type_name)(self.repo, hexsha) - - self.tag = lines[2][4:] # tag <tag name> - - tagger_info = lines[3][7:]# tagger <actor> <date> - self.tagger, self.tagged_date = commit.Commit._actor(tagger_info) - - # line 4 empty - check git source to figure out purpose - self.message = "\n".join(lines[5:]) - - + """ + Non-Lightweight tag carrying additional information about an object we are pointing + to. + """ + type = "tag" + __slots__ = ( "object", "tag", "tagger", "tagged_date", "message" ) + + def __init__(self, repo, id, size=None, object=None, tag=None, + tagger=None, tagged_date=None, message=None): + """ + Initialize a tag object with additional data + + ``repo`` + repository this object is located in + + ``id`` + SHA1 or ref suitable for git-rev-parse + + ``size`` + Size of the object's data in bytes + + ``object`` + Object instance of object we are pointing to + + ``tag`` + name of this tag + + ``tagger`` + Actor identifying the tagger + + ``tagged_date`` : (tm_year, tm_mon, tm_mday, tm_hour, tm_min, tm_sec, tm_wday, tm_yday, tm_isdst) + is the DateTime of the tag creation + """ + super(TagObject, self).__init__(repo, id , size) + self.object = object + self.tag = tag + self.tagger = tagger + self.tagged_date = tagged_date + self.message = message + + def __bake__(self): + super(TagObject, self).__bake__() + + output = self.repo.git.cat_file(self.type,self.id) + lines = output.split("\n") + + obj, hexsha = lines[0].split(" ") # object <hexsha> + type_token, type_name = lines[1].split(" ") # type <type_name> + self.object = base.Object.get_type_by_name(type_name)(self.repo, hexsha) + + self.tag = lines[2][4:] # tag <tag name> + + tagger_info = lines[3][7:]# tagger <actor> <date> + self.tagger, self.tagged_date = commit.Commit._actor(tagger_info) + + # line 4 empty - check git source to figure out purpose + self.message = "\n".join(lines[5:]) + + diff --git a/lib/git/tree.py b/lib/git/tree.py index 6215f875..3d4deb16 100644 --- a/lib/git/tree.py +++ b/lib/git/tree.py @@ -9,97 +9,97 @@ import blob import base class Tree(base.Object): - - type = "tree" - - def __init__(self, repo, id, mode=None, path=None): - super(Tree, self).__init__(repo, id) - self.mode = mode - self.path = path - self._contents = None - - def __bake__(self): - # Read the tree contents. - super(Tree, self).__bake__() - self._contents = {} - for line in self.repo.git.ls_tree(self.id).splitlines(): - obj = self.content_from_string(self.repo, line) - if obj is not None: - self._contents[obj.path] = obj - - @staticmethod - def content_from_string(repo, text): - """ - Parse a content item and create the appropriate object - - ``repo`` - is the Repo - - ``text`` - is the single line containing the items data in `git ls-tree` format - - Returns - ``git.Blob`` or ``git.Tree`` - """ - try: - mode, typ, id, path = text.expandtabs(1).split(" ", 3) - except: - return None - - if typ == "tree": - return Tree(repo, id=id, mode=mode, path=path) - elif typ == "blob": - return blob.Blob(repo, id=id, mode=mode, path=path) - elif typ == "commit": - return None - else: - raise(TypeError, "Invalid type: %s" % typ) - - def __div__(self, file): - """ - Find the named object in this tree's contents - - Examples:: - - >>> Repo('/path/to/python-git').tree/'lib' - <git.Tree "6cc23ee138be09ff8c28b07162720018b244e95e"> - >>> Repo('/path/to/python-git').tree/'README.txt' - <git.Blob "8b1e02c0fb554eed2ce2ef737a68bb369d7527df"> - - Returns - ``git.Blob`` or ``git.Tree`` or ``None`` if not found - """ - return self.get(file) - - @property - def basename(self): - os.path.basename(self.path) - - def __repr__(self): - return '<git.Tree "%s">' % self.id - - # Implement the basics of the dict protocol: - # directories/trees can be seen as object dicts. - def __getitem__(self, key): - return self._contents[key] - - def __iter__(self): - return iter(self._contents) - - def __len__(self): - return len(self._contents) - - def __contains__(self, key): - return key in self._contents - - def get(self, key): - return self._contents.get(key) - - def items(self): - return self._contents.items() - - def keys(self): - return self._contents.keys() - - def values(self): - return self._contents.values() + + type = "tree" + + def __init__(self, repo, id, mode=None, path=None): + super(Tree, self).__init__(repo, id) + self.mode = mode + self.path = path + self._contents = None + + def __bake__(self): + # Read the tree contents. + super(Tree, self).__bake__() + self._contents = {} + for line in self.repo.git.ls_tree(self.id).splitlines(): + obj = self.content_from_string(self.repo, line) + if obj is not None: + self._contents[obj.path] = obj + + @staticmethod + def content_from_string(repo, text): + """ + Parse a content item and create the appropriate object + + ``repo`` + is the Repo + + ``text`` + is the single line containing the items data in `git ls-tree` format + + Returns + ``git.Blob`` or ``git.Tree`` + """ + try: + mode, typ, id, path = text.expandtabs(1).split(" ", 3) + except: + return None + + if typ == "tree": + return Tree(repo, id=id, mode=mode, path=path) + elif typ == "blob": + return blob.Blob(repo, id=id, mode=mode, path=path) + elif typ == "commit": + return None + else: + raise(TypeError, "Invalid type: %s" % typ) + + def __div__(self, file): + """ + Find the named object in this tree's contents + + Examples:: + + >>> Repo('/path/to/python-git').tree/'lib' + <git.Tree "6cc23ee138be09ff8c28b07162720018b244e95e"> + >>> Repo('/path/to/python-git').tree/'README.txt' + <git.Blob "8b1e02c0fb554eed2ce2ef737a68bb369d7527df"> + + Returns + ``git.Blob`` or ``git.Tree`` or ``None`` if not found + """ + return self.get(file) + + @property + def basename(self): + os.path.basename(self.path) + + def __repr__(self): + return '<git.Tree "%s">' % self.id + + # Implement the basics of the dict protocol: + # directories/trees can be seen as object dicts. + def __getitem__(self, key): + return self._contents[key] + + def __iter__(self): + return iter(self._contents) + + def __len__(self): + return len(self._contents) + + def __contains__(self, key): + return key in self._contents + + def get(self, key): + return self._contents.get(key) + + def items(self): + return self._contents.items() + + def keys(self): + return self._contents.keys() + + def values(self): + return self._contents.values() diff --git a/lib/git/utils.py b/lib/git/utils.py index 5d0ba8ca..c204c432 100644 --- a/lib/git/utils.py +++ b/lib/git/utils.py @@ -7,20 +7,20 @@ import os def dashify(string): - return string.replace('_', '-') + return string.replace('_', '-') def touch(filename): - os.utime(filename) + os.utime(filename) def is_git_dir(d): - """ This is taken from the git setup.c:is_git_directory - function.""" + """ This is taken from the git setup.c:is_git_directory + function.""" - if os.path.isdir(d) and \ - os.path.isdir(os.path.join(d, 'objects')) and \ - os.path.isdir(os.path.join(d, 'refs')): - headref = os.path.join(d, 'HEAD') - return os.path.isfile(headref) or \ - (os.path.islink(headref) and - os.readlink(headref).startswith('refs')) - return False + if os.path.isdir(d) and \ + os.path.isdir(os.path.join(d, 'objects')) and \ + os.path.isdir(os.path.join(d, 'refs')): + headref = os.path.join(d, 'HEAD') + return os.path.isfile(headref) or \ + (os.path.islink(headref) and + os.readlink(headref).startswith('refs')) + return False @@ -1,9 +1,9 @@ try: - from setuptools import setup, find_packages + from setuptools import setup, find_packages except ImportError: - from ez_setup import use_setuptools - use_setuptools() - from setuptools import setup, find_packages + from ez_setup import use_setuptools + use_setuptools() + from setuptools import setup, find_packages from distutils.command.build_py import build_py as _build_py from setuptools.command.sdist import sdist as _sdist @@ -15,52 +15,52 @@ VERSION = v.readline().strip() v.close() class build_py(_build_py): - def run(self): - init = path.join(self.build_lib, 'git', '__init__.py') - if path.exists(init): - os.unlink(init) - _build_py.run(self) - _stamp_version(init) - self.byte_compile([init]) + def run(self): + init = path.join(self.build_lib, 'git', '__init__.py') + if path.exists(init): + os.unlink(init) + _build_py.run(self) + _stamp_version(init) + self.byte_compile([init]) class sdist(_sdist): - def make_release_tree (self, base_dir, files): - _sdist.make_release_tree(self, base_dir, files) - orig = path.join('lib', 'git', '__init__.py') - assert path.exists(orig) - dest = path.join(base_dir, orig) - if hasattr(os, 'link') and path.exists(dest): - os.unlink(dest) - self.copy_file(orig, dest) - _stamp_version(dest) + def make_release_tree (self, base_dir, files): + _sdist.make_release_tree(self, base_dir, files) + orig = path.join('lib', 'git', '__init__.py') + assert path.exists(orig) + dest = path.join(base_dir, orig) + if hasattr(os, 'link') and path.exists(dest): + os.unlink(dest) + self.copy_file(orig, dest) + _stamp_version(dest) def _stamp_version(filename): - found, out = False, [] - f = open(filename, 'r') - for line in f: - if '__version__ =' in line: - line = line.replace("'git'", "'%s'" % VERSION) - found = True - out.append(line) - f.close() + found, out = False, [] + f = open(filename, 'r') + for line in f: + if '__version__ =' in line: + line = line.replace("'git'", "'%s'" % VERSION) + found = True + out.append(line) + f.close() - if found: - f = open(filename, 'w') - f.writelines(out) - f.close() + if found: + f = open(filename, 'w') + f.writelines(out) + f.close() setup(name = "GitPython", - cmdclass={'build_py': build_py, 'sdist': sdist}, - version = VERSION, - description = "Python Git Library", - author = "Michael Trier", - author_email = "mtrier@gmail.com", - url = "http://gitorious.org/projects/git-python/", - packages = find_packages('lib'), - package_dir = {'':'lib'}, - license = "BSD License", - long_description = """\ + cmdclass={'build_py': build_py, 'sdist': sdist}, + version = VERSION, + description = "Python Git Library", + author = "Michael Trier", + author_email = "mtrier@gmail.com", + url = "http://gitorious.org/projects/git-python/", + packages = find_packages('lib'), + package_dir = {'':'lib'}, + license = "BSD License", + long_description = """\ GitPython is a python library used to interact with Git repositories. GitPython provides object model access to your git repository. Once you have @@ -70,14 +70,14 @@ trees, blobs, etc. GitPython is a port of the grit library in Ruby created by Tom Preston-Werner and Chris Wanstrath. """, - classifiers = [ - "Development Status :: 3 - Alpha", - "Intended Audience :: Developers", - "License :: OSI Approved :: BSD License", - "Operating System :: OS Independent", - "Programming Language :: Python", - "Programming Language :: Python :: 2.5", - "Programming Language :: Python :: 2.6", - "Topic :: Software Development :: Libraries :: Python Modules", - ] - ) + classifiers = [ + "Development Status :: 3 - Alpha", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 2.5", + "Programming Language :: Python :: 2.6", + "Topic :: Software Development :: Libraries :: Python Modules", + ] + ) diff --git a/test/git/test_actor.py b/test/git/test_actor.py index 862010fc..ae4da507 100644 --- a/test/git/test_actor.py +++ b/test/git/test_actor.py @@ -9,20 +9,20 @@ from test.testlib import * from git import * class TestActor(object): - def test_from_string_should_separate_name_and_email(self): - a = Actor.from_string("Michael Trier <mtrier@example.com>") - assert_equal("Michael Trier", a.name) - assert_equal("mtrier@example.com", a.email) + def test_from_string_should_separate_name_and_email(self): + a = Actor.from_string("Michael Trier <mtrier@example.com>") + assert_equal("Michael Trier", a.name) + assert_equal("mtrier@example.com", a.email) - def test_from_string_should_handle_just_name(self): - a = Actor.from_string("Michael Trier") - assert_equal("Michael Trier", a.name) - assert_equal(None, a.email) + def test_from_string_should_handle_just_name(self): + a = Actor.from_string("Michael Trier") + assert_equal("Michael Trier", a.name) + assert_equal(None, a.email) - def test_should_display_representation(self): - a = Actor.from_string("Michael Trier <mtrier@example.com>") - assert_equal('<git.Actor "Michael Trier <mtrier@example.com>">', repr(a)) + def test_should_display_representation(self): + a = Actor.from_string("Michael Trier <mtrier@example.com>") + assert_equal('<git.Actor "Michael Trier <mtrier@example.com>">', repr(a)) - def test_str_should_alias_name(self): - a = Actor.from_string("Michael Trier <mtrier@example.com>") - assert_equal(a.name, str(a))
\ No newline at end of file + def test_str_should_alias_name(self): + a = Actor.from_string("Michael Trier <mtrier@example.com>") + assert_equal(a.name, str(a))
\ No newline at end of file diff --git a/test/git/test_blob.py b/test/git/test_blob.py index 8741fc1d..e2ac22e1 100644 --- a/test/git/test_blob.py +++ b/test/git/test_blob.py @@ -9,89 +9,89 @@ from test.testlib import * from git import * class TestBlob(object): - def setup(self): - self.repo = Repo(GIT_REPO) - - @patch_object(Git, '_call_process') - def test_should_return_blob_contents(self, git): - git.return_value = fixture('cat_file_blob') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal("Hello world", blob.data) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) + def setup(self): + self.repo = Repo(GIT_REPO) + + @patch_object(Git, '_call_process') + def test_should_return_blob_contents(self, git): + git.return_value = fixture('cat_file_blob') + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal("Hello world", blob.data) + assert_true(git.called) + assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - @patch_object(Git, '_call_process') - def test_should_return_blob_contents_with_newline(self, git): - git.return_value = fixture('cat_file_blob_nl') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal("Hello world\n", blob.data) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - - @patch_object(Git, '_call_process') - def test_should_cache_data(self, git): - git.return_value = fixture('cat_file_blob') - blob = Blob(self.repo, **{'id': 'abc'}) - blob.data - blob.data - assert_true(git.called) - assert_equal(git.call_count, 1) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) + @patch_object(Git, '_call_process') + def test_should_return_blob_contents_with_newline(self, git): + git.return_value = fixture('cat_file_blob_nl') + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal("Hello world\n", blob.data) + assert_true(git.called) + assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) + + @patch_object(Git, '_call_process') + def test_should_cache_data(self, git): + git.return_value = fixture('cat_file_blob') + blob = Blob(self.repo, **{'id': 'abc'}) + blob.data + blob.data + assert_true(git.called) + assert_equal(git.call_count, 1) + assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - @patch_object(Git, '_call_process') - def test_should_return_file_size(self, git): - git.return_value = fixture('cat_file_blob_size') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal(11, blob.size) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) + @patch_object(Git, '_call_process') + def test_should_return_file_size(self, git): + git.return_value = fixture('cat_file_blob_size') + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal(11, blob.size) + assert_true(git.called) + assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) - @patch_object(Git, '_call_process') - def test_should_cache_file_size(self, git): - git.return_value = fixture('cat_file_blob_size') - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal(11, blob.size) - assert_equal(11, blob.size) - assert_true(git.called) - assert_equal(git.call_count, 1) - assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) + @patch_object(Git, '_call_process') + def test_should_cache_file_size(self, git): + git.return_value = fixture('cat_file_blob_size') + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal(11, blob.size) + assert_equal(11, blob.size) + assert_true(git.called) + assert_equal(git.call_count, 1) + assert_equal(git.call_args, (('cat_file', 'abc'), {'s': True})) - def test_mime_type_should_return_mime_type_for_known_types(self): - blob = Blob(self.repo, **{'id': 'abc', 'path': 'foo.png'}) - assert_equal("image/png", blob.mime_type) + def test_mime_type_should_return_mime_type_for_known_types(self): + blob = Blob(self.repo, **{'id': 'abc', 'path': 'foo.png'}) + assert_equal("image/png", blob.mime_type) - def test_mime_type_should_return_text_plain_for_unknown_types(self): - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal("text/plain", blob.mime_type) + def test_mime_type_should_return_text_plain_for_unknown_types(self): + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal("text/plain", blob.mime_type) - @patch_object(Git, '_call_process') - def test_should_display_blame_information(self, git): - git.return_value = fixture('blame') - b = Blob.blame(self.repo, 'master', 'lib/git.py') - assert_equal(13, len(b)) - assert_equal( 2, len(b[0]) ) - # assert_equal(25, reduce(lambda acc, x: acc + len(x[-1]), b)) - assert_equal(hash(b[0][0]), hash(b[9][0])) - c = b[0][0] - assert_true(git.called) - assert_equal(git.call_args, (('blame', 'master', '--', 'lib/git.py'), {'p': True})) - - assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', c.id) - assert_equal('Tom Preston-Werner', c.author.name) - assert_equal('tom@mojombo.com', c.author.email) - assert_equal(time.gmtime(1191997100), c.authored_date) - assert_equal('Tom Preston-Werner', c.committer.name) - assert_equal('tom@mojombo.com', c.committer.email) - assert_equal(time.gmtime(1191997100), c.committed_date) - assert_equal('initial grit setup', c.message) - - # test the 'lines per commit' entries - tlist = b[0][1] - assert_true( tlist ) - assert_true( isinstance( tlist[0], basestring ) ) - assert_true( len( tlist ) < sum( len(t) for t in tlist ) ) # test for single-char bug - + @patch_object(Git, '_call_process') + def test_should_display_blame_information(self, git): + git.return_value = fixture('blame') + b = Blob.blame(self.repo, 'master', 'lib/git.py') + assert_equal(13, len(b)) + assert_equal( 2, len(b[0]) ) + # assert_equal(25, reduce(lambda acc, x: acc + len(x[-1]), b)) + assert_equal(hash(b[0][0]), hash(b[9][0])) + c = b[0][0] + assert_true(git.called) + assert_equal(git.call_args, (('blame', 'master', '--', 'lib/git.py'), {'p': True})) + + assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', c.id) + assert_equal('Tom Preston-Werner', c.author.name) + assert_equal('tom@mojombo.com', c.author.email) + assert_equal(time.gmtime(1191997100), c.authored_date) + assert_equal('Tom Preston-Werner', c.committer.name) + assert_equal('tom@mojombo.com', c.committer.email) + assert_equal(time.gmtime(1191997100), c.committed_date) + assert_equal('initial grit setup', c.message) + + # test the 'lines per commit' entries + tlist = b[0][1] + assert_true( tlist ) + assert_true( isinstance( tlist[0], basestring ) ) + assert_true( len( tlist ) < sum( len(t) for t in tlist ) ) # test for single-char bug + - def test_should_return_appropriate_representation(self): - blob = Blob(self.repo, **{'id': 'abc'}) - assert_equal('<git.Blob "abc">', repr(blob)) + def test_should_return_appropriate_representation(self): + blob = Blob(self.repo, **{'id': 'abc'}) + assert_equal('<git.Blob "abc">', repr(blob)) diff --git a/test/git/test_commit.py b/test/git/test_commit.py index fb376b02..e92c13dd 100644 --- a/test/git/test_commit.py +++ b/test/git/test_commit.py @@ -8,241 +8,241 @@ from test.testlib import * from git import * class TestCommit(object): - def setup(self): - self.repo = Repo(GIT_REPO) + def setup(self): + self.repo = Repo(GIT_REPO) - @patch_object(Git, '_call_process') - def test_bake(self, git): - git.return_value = fixture('rev_list_single') + @patch_object(Git, '_call_process') + def test_bake(self, git): + git.return_value = fixture('rev_list_single') - commit = Commit(self.repo, **{'id': '4c8124ffcf4039d292442eeccabdeca5af5c5017'}) - commit.author # bake + commit = Commit(self.repo, **{'id': '4c8124ffcf4039d292442eeccabdeca5af5c5017'}) + commit.author # bake - assert_equal("Tom Preston-Werner", commit.author.name) - assert_equal("tom@mojombo.com", commit.author.email) + assert_equal("Tom Preston-Werner", commit.author.name) + assert_equal("tom@mojombo.com", commit.author.email) - assert_true(git.called) - assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) + assert_true(git.called) + assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) - @patch_object(Git, '_call_process') - def test_id_abbrev(self, git): - git.return_value = fixture('rev_list_commit_idabbrev') - assert_equal('80f136f', self.repo.commit('80f136f500dfdb8c3e8abf4ae716f875f0a1b57f').id_abbrev) + @patch_object(Git, '_call_process') + def test_id_abbrev(self, git): + git.return_value = fixture('rev_list_commit_idabbrev') + assert_equal('80f136f', self.repo.commit('80f136f500dfdb8c3e8abf4ae716f875f0a1b57f').id_abbrev) - @patch_object(Git, '_call_process') - def test_diff(self, git): - git.return_value = fixture('diff_p') + @patch_object(Git, '_call_process') + def test_diff(self, git): + git.return_value = fixture('diff_p') - diffs = Commit.diff(self.repo, 'master') + diffs = Commit.diff(self.repo, 'master') - assert_equal(15, len(diffs)) + assert_equal(15, len(diffs)) - assert_equal('.gitignore', diffs[0].a_blob.path) - assert_equal('.gitignore', diffs[0].b_blob.path) - assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diffs[0].a_blob.id) - assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diffs[0].b_blob.id) - assert_equal('100644', diffs[0].b_blob.mode) - assert_equal(False, diffs[0].new_file) - assert_equal(False, diffs[0].deleted_file) - assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diffs[0].diff) + assert_equal('.gitignore', diffs[0].a_blob.path) + assert_equal('.gitignore', diffs[0].b_blob.path) + assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diffs[0].a_blob.id) + assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diffs[0].b_blob.id) + assert_equal('100644', diffs[0].b_blob.mode) + assert_equal(False, diffs[0].new_file) + assert_equal(False, diffs[0].deleted_file) + assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diffs[0].diff) - assert_equal('lib/grit/actor.rb', diffs[5].b_blob.path) - assert_equal(None, diffs[5].a_blob) - assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diffs[5].b_blob.id) - assert_equal( None, diffs[5].a_mode ) - assert_equal(True, diffs[5].new_file) + assert_equal('lib/grit/actor.rb', diffs[5].b_blob.path) + assert_equal(None, diffs[5].a_blob) + assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diffs[5].b_blob.id) + assert_equal( None, diffs[5].a_mode ) + assert_equal(True, diffs[5].new_file) - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', 'master'), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', 'master'), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diff_with_rename(self, git): - git.return_value = fixture('diff_rename') + @patch_object(Git, '_call_process') + def test_diff_with_rename(self, git): + git.return_value = fixture('diff_rename') - diffs = Commit.diff(self.repo, 'rename') + diffs = Commit.diff(self.repo, 'rename') - assert_equal(1, len(diffs)) + assert_equal(1, len(diffs)) - diff = diffs[0] - assert_true(diff.renamed) - assert_equal(diff.rename_from, 'AUTHORS') - assert_equal(diff.rename_to, 'CONTRIBUTORS') + diff = diffs[0] + assert_true(diff.renamed) + assert_equal(diff.rename_from, 'AUTHORS') + assert_equal(diff.rename_to, 'CONTRIBUTORS') - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', 'rename'), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', 'rename'), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diff_with_two_commits(self, git): - git.return_value = fixture('diff_2') + @patch_object(Git, '_call_process') + def test_diff_with_two_commits(self, git): + git.return_value = fixture('diff_2') - diffs = Commit.diff(self.repo, '59ddc32', '13d27d5') + diffs = Commit.diff(self.repo, '59ddc32', '13d27d5') - assert_equal(3, len(diffs)) + assert_equal(3, len(diffs)) - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5'), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5'), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diff_with_files(self, git): - git.return_value = fixture('diff_f') + @patch_object(Git, '_call_process') + def test_diff_with_files(self, git): + git.return_value = fixture('diff_f') - diffs = Commit.diff(self.repo, '59ddc32', ['lib']) + diffs = Commit.diff(self.repo, '59ddc32', ['lib']) - assert_equal(1, len(diffs)) - assert_equal('lib/grit/diff.rb', diffs[0].a_blob.path) + assert_equal(1, len(diffs)) + assert_equal('lib/grit/diff.rb', diffs[0].a_blob.path) - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '--', 'lib'), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', '59ddc32', '--', 'lib'), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diff_with_two_commits_and_files(self, git): - git.return_value = fixture('diff_2f') + @patch_object(Git, '_call_process') + def test_diff_with_two_commits_and_files(self, git): + git.return_value = fixture('diff_2f') - diffs = Commit.diff(self.repo, '59ddc32', '13d27d5', ['lib']) + diffs = Commit.diff(self.repo, '59ddc32', '13d27d5', ['lib']) - assert_equal(1, len(diffs)) - assert_equal('lib/grit/commit.rb', diffs[0].a_blob.path) + assert_equal(1, len(diffs)) + assert_equal('lib/grit/commit.rb', diffs[0].a_blob.path) - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5', '--', 'lib'), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', '59ddc32', '13d27d5', '--', 'lib'), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diffs(self, git): - git.return_value = fixture('diff_p') + @patch_object(Git, '_call_process') + def test_diffs(self, git): + git.return_value = fixture('diff_p') - commit = Commit(self.repo, id='91169e1f5fa4de2eaea3f176461f5dc784796769', parents=['038af8c329ef7c1bae4568b98bd5c58510465493']) - diffs = commit.diffs + commit = Commit(self.repo, id='91169e1f5fa4de2eaea3f176461f5dc784796769', parents=['038af8c329ef7c1bae4568b98bd5c58510465493']) + diffs = commit.diffs - assert_equal(15, len(diffs)) + assert_equal(15, len(diffs)) - assert_equal('.gitignore', diffs[0].a_blob.path) - assert_equal('.gitignore', diffs[0].b_blob.path) - assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diffs[0].a_blob.id) - assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diffs[0].b_blob.id) - assert_equal('100644', diffs[0].b_blob.mode) - assert_equal(False, diffs[0].new_file) - assert_equal(False, diffs[0].deleted_file) - assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diffs[0].diff) + assert_equal('.gitignore', diffs[0].a_blob.path) + assert_equal('.gitignore', diffs[0].b_blob.path) + assert_equal('4ebc8aea50e0a67e000ba29a30809d0a7b9b2666', diffs[0].a_blob.id) + assert_equal('2dd02534615434d88c51307beb0f0092f21fd103', diffs[0].b_blob.id) + assert_equal('100644', diffs[0].b_blob.mode) + assert_equal(False, diffs[0].new_file) + assert_equal(False, diffs[0].deleted_file) + assert_equal("--- a/.gitignore\n+++ b/.gitignore\n@@ -1 +1,2 @@\n coverage\n+pkg", diffs[0].diff) - assert_equal('lib/grit/actor.rb', diffs[5].b_blob.path) - assert_equal(None, diffs[5].a_blob) - assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diffs[5].b_blob.id) - assert_equal(True, diffs[5].new_file) + assert_equal('lib/grit/actor.rb', diffs[5].b_blob.path) + assert_equal(None, diffs[5].a_blob) + assert_equal('f733bce6b57c0e5e353206e692b0e3105c2527f4', diffs[5].b_blob.id) + assert_equal(True, diffs[5].new_file) - assert_true(git.called) - assert_equal(git.call_args, (('diff', '-M', - '038af8c329ef7c1bae4568b98bd5c58510465493', - '91169e1f5fa4de2eaea3f176461f5dc784796769', - ), {'full_index': True})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', '-M', + '038af8c329ef7c1bae4568b98bd5c58510465493', + '91169e1f5fa4de2eaea3f176461f5dc784796769', + ), {'full_index': True})) - @patch_object(Git, '_call_process') - def test_diffs_on_initial_import(self, git): - git.return_value = fixture('diff_i') - - commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') - commit.__bake_it__() - diffs = commit.diffs + @patch_object(Git, '_call_process') + def test_diffs_on_initial_import(self, git): + git.return_value = fixture('diff_i') + + commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') + commit.__bake_it__() + diffs = commit.diffs - assert_equal(10, len(diffs)) + assert_equal(10, len(diffs)) - assert_equal('History.txt', diffs[0].b_blob.path) - assert_equal(None, diffs[0].a_blob) - assert_equal('100644', diffs[0].b_blob.mode) - assert_equal('81d2c27608b352814cbe979a6acd678d30219678', diffs[0].b_blob.id) - assert_equal(True, diffs[0].new_file) - assert_equal(False, diffs[0].deleted_file) - assert_equal("--- /dev/null\n+++ b/History.txt\n@@ -0,0 +1,5 @@\n+== 1.0.0 / 2007-10-09\n+\n+* 1 major enhancement\n+ * Birthday!\n+", diffs[0].diff) + assert_equal('History.txt', diffs[0].b_blob.path) + assert_equal(None, diffs[0].a_blob) + assert_equal('100644', diffs[0].b_blob.mode) + assert_equal('81d2c27608b352814cbe979a6acd678d30219678', diffs[0].b_blob.id) + assert_equal(True, diffs[0].new_file) + assert_equal(False, diffs[0].deleted_file) + assert_equal("--- /dev/null\n+++ b/History.txt\n@@ -0,0 +1,5 @@\n+== 1.0.0 / 2007-10-09\n+\n+* 1 major enhancement\n+ * Birthday!\n+", diffs[0].diff) - assert_equal('lib/grit.rb', diffs[5].b_blob.path) - assert_equal(None, diffs[5].a_blob) - assert_equal('32cec87d1e78946a827ddf6a8776be4d81dcf1d1', diffs[5].b_blob.id) - assert_equal(True, diffs[5].new_file) + assert_equal('lib/grit.rb', diffs[5].b_blob.path) + assert_equal(None, diffs[5].a_blob) + assert_equal('32cec87d1e78946a827ddf6a8776be4d81dcf1d1', diffs[5].b_blob.id) + assert_equal(True, diffs[5].new_file) - assert_true(git.called) - assert_equal(git.call_args, (('show', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '-M'), {'full_index': True, 'pretty': 'raw'})) + assert_true(git.called) + assert_equal(git.call_args, (('show', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '-M'), {'full_index': True, 'pretty': 'raw'})) - @patch_object(Git, '_call_process') - def test_diffs_on_initial_import_with_empty_commit(self, git): - git.return_value = fixture('show_empty_commit') - - commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') - diffs = commit.diffs + @patch_object(Git, '_call_process') + def test_diffs_on_initial_import_with_empty_commit(self, git): + git.return_value = fixture('show_empty_commit') + + commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') + diffs = commit.diffs - assert_equal([], diffs) - - assert_true(git.called) - assert_equal(git.call_args, (('show', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '-M'), {'full_index': True, 'pretty': 'raw'})) - - @patch_object(Git, '_call_process') - def test_diffs_with_mode_only_change(self, git): - git.return_value = fixture('diff_mode_only') - - commit = Commit(self.repo, id='91169e1f5fa4de2eaea3f176461f5dc784796769') - commit.__bake_it__() - diffs = commit.diffs - - # in case of mode-only changes, there is no blob - assert_equal(23, len(diffs)) - assert_equal(None, diffs[0].a_blob) - assert_equal(None, diffs[0].b_blob) - assert_equal('100644', diffs[0].a_mode) - assert_equal('100755', diffs[0].b_mode) - - assert_true(git.called) - assert_equal(git.call_args, (('show', '91169e1f5fa4de2eaea3f176461f5dc784796769', '-M'), {'full_index': True, 'pretty': 'raw'})) - - @patch_object(Git, '_call_process') - def test_stats(self, git): - git.return_value = fixture('diff_tree_numstat_root') - - commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') - commit.__bake_it__() - stats = commit.stats - - keys = stats.files.keys() - keys.sort() - assert_equal(["a.txt", "b.txt"], keys) - - assert_true(git.called) - assert_equal(git.call_args, (('diff_tree', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '--'), {'numstat': True, 'root': True })) - - @patch_object(Git, '_call_process') - def test_rev_list_bisect_all(self, git): - """ - 'git rev-list --bisect-all' returns additional information - in the commit header. This test ensures that we properly parse it. - """ - - git.return_value = fixture('rev_list_bisect_all') - - revs = self.repo.git.rev_list('HEAD', - pretty='raw', - first_parent=True, - bisect_all=True) - assert_true(git.called) - - commits = Commit.list_from_string(self.repo, revs) - expected_ids = ( - 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', - '33ebe7acec14b25c5f84f35a664803fcab2f7781', - 'a6604a00a652e754cb8b6b0b9f194f839fc38d7c', - '8df638c22c75ddc9a43ecdde90c0c9939f5009e7', - 'c231551328faa864848bde6ff8127f59c9566e90', - ) - for sha1, commit in zip(expected_ids, commits): - assert_equal(sha1, commit.id) - - def test_str(self): - commit = Commit(self.repo, id='abc') - assert_equal ("abc", str(commit)) - - def test_repr(self): - commit = Commit(self.repo, id='abc') - assert_equal('<git.Commit "abc">', repr(commit)) - - def test_equality(self): - commit1 = Commit(self.repo, id='abc') - commit2 = Commit(self.repo, id='abc') - commit3 = Commit(self.repo, id='zyx') - assert_equal(commit1, commit2) - assert_not_equal(commit2, commit3) + assert_equal([], diffs) + + assert_true(git.called) + assert_equal(git.call_args, (('show', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '-M'), {'full_index': True, 'pretty': 'raw'})) + + @patch_object(Git, '_call_process') + def test_diffs_with_mode_only_change(self, git): + git.return_value = fixture('diff_mode_only') + + commit = Commit(self.repo, id='91169e1f5fa4de2eaea3f176461f5dc784796769') + commit.__bake_it__() + diffs = commit.diffs + + # in case of mode-only changes, there is no blob + assert_equal(23, len(diffs)) + assert_equal(None, diffs[0].a_blob) + assert_equal(None, diffs[0].b_blob) + assert_equal('100644', diffs[0].a_mode) + assert_equal('100755', diffs[0].b_mode) + + assert_true(git.called) + assert_equal(git.call_args, (('show', '91169e1f5fa4de2eaea3f176461f5dc784796769', '-M'), {'full_index': True, 'pretty': 'raw'})) + + @patch_object(Git, '_call_process') + def test_stats(self, git): + git.return_value = fixture('diff_tree_numstat_root') + + commit = Commit(self.repo, id='634396b2f541a9f2d58b00be1a07f0c358b999b3') + commit.__bake_it__() + stats = commit.stats + + keys = stats.files.keys() + keys.sort() + assert_equal(["a.txt", "b.txt"], keys) + + assert_true(git.called) + assert_equal(git.call_args, (('diff_tree', '634396b2f541a9f2d58b00be1a07f0c358b999b3', '--'), {'numstat': True, 'root': True })) + + @patch_object(Git, '_call_process') + def test_rev_list_bisect_all(self, git): + """ + 'git rev-list --bisect-all' returns additional information + in the commit header. This test ensures that we properly parse it. + """ + + git.return_value = fixture('rev_list_bisect_all') + + revs = self.repo.git.rev_list('HEAD', + pretty='raw', + first_parent=True, + bisect_all=True) + assert_true(git.called) + + commits = Commit.list_from_string(self.repo, revs) + expected_ids = ( + 'cf37099ea8d1d8c7fbf9b6d12d7ec0249d3acb8b', + '33ebe7acec14b25c5f84f35a664803fcab2f7781', + 'a6604a00a652e754cb8b6b0b9f194f839fc38d7c', + '8df638c22c75ddc9a43ecdde90c0c9939f5009e7', + 'c231551328faa864848bde6ff8127f59c9566e90', + ) + for sha1, commit in zip(expected_ids, commits): + assert_equal(sha1, commit.id) + + def test_str(self): + commit = Commit(self.repo, id='abc') + assert_equal ("abc", str(commit)) + + def test_repr(self): + commit = Commit(self.repo, id='abc') + assert_equal('<git.Commit "abc">', repr(commit)) + + def test_equality(self): + commit1 = Commit(self.repo, id='abc') + commit2 = Commit(self.repo, id='abc') + commit3 = Commit(self.repo, id='zyx') + assert_equal(commit1, commit2) + assert_not_equal(commit2, commit3) diff --git a/test/git/test_diff.py b/test/git/test_diff.py index 65a27e98..b9834879 100644 --- a/test/git/test_diff.py +++ b/test/git/test_diff.py @@ -8,23 +8,23 @@ from test.testlib import * from git import * class TestDiff(object): - def setup(self): - self.repo = Repo(GIT_REPO) + def setup(self): + self.repo = Repo(GIT_REPO) - def test_list_from_string_new_mode(self): - output = fixture('diff_new_mode') - diffs = Diff.list_from_string(self.repo, output) - assert_equal(1, len(diffs)) - assert_equal(10, len(diffs[0].diff.splitlines())) + def test_list_from_string_new_mode(self): + output = fixture('diff_new_mode') + diffs = Diff.list_from_string(self.repo, output) + assert_equal(1, len(diffs)) + assert_equal(10, len(diffs[0].diff.splitlines())) - def test_diff_with_rename(self): - output = fixture('diff_rename') - diffs = Diff.list_from_string(self.repo, output) + def test_diff_with_rename(self): + output = fixture('diff_rename') + diffs = Diff.list_from_string(self.repo, output) - assert_equal(1, len(diffs)) + assert_equal(1, len(diffs)) - diff = diffs[0] - assert_true(diff.renamed) - assert_equal(diff.rename_from, 'AUTHORS') - assert_equal(diff.rename_to, 'CONTRIBUTORS') + diff = diffs[0] + assert_true(diff.renamed) + assert_equal(diff.rename_from, 'AUTHORS') + assert_equal(diff.rename_to, 'CONTRIBUTORS') diff --git a/test/git/test_git.py b/test/git/test_git.py index 6e28f4c0..c9f399cc 100644 --- a/test/git/test_git.py +++ b/test/git/test_git.py @@ -9,50 +9,50 @@ from test.testlib import * from git import Git, GitCommandError class TestGit(object): - def setup(self): - base = os.path.join(os.path.dirname(__file__), "../..") - self.git = Git(base) - - @patch_object(Git, 'execute') - def test_call_process_calls_execute(self, git): - git.return_value = '' - self.git.version() - assert_true(git.called) - assert_equal(git.call_args, ((['git', 'version'],), {})) - - @raises(GitCommandError) - def test_it_raises_errors(self): - self.git.this_does_not_exist() - - - def test_it_transforms_kwargs_into_git_command_arguments(self): - assert_equal(["-s"], self.git.transform_kwargs(**{'s': True})) - assert_equal(["-s5"], self.git.transform_kwargs(**{'s': 5})) - - assert_equal(["--max-count"], self.git.transform_kwargs(**{'max_count': True})) - assert_equal(["--max-count=5"], self.git.transform_kwargs(**{'max_count': 5})) - - assert_equal(["-s", "-t"], self.git.transform_kwargs(**{'s': True, 't': True})) - - def test_it_executes_git_to_shell_and_returns_result(self): - assert_match('^git version [\d\.]{2}.*$', self.git.execute(["git","version"])) - - def test_it_accepts_stdin(self): - filename = fixture_path("cat_file_blob") - fh = open(filename, 'r') - assert_equal("70c379b63ffa0795fdbfbc128e5a2818397b7ef8", - self.git.hash_object(istream=fh, stdin=True)) - fh.close() - - def test_it_handles_large_input(self): - if sys.platform == 'win32': - output = self.git.execute(["type", "C:\WINDOWS\system32\cmd.exe"]) - else: - output = self.git.execute(["cat", "/bin/bash"]) - assert_true(len(output) > 4096) # at least 4k - - @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) - assert_true("pass_this_kwarg" not in git.call_args[1]) + def setup(self): + base = os.path.join(os.path.dirname(__file__), "../..") + self.git = Git(base) + + @patch_object(Git, 'execute') + def test_call_process_calls_execute(self, git): + git.return_value = '' + self.git.version() + assert_true(git.called) + assert_equal(git.call_args, ((['git', 'version'],), {})) + + @raises(GitCommandError) + def test_it_raises_errors(self): + self.git.this_does_not_exist() + + + def test_it_transforms_kwargs_into_git_command_arguments(self): + assert_equal(["-s"], self.git.transform_kwargs(**{'s': True})) + assert_equal(["-s5"], self.git.transform_kwargs(**{'s': 5})) + + assert_equal(["--max-count"], self.git.transform_kwargs(**{'max_count': True})) + assert_equal(["--max-count=5"], self.git.transform_kwargs(**{'max_count': 5})) + + assert_equal(["-s", "-t"], self.git.transform_kwargs(**{'s': True, 't': True})) + + def test_it_executes_git_to_shell_and_returns_result(self): + assert_match('^git version [\d\.]{2}.*$', self.git.execute(["git","version"])) + + def test_it_accepts_stdin(self): + filename = fixture_path("cat_file_blob") + fh = open(filename, 'r') + assert_equal("70c379b63ffa0795fdbfbc128e5a2818397b7ef8", + self.git.hash_object(istream=fh, stdin=True)) + fh.close() + + def test_it_handles_large_input(self): + if sys.platform == 'win32': + output = self.git.execute(["type", "C:\WINDOWS\system32\cmd.exe"]) + else: + output = self.git.execute(["cat", "/bin/bash"]) + assert_true(len(output) > 4096) # at least 4k + + @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) + assert_true("pass_this_kwarg" not in git.call_args[1]) diff --git a/test/git/test_head.py b/test/git/test_head.py index e3408974..8338552f 100644 --- a/test/git/test_head.py +++ b/test/git/test_head.py @@ -8,25 +8,25 @@ from test.testlib import * from git import * class TestHead(object): - def setup(self): - self.repo = Repo(GIT_REPO) + def setup(self): + self.repo = Repo(GIT_REPO) - @patch_object(Git, '_call_process') - def test_repr(self, git): - git.return_value = fixture('for_each_ref') - - head = self.repo.heads[0] - - assert_equal('<git.Head "%s">' % head.name, repr(head)) - - assert_true(git.called) - assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) + @patch_object(Git, '_call_process') + def test_repr(self, git): + git.return_value = fixture('for_each_ref') + + head = self.repo.heads[0] + + assert_equal('<git.Head "%s">' % head.name, repr(head)) + + assert_true(git.called) + assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) - @patch_object(Git, '_call_process') - def test_ref_with_path_component(self, git): - git.return_value = fixture('for_each_ref_with_path_component') - head = self.repo.heads[0] + @patch_object(Git, '_call_process') + def test_ref_with_path_component(self, git): + git.return_value = fixture('for_each_ref_with_path_component') + head = self.repo.heads[0] - assert_equal('refactoring/feature1', head.name) - assert_true(git.called) - assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) + assert_equal('refactoring/feature1', head.name) + assert_true(git.called) + assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) diff --git a/test/git/test_repo.py b/test/git/test_repo.py index a9d3beaf..e232b065 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -10,255 +10,255 @@ from test.testlib import * from git import * class TestRepo(object): - def setup(self): - self.repo = Repo(GIT_REPO) - - @raises(InvalidGitRepositoryError) - def test_new_should_raise_on_invalid_repo_location(self): - if sys.platform == "win32": - Repo("C:\\WINDOWS\\Temp") - else: - Repo("/tmp") + def setup(self): + self.repo = Repo(GIT_REPO) + + @raises(InvalidGitRepositoryError) + def test_new_should_raise_on_invalid_repo_location(self): + if sys.platform == "win32": + Repo("C:\\WINDOWS\\Temp") + else: + Repo("/tmp") - @raises(NoSuchPathError) - def test_new_should_raise_on_non_existant_path(self): - Repo("repos/foobar") + @raises(NoSuchPathError) + def test_new_should_raise_on_non_existant_path(self): + Repo("repos/foobar") - def test_description(self): - txt = "Test repository" - self.repo.description = txt - assert_equal(self.repo.description, txt) + def test_description(self): + txt = "Test repository" + self.repo.description = txt + assert_equal(self.repo.description, txt) - def test_heads_should_return_array_of_head_objects(self): - for head in self.repo.heads: - assert_equal(Head, head.__class__) + def test_heads_should_return_array_of_head_objects(self): + for head in self.repo.heads: + assert_equal(Head, head.__class__) - @patch_object(Git, '_call_process') - def test_heads_should_populate_head_data(self, git): - git.return_value = fixture('for_each_ref') + @patch_object(Git, '_call_process') + def test_heads_should_populate_head_data(self, git): + git.return_value = fixture('for_each_ref') - head = self.repo.heads[0] - assert_equal('master', head.name) - assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', head.commit.id) + head = self.repo.heads[0] + assert_equal('master', head.name) + assert_equal('634396b2f541a9f2d58b00be1a07f0c358b999b3', head.commit.id) - assert_true(git.called) - assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) + assert_true(git.called) + assert_equal(git.call_args, (('for_each_ref', 'refs/heads'), {'sort': 'committerdate', 'format': '%(refname)%00%(objectname)'})) - @patch_object(Git, '_call_process') - def test_commits(self, git): - git.return_value = fixture('rev_list') + @patch_object(Git, '_call_process') + def test_commits(self, git): + git.return_value = fixture('rev_list') - commits = self.repo.commits('master', max_count=10) + commits = self.repo.commits('master', max_count=10) - c = commits[0] - assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id) - assert_equal(["634396b2f541a9f2d58b00be1a07f0c358b999b3"], [p.id for p in c.parents]) - assert_equal("672eca9b7f9e09c22dcb128c283e8c3c8d7697a4", c.tree.id) - assert_equal("Tom Preston-Werner", c.author.name) - assert_equal("tom@mojombo.com", c.author.email) - assert_equal(time.gmtime(1191999972), c.authored_date) - assert_equal("Tom Preston-Werner", c.committer.name) - assert_equal("tom@mojombo.com", c.committer.email) - assert_equal(time.gmtime(1191999972), c.committed_date) - assert_equal("implement Grit#heads", c.message) + c = commits[0] + assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', c.id) + assert_equal(["634396b2f541a9f2d58b00be1a07f0c358b999b3"], [p.id for p in c.parents]) + assert_equal("672eca9b7f9e09c22dcb128c283e8c3c8d7697a4", c.tree.id) + assert_equal("Tom Preston-Werner", c.author.name) + assert_equal("tom@mojombo.com", c.author.email) + assert_equal(time.gmtime(1191999972), c.authored_date) + assert_equal("Tom Preston-Werner", c.committer.name) + assert_equal("tom@mojombo.com", c.committer.email) + assert_equal(time.gmtime(1191999972), c.committed_date) + assert_equal("implement Grit#heads", c.message) - c = commits[1] - assert_equal([], c.parents) + c = commits[1] + assert_equal([], c.parents) - c = commits[2] - assert_equal(["6e64c55896aabb9a7d8e9f8f296f426d21a78c2c", "7f874954efb9ba35210445be456c74e037ba6af2"], map(lambda p: p.id, c.parents)) - assert_equal("Merge branch 'site'", c.summary) + c = commits[2] + assert_equal(["6e64c55896aabb9a7d8e9f8f296f426d21a78c2c", "7f874954efb9ba35210445be456c74e037ba6af2"], map(lambda p: p.id, c.parents)) + assert_equal("Merge branch 'site'", c.summary) - assert_true(git.called) - assert_equal(git.call_args, (('rev_list', 'master', '--', ''), {'skip': 0, 'pretty': 'raw', 'max_count': 10})) + assert_true(git.called) + assert_equal(git.call_args, (('rev_list', 'master', '--', ''), {'skip': 0, 'pretty': 'raw', 'max_count': 10})) - @patch_object(Git, '_call_process') - def test_commit_count(self, git): - git.return_value = fixture('rev_list_count') + @patch_object(Git, '_call_process') + def test_commit_count(self, git): + git.return_value = fixture('rev_list_count') - assert_equal(655, self.repo.commit_count('master')) + assert_equal(655, self.repo.commit_count('master')) - assert_true(git.called) - assert_equal(git.call_args, (('rev_list', 'master', '--', ''), {})) + assert_true(git.called) + assert_equal(git.call_args, (('rev_list', 'master', '--', ''), {})) - @patch_object(Git, '_call_process') - def test_commit(self, git): - git.return_value = fixture('rev_list_single') + @patch_object(Git, '_call_process') + def test_commit(self, git): + git.return_value = fixture('rev_list_single') - commit = self.repo.commit('4c8124ffcf4039d292442eeccabdeca5af5c5017') + commit = self.repo.commit('4c8124ffcf4039d292442eeccabdeca5af5c5017') - assert_equal("4c8124ffcf4039d292442eeccabdeca5af5c5017", commit.id) + assert_equal("4c8124ffcf4039d292442eeccabdeca5af5c5017", commit.id) - assert_true(git.called) - assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) + assert_true(git.called) + assert_equal(git.call_args, (('rev_list', '4c8124ffcf4039d292442eeccabdeca5af5c5017', '--', ''), {'pretty': 'raw', 'max_count': 1})) - @patch_object(Git, '_call_process') - def test_tree(self, git): - git.return_value = fixture('ls_tree_a') + @patch_object(Git, '_call_process') + def test_tree(self, git): + git.return_value = fixture('ls_tree_a') - tree = self.repo.tree('master') + tree = self.repo.tree('master') - assert_equal(4, len([c for c in tree.values() if isinstance(c, Blob)])) - assert_equal(3, len([c for c in tree.values() if isinstance(c, Tree)])) + assert_equal(4, len([c for c in tree.values() if isinstance(c, Blob)])) + assert_equal(3, len([c for c in tree.values() if isinstance(c, Tree)])) - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Git, '_call_process') - def test_blob(self, git): - git.return_value = fixture('cat_file_blob') + @patch_object(Git, '_call_process') + def test_blob(self, git): + git.return_value = fixture('cat_file_blob') - blob = self.repo.blob("abc") - assert_equal("Hello world", blob.data) + blob = self.repo.blob("abc") + assert_equal("Hello world", blob.data) - assert_true(git.called) - assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) + assert_true(git.called) + assert_equal(git.call_args, (('cat_file', 'abc'), {'p': True, 'with_raw_output': True})) - @patch_object(Repo, '__init__') - @patch_object(Git, '_call_process') - def test_init_bare(self, git, repo): - git.return_value = True - repo.return_value = None + @patch_object(Repo, '__init__') + @patch_object(Git, '_call_process') + def test_init_bare(self, git, repo): + git.return_value = True + repo.return_value = None - Repo.init_bare("repos/foo/bar.git") + Repo.init_bare("repos/foo/bar.git") - assert_true(git.called) - assert_equal(git.call_args, (('init', '--bare'), {})) - assert_true(repo.called) - assert_equal(repo.call_args, (('repos/foo/bar.git',), {})) + assert_true(git.called) + assert_equal(git.call_args, (('init', '--bare'), {})) + assert_true(repo.called) + assert_equal(repo.call_args, (('repos/foo/bar.git',), {})) - @patch_object(Repo, '__init__') - @patch_object(Git, '_call_process') - def test_init_bare_with_options(self, git, repo): - git.return_value = True - repo.return_value = None + @patch_object(Repo, '__init__') + @patch_object(Git, '_call_process') + def test_init_bare_with_options(self, git, repo): + git.return_value = True + repo.return_value = None - Repo.init_bare("repos/foo/bar.git", **{'template': "/baz/sweet"}) + Repo.init_bare("repos/foo/bar.git", **{'template': "/baz/sweet"}) - assert_true(git.called) - assert_equal(git.call_args, (('init', '--bare'), {'template': '/baz/sweet'})) - assert_true(repo.called) - assert_equal(repo.call_args, (('repos/foo/bar.git',), {})) + assert_true(git.called) + assert_equal(git.call_args, (('init', '--bare'), {'template': '/baz/sweet'})) + assert_true(repo.called) + assert_equal(repo.call_args, (('repos/foo/bar.git',), {})) - @patch_object(Repo, '__init__') - @patch_object(Git, '_call_process') - def test_fork_bare(self, git, repo): - git.return_value = None - repo.return_value = None + @patch_object(Repo, '__init__') + @patch_object(Git, '_call_process') + def test_fork_bare(self, git, repo): + git.return_value = None + repo.return_value = None - self.repo.fork_bare("repos/foo/bar.git") + self.repo.fork_bare("repos/foo/bar.git") - assert_true(git.called) - path = os.path.join(absolute_project_path(), '.git') - assert_equal(git.call_args, (('clone', path, 'repos/foo/bar.git'), {'bare': True})) - assert_true(repo.called) + assert_true(git.called) + path = os.path.join(absolute_project_path(), '.git') + assert_equal(git.call_args, (('clone', path, 'repos/foo/bar.git'), {'bare': True})) + assert_true(repo.called) - @patch_object(Repo, '__init__') - @patch_object(Git, '_call_process') - def test_fork_bare_with_options(self, git, repo): - git.return_value = None - repo.return_value = None + @patch_object(Repo, '__init__') + @patch_object(Git, '_call_process') + def test_fork_bare_with_options(self, git, repo): + git.return_value = None + repo.return_value = None - self.repo.fork_bare("repos/foo/bar.git", **{'template': '/awesome'}) + self.repo.fork_bare("repos/foo/bar.git", **{'template': '/awesome'}) - assert_true(git.called) - path = os.path.join(absolute_project_path(), '.git') - assert_equal(git.call_args, (('clone', path, 'repos/foo/bar.git'), - {'bare': True, 'template': '/awesome'})) - assert_true(repo.called) + assert_true(git.called) + path = os.path.join(absolute_project_path(), '.git') + assert_equal(git.call_args, (('clone', path, 'repos/foo/bar.git'), + {'bare': True, 'template': '/awesome'})) + assert_true(repo.called) - @patch_object(Git, '_call_process') - def test_diff(self, git): - self.repo.diff('master^', 'master') + @patch_object(Git, '_call_process') + def test_diff(self, git): + self.repo.diff('master^', 'master') - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', 'master^', 'master', '--'), {})) - self.repo.diff('master^', 'master', 'foo/bar') + self.repo.diff('master^', 'master', 'foo/bar') - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar'), {})) - self.repo.diff('master^', 'master', 'foo/bar', 'foo/baz') + self.repo.diff('master^', 'master', 'foo/bar', 'foo/baz') - assert_true(git.called) - assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar', 'foo/baz'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('diff', 'master^', 'master', '--', 'foo/bar', 'foo/baz'), {})) - @patch_object(Git, '_call_process') - def test_diff_with_parents(self, git): - git.return_value = fixture('diff_p') + @patch_object(Git, '_call_process') + def test_diff_with_parents(self, git): + git.return_value = fixture('diff_p') - diffs = self.repo.commit_diff('master') - assert_equal(15, len(diffs)) - assert_true(git.called) + diffs = self.repo.commit_diff('master') + assert_equal(15, len(diffs)) + assert_true(git.called) - def test_archive_tar(self): - assert self.repo.archive_tar() + def test_archive_tar(self): + assert self.repo.archive_tar() - def test_archive_tar_gz(self): - assert self.repo.archive_tar_gz() + def test_archive_tar_gz(self): + assert self.repo.archive_tar_gz() - @patch('git.utils.touch') - def test_enable_daemon_serve(self, touch): - self.repo.daemon_serve = False - assert_false(self.repo.daemon_serve) + @patch('git.utils.touch') + def test_enable_daemon_serve(self, touch): + self.repo.daemon_serve = False + assert_false(self.repo.daemon_serve) - def test_disable_daemon_serve(self): - self.repo.daemon_serve = True - assert_true(self.repo.daemon_serve) + def test_disable_daemon_serve(self): + self.repo.daemon_serve = True + assert_true(self.repo.daemon_serve) - @patch_object(os.path, 'exists') - def test_alternates_no_file(self, os): - os.return_value = False - assert_equal([], self.repo.alternates) - - assert_true(os.called) - - @patch_object(os, 'remove') - def test_alternates_setter_empty(self, os): - self.repo.alternates = [] - assert_true(os.called) - - def test_repr(self): - path = os.path.join(os.path.abspath(GIT_REPO), '.git') - assert_equal('<git.Repo "%s">' % path, repr(self.repo)) - - @patch_object(Git, '_call_process') - def test_log(self, git): - git.return_value = fixture('rev_list') - assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', self.repo.log()[0].id) - assert_equal('ab25fd8483882c3bda8a458ad2965d2248654335', self.repo.log()[-1].id) - assert_true(git.called) - assert_equal(git.call_count, 2) - assert_equal(git.call_args, (('log', 'master', '--'), {'pretty': 'raw'})) - - @patch_object(Git, '_call_process') - def test_log_with_path_and_options(self, git): - git.return_value = fixture('rev_list') - self.repo.log('master', 'file.rb', **{'max_count': 1}) - assert_true(git.called) - assert_equal(git.call_args, (('log', 'master', '--', 'file.rb'), {'pretty': 'raw', 'max_count': 1})) - - def test_is_dirty_with_bare_repository(self): - self.repo.bare = True - assert_false(self.repo.is_dirty) - - @patch_object(Git, '_call_process') - def test_is_dirty_with_clean_working_dir(self, git): - self.repo.bare = False - git.return_value = '' - assert_false(self.repo.is_dirty) - assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) - - @patch_object(Git, '_call_process') - def test_is_dirty_with_dirty_working_dir(self, git): - self.repo.bare = False - git.return_value = '''-aaa\n+bbb''' - assert_true(self.repo.is_dirty) - assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) - - @patch_object(Git, '_call_process') - def test_active_branch(self, git): - git.return_value = 'refs/heads/major-refactoring' - assert_equal(self.repo.active_branch, 'major-refactoring') - assert_equal(git.call_args, (('symbolic_ref', 'HEAD'), {})) + @patch_object(os.path, 'exists') + def test_alternates_no_file(self, os): + os.return_value = False + assert_equal([], self.repo.alternates) + + assert_true(os.called) + + @patch_object(os, 'remove') + def test_alternates_setter_empty(self, os): + self.repo.alternates = [] + assert_true(os.called) + + def test_repr(self): + path = os.path.join(os.path.abspath(GIT_REPO), '.git') + assert_equal('<git.Repo "%s">' % path, repr(self.repo)) + + @patch_object(Git, '_call_process') + def test_log(self, git): + git.return_value = fixture('rev_list') + assert_equal('4c8124ffcf4039d292442eeccabdeca5af5c5017', self.repo.log()[0].id) + assert_equal('ab25fd8483882c3bda8a458ad2965d2248654335', self.repo.log()[-1].id) + assert_true(git.called) + assert_equal(git.call_count, 2) + assert_equal(git.call_args, (('log', 'master', '--'), {'pretty': 'raw'})) + + @patch_object(Git, '_call_process') + def test_log_with_path_and_options(self, git): + git.return_value = fixture('rev_list') + self.repo.log('master', 'file.rb', **{'max_count': 1}) + assert_true(git.called) + assert_equal(git.call_args, (('log', 'master', '--', 'file.rb'), {'pretty': 'raw', 'max_count': 1})) + + def test_is_dirty_with_bare_repository(self): + self.repo.bare = True + assert_false(self.repo.is_dirty) + + @patch_object(Git, '_call_process') + def test_is_dirty_with_clean_working_dir(self, git): + self.repo.bare = False + git.return_value = '' + assert_false(self.repo.is_dirty) + assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) + + @patch_object(Git, '_call_process') + def test_is_dirty_with_dirty_working_dir(self, git): + self.repo.bare = False + git.return_value = '''-aaa\n+bbb''' + assert_true(self.repo.is_dirty) + assert_equal(git.call_args, (('diff', 'HEAD', '--'), {})) + + @patch_object(Git, '_call_process') + def test_active_branch(self, git): + git.return_value = 'refs/heads/major-refactoring' + assert_equal(self.repo.active_branch, 'major-refactoring') + assert_equal(git.call_args, (('symbolic_ref', 'HEAD'), {})) diff --git a/test/git/test_stats.py b/test/git/test_stats.py index b6f1b60e..0063bb2d 100644 --- a/test/git/test_stats.py +++ b/test/git/test_stats.py @@ -8,20 +8,20 @@ from test.testlib import * from git import * class TestStats(object): - def setup(self): - self.repo = Repo(GIT_REPO) - - def test_list_from_string(self): - output = fixture('diff_numstat') - stats = Stats.list_from_string(self.repo, output) - - assert_equal(2, stats.total['files']) - assert_equal(52, stats.total['lines']) - assert_equal(29, stats.total['insertions']) - assert_equal(23, stats.total['deletions']) - - assert_equal(29, stats.files["a.txt"]['insertions']) - assert_equal(18, stats.files["a.txt"]['deletions']) - - assert_equal(0, stats.files["b.txt"]['insertions']) - assert_equal(5, stats.files["b.txt"]['deletions']) + def setup(self): + self.repo = Repo(GIT_REPO) + + def test_list_from_string(self): + output = fixture('diff_numstat') + stats = Stats.list_from_string(self.repo, output) + + assert_equal(2, stats.total['files']) + assert_equal(52, stats.total['lines']) + assert_equal(29, stats.total['insertions']) + assert_equal(23, stats.total['deletions']) + + assert_equal(29, stats.files["a.txt"]['insertions']) + assert_equal(18, stats.files["a.txt"]['deletions']) + + assert_equal(0, stats.files["b.txt"]['insertions']) + assert_equal(5, stats.files["b.txt"]['deletions']) diff --git a/test/git/test_tree.py b/test/git/test_tree.py index 3946a33c..d52a8e0a 100644 --- a/test/git/test_tree.py +++ b/test/git/test_tree.py @@ -8,142 +8,142 @@ from test.testlib import * from git import * class TestTree(object): - def setup(self): - self.repo = Repo(GIT_REPO) - - @patch_object(Git, '_call_process') - def test_contents_should_cache(self, git): - git.return_value = fixture('ls_tree_a') + fixture('ls_tree_b') - - tree = self.repo.tree('master') - - child = tree['grit'] - child.items() - child.items() - - assert_true(git.called) - assert_equal(2, git.call_count) - assert_equal(git.call_args, (('ls_tree', '34868e6e7384cb5ee51c543a8187fdff2675b5a7'), {})) + def setup(self): + self.repo = Repo(GIT_REPO) + + @patch_object(Git, '_call_process') + def test_contents_should_cache(self, git): + git.return_value = fixture('ls_tree_a') + fixture('ls_tree_b') + + tree = self.repo.tree('master') + + child = tree['grit'] + child.items() + child.items() + + assert_true(git.called) + assert_equal(2, git.call_count) + assert_equal(git.call_args, (('ls_tree', '34868e6e7384cb5ee51c543a8187fdff2675b5a7'), {})) - def test_content_from_string_tree_should_return_tree(self): - text = fixture('ls_tree_a').splitlines()[-1] - tree = Tree.content_from_string(None, text) - - assert_equal(Tree, tree.__class__) - assert_equal("650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44", tree.id) - assert_equal("040000", tree.mode) - assert_equal("test", tree.path) + def test_content_from_string_tree_should_return_tree(self): + text = fixture('ls_tree_a').splitlines()[-1] + tree = Tree.content_from_string(None, text) + + assert_equal(Tree, tree.__class__) + assert_equal("650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44", tree.id) + assert_equal("040000", tree.mode) + assert_equal("test", tree.path) - def test_content_from_string_tree_should_return_blob(self): - text = fixture('ls_tree_b').split("\n")[0] - - tree = Tree.content_from_string(None, text) - - assert_equal(Blob, tree.__class__) - assert_equal("aa94e396335d2957ca92606f909e53e7beaf3fbb", tree.id) - assert_equal("100644", tree.mode) - assert_equal("grit.rb", tree.path) + def test_content_from_string_tree_should_return_blob(self): + text = fixture('ls_tree_b').split("\n")[0] + + tree = Tree.content_from_string(None, text) + + assert_equal(Blob, tree.__class__) + assert_equal("aa94e396335d2957ca92606f909e53e7beaf3fbb", tree.id) + assert_equal("100644", tree.mode) + assert_equal("grit.rb", tree.path) - def test_content_from_string_tree_should_return_commit(self): - text = fixture('ls_tree_commit').split("\n")[1] - - tree = Tree.content_from_string(None, text) - assert_none(tree) - - @raises(TypeError) - def test_content_from_string_invalid_type_should_raise(self): - Tree.content_from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") - - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_slash(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 1 - - tree = self.repo.tree('master') - - assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', (tree/'lib').id) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) - - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + def test_content_from_string_tree_should_return_commit(self): + text = fixture('ls_tree_commit').split("\n")[1] + + tree = Tree.content_from_string(None, text) + assert_none(tree) + + @raises(TypeError) + def test_content_from_string_invalid_type_should_raise(self): + Tree.content_from_string(None, "040000 bogus 650fa3f0c17f1edb4ae53d8dcca4ac59d86e6c44 test") + + @patch_object(Blob, 'size') + @patch_object(Git, '_call_process') + def test_slash(self, git, blob): + git.return_value = fixture('ls_tree_a') + blob.return_value = 1 + + tree = self.repo.tree('master') + + assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', (tree/'lib').id) + assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) + + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_slash_with_zero_length_file(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 0 - - tree = self.repo.tree('master') - - assert_not_none(tree/'README.txt') - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) - - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + @patch_object(Blob, 'size') + @patch_object(Git, '_call_process') + def test_slash_with_zero_length_file(self, git, blob): + git.return_value = fixture('ls_tree_a') + blob.return_value = 0 + + tree = self.repo.tree('master') + + assert_not_none(tree/'README.txt') + assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', (tree/'README.txt').id) + + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Git, '_call_process') - def test_slash_with_commits(self, git): - git.return_value = fixture('ls_tree_commit') + @patch_object(Git, '_call_process') + def test_slash_with_commits(self, git): + git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') - - assert_none(tree/'bar') - assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', (tree/'foo').id) - assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', (tree/'baz').id) + tree = self.repo.tree('master') + + assert_none(tree/'bar') + assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', (tree/'foo').id) + assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', (tree/'baz').id) - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_dict(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 1 + @patch_object(Blob, 'size') + @patch_object(Git, '_call_process') + def test_dict(self, git, blob): + git.return_value = fixture('ls_tree_a') + blob.return_value = 1 - tree = self.repo.tree('master') + tree = self.repo.tree('master') - assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', tree['lib'].id) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) + assert_equal('aa06ba24b4e3f463b3c4a85469d0fb9e5b421cf8', tree['lib'].id) + assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Blob, 'size') - @patch_object(Git, '_call_process') - def test_dict_with_zero_length_file(self, git, blob): - git.return_value = fixture('ls_tree_a') - blob.return_value = 0 + @patch_object(Blob, 'size') + @patch_object(Git, '_call_process') + def test_dict_with_zero_length_file(self, git, blob): + git.return_value = fixture('ls_tree_a') + blob.return_value = 0 - tree = self.repo.tree('master') + tree = self.repo.tree('master') - assert_not_none(tree['README.txt']) - assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) + assert_not_none(tree['README.txt']) + assert_equal('8b1e02c0fb554eed2ce2ef737a68bb369d7527df', tree['README.txt'].id) - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Git, '_call_process') - def test_dict_with_commits(self, git): - git.return_value = fixture('ls_tree_commit') + @patch_object(Git, '_call_process') + def test_dict_with_commits(self, git): + git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') + tree = self.repo.tree('master') - assert_none(tree.get('bar')) - assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', tree['foo'].id) - assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', tree['baz'].id) + assert_none(tree.get('bar')) + assert_equal('2afb47bcedf21663580d5e6d2f406f08f3f65f19', tree['foo'].id) + assert_equal('f623ee576a09ca491c4a27e48c0dfe04be5f4a2e', tree['baz'].id) - assert_true(git.called) - assert_equal(git.call_args, (('ls_tree', 'master'), {})) + assert_true(git.called) + assert_equal(git.call_args, (('ls_tree', 'master'), {})) - @patch_object(Git, '_call_process') - @raises(KeyError) - def test_dict_with_non_existant_file(self, git): - git.return_value = fixture('ls_tree_commit') + @patch_object(Git, '_call_process') + @raises(KeyError) + def test_dict_with_non_existant_file(self, git): + git.return_value = fixture('ls_tree_commit') - tree = self.repo.tree('master') - tree['bar'] + tree = self.repo.tree('master') + tree['bar'] - def test_repr(self): - tree = Tree(self.repo, id='abc') - assert_equal('<git.Tree "abc">', repr(tree)) + def test_repr(self): + tree = Tree(self.repo, id='abc') + assert_equal('<git.Tree "abc">', repr(tree)) diff --git a/test/git/test_utils.py b/test/git/test_utils.py index 327a07ed..2983a14a 100644 --- a/test/git/test_utils.py +++ b/test/git/test_utils.py @@ -9,13 +9,13 @@ from test.testlib import * from git import * class TestUtils(object): - def setup(self): - self.testdict = { - "string": "42", - "int": 42, - "array": [ 42 ], - } + def setup(self): + self.testdict = { + "string": "42", + "int": 42, + "array": [ 42 ], + } - def test_it_should_dashify(self): - assert_equal('this-is-my-argument', dashify('this_is_my_argument')) - assert_equal('foo', dashify('foo')) + def test_it_should_dashify(self): + assert_equal('this-is-my-argument', dashify('this_is_my_argument')) + assert_equal('foo', dashify('foo')) diff --git a/test/testlib/__init__.py b/test/testlib/__init__.py index 77512794..2133eb8c 100644 --- a/test/testlib/__init__.py +++ b/test/testlib/__init__.py @@ -10,4 +10,4 @@ from asserts import * from helper import * __all__ = [ name for name, obj in locals().items() - if not (name.startswith('_') or inspect.ismodule(obj)) ] + if not (name.startswith('_') or inspect.ismodule(obj)) ] diff --git a/test/testlib/asserts.py b/test/testlib/asserts.py index f66af122..8f2acdc9 100644 --- a/test/testlib/asserts.py +++ b/test/testlib/asserts.py @@ -10,29 +10,29 @@ from nose import tools from nose.tools import * __all__ = ['assert_instance_of', 'assert_not_instance_of', - 'assert_none', 'assert_not_none', - 'assert_match', 'assert_not_match'] + tools.__all__ + 'assert_none', 'assert_not_none', + 'assert_match', 'assert_not_match'] + tools.__all__ def assert_instance_of(expected, actual, msg=None): - """Verify that object is an instance of expected """ - assert isinstance(actual, expected), msg + """Verify that object is an instance of expected """ + assert isinstance(actual, expected), msg def assert_not_instance_of(expected, actual, msg=None): - """Verify that object is not an instance of expected """ - assert not isinstance(actual, expected, msg) - + """Verify that object is not an instance of expected """ + assert not isinstance(actual, expected, msg) + def assert_none(actual, msg=None): - """verify that item is None""" - assert_equal(None, actual, msg) + """verify that item is None""" + assert_equal(None, actual, msg) def assert_not_none(actual, msg=None): - """verify that item is None""" - assert_not_equal(None, actual, msg) + """verify that item is None""" + assert_not_equal(None, actual, msg) def assert_match(pattern, string, msg=None): - """verify that the pattern matches the string""" - assert_not_none(re.search(pattern, string), msg) + """verify that the pattern matches the string""" + assert_not_none(re.search(pattern, string), msg) def assert_not_match(pattern, string, msg=None): - """verify that the pattern does not match the string""" - assert_none(re.search(pattern, string), msg)
\ No newline at end of file + """verify that the pattern does not match the string""" + assert_none(re.search(pattern, string), msg)
\ No newline at end of file diff --git a/test/testlib/helper.py b/test/testlib/helper.py index ca262ee4..74f48447 100644 --- a/test/testlib/helper.py +++ b/test/testlib/helper.py @@ -9,11 +9,11 @@ import os GIT_REPO = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) def fixture_path(name): - test_dir = os.path.dirname(os.path.dirname(__file__)) - return os.path.join(test_dir, "fixtures", name) + test_dir = os.path.dirname(os.path.dirname(__file__)) + return os.path.join(test_dir, "fixtures", name) def fixture(name): - return open(fixture_path(name)).read() + return open(fixture_path(name)).read() def absolute_project_path(): - return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) + return os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) |