diff options
-rw-r--r-- | CHANGES | 10 | ||||
-rw-r--r-- | lib/git/__init__.py | 8 | ||||
-rw-r--r-- | lib/git/blob.py | 126 | ||||
-rw-r--r-- | lib/git/diff.py | 2 | ||||
-rw-r--r-- | lib/git/head.py | 49 | ||||
-rw-r--r-- | lib/git/objects/__init__.py | 11 | ||||
-rw-r--r-- | lib/git/objects/base.py (renamed from lib/git/base.py) | 159 | ||||
-rw-r--r-- | lib/git/objects/blob.py | 36 | ||||
-rw-r--r-- | lib/git/objects/commit.py (renamed from lib/git/commit.py) | 6 | ||||
-rw-r--r-- | lib/git/objects/tag.py (renamed from lib/git/tag.py) | 71 | ||||
-rw-r--r-- | lib/git/objects/tree.py (renamed from lib/git/tree.py) | 0 | ||||
-rw-r--r-- | lib/git/objects/util.py | 36 | ||||
-rw-r--r-- | lib/git/refs.py | 241 | ||||
-rw-r--r-- | lib/git/repo.py | 98 | ||||
-rw-r--r-- | test/git/test_base.py | 12 | ||||
-rw-r--r-- | test/git/test_blob.py | 28 | ||||
-rw-r--r-- | test/git/test_repo.py | 27 | ||||
-rw-r--r-- | test/git/test_tag.py | 2 |
18 files changed, 479 insertions, 443 deletions
@@ -17,6 +17,16 @@ General where unique * removed basename method from Objects with path's as it replicated features of os.path +objects Package +---------------- +* blob, tree, tag and commit module have been moved to new objects package. This should + not affect you though unless you explicitly imported individual objects. If you just + used the git package, names did not change. + +Repo +---- +* Moved blame method from Blob to repo as it appeared to belong there much more. + Diff ---- * Members a a_commit and b_commit renamed to a_blob and b_blob - they are populated diff --git a/lib/git/__init__.py b/lib/git/__init__.py index 5ce3c122..6f482128 100644 --- a/lib/git/__init__.py +++ b/lib/git/__init__.py @@ -9,19 +9,17 @@ import inspect __version__ = 'git' +from git.objects import * +from git.refs import * from git.actor import Actor -from git.blob import Blob -from git.commit import Commit from git.diff import Diff from git.errors import InvalidGitRepositoryError, NoSuchPathError, GitCommandError from git.cmd import Git -from git.head import Head from git.repo import Repo from git.stats import Stats -from git.tag import Tag,TagRef,TagObject -from git.tree import Tree 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)) ] diff --git a/lib/git/blob.py b/lib/git/blob.py deleted file mode 100644 index 1fafb128..00000000 --- a/lib/git/blob.py +++ /dev/null @@ -1,126 +0,0 @@ -# blob.py -# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors -# -# This module is part of GitPython and is released under -# the BSD License: http://www.opensource.org/licenses/bsd-license.php - -import mimetypes -import os -import re -import time -from actor import Actor -from commit import Commit -import base - -class Blob(base.IndexObject): - """A Blob encapsulates a git blob object""" - DEFAULT_MIME_TYPE = "text/plain" - type = "blob" - - __slots__ = tuple() - - # 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(.*)$') - - @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 - - @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(False): - 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 diff --git a/lib/git/diff.py b/lib/git/diff.py index 943fb08a..4bc88bf4 100644 --- a/lib/git/diff.py +++ b/lib/git/diff.py @@ -5,7 +5,7 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import re -import blob +import objects.blob as blob class Diff(object): """ diff --git a/lib/git/head.py b/lib/git/head.py deleted file mode 100644 index 42dfd735..00000000 --- a/lib/git/head.py +++ /dev/null @@ -1,49 +0,0 @@ -# head.py -# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors -# -# This module is part of GitPython and is released under -# the BSD License: http://www.opensource.org/licenses/bsd-license.php - -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' - """ - - @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/objects/__init__.py b/lib/git/objects/__init__.py new file mode 100644 index 00000000..39e650b7 --- /dev/null +++ b/lib/git/objects/__init__.py @@ -0,0 +1,11 @@ +""" +Import all submodules main classes into the package space +""" +import inspect +from tag import * +from blob import * +from tree import * +from commit import * + +__all__ = [ name for name, obj in locals().items() + if not (name.startswith('_') or inspect.ismodule(obj)) ]
\ No newline at end of file diff --git a/lib/git/base.py b/lib/git/objects/base.py index 252ebe4b..43aa8dd1 100644 --- a/lib/git/base.py +++ b/lib/git/objects/base.py @@ -109,36 +109,8 @@ class Object(LazyMixin): 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 IndexObject(Object): """ Base for all objects that can be part of the index file , namely Tree, Blob and @@ -188,130 +160,3 @@ class IndexObject(Object): return mode -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 - (shortest) Name of this reference - it may contain path components - """ - # first two path tokens are can be removed as they are - # refs/heads or refs/tags or refs/remotes - tokens = self.path.split('/') - if len(tokens) < 3: - return self.path # could be refs/HEAD - - return '/'.join(tokens[2:]) - - @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) - obj.size = object_size - return cls(full_path, obj) diff --git a/lib/git/objects/blob.py b/lib/git/objects/blob.py new file mode 100644 index 00000000..88ca73d6 --- /dev/null +++ b/lib/git/objects/blob.py @@ -0,0 +1,36 @@ +# blob.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php + +import mimetypes +import base + +class Blob(base.IndexObject): + """A Blob encapsulates a git blob object""" + DEFAULT_MIME_TYPE = "text/plain" + type = "blob" + + __slots__ = tuple() + + + @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 + + + def __repr__(self): + return '<git.Blob "%s">' % self.id diff --git a/lib/git/commit.py b/lib/git/objects/commit.py index 68415be5..c70b03e4 100644 --- a/lib/git/commit.py +++ b/lib/git/objects/commit.py @@ -7,10 +7,10 @@ import re import time -from actor import Actor +from git.actor import Actor from tree import Tree -import diff -import stats +import git.diff as diff +import git.stats as stats import base class Commit(base.Object): diff --git a/lib/git/tag.py b/lib/git/objects/tag.py index 89060ee0..af1022f0 100644 --- a/lib/git/tag.py +++ b/lib/git/objects/tag.py @@ -1,71 +1,15 @@ -# tag.py +# objects.py # Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors # # This module is part of GitPython and is released under # the BSD License: http://www.opensource.org/licenses/bsd-license.php - -import commit +""" +Module containing all object based types. +""" import base +import commit +from util import get_object_type_by_name -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 - - ``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 - - @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 @@ -110,7 +54,7 @@ class TagObject(base.Object): 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.object = get_object_type_by_name(type_name)(self.repo, hexsha) self.tag = lines[2][4:] # tag <tag name> @@ -124,3 +68,4 @@ class TagObject(base.Object): super(TagObject, self)._set_cache_(attr) + diff --git a/lib/git/tree.py b/lib/git/objects/tree.py index 597668ae..597668ae 100644 --- a/lib/git/tree.py +++ b/lib/git/objects/tree.py diff --git a/lib/git/objects/util.py b/lib/git/objects/util.py new file mode 100644 index 00000000..15c1d114 --- /dev/null +++ b/lib/git/objects/util.py @@ -0,0 +1,36 @@ +# util.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php +""" +Module for general utility functions +""" +import commit, tag, blob, tree + +def get_object_type_by_name(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) diff --git a/lib/git/refs.py b/lib/git/refs.py new file mode 100644 index 00000000..cb730edb --- /dev/null +++ b/lib/git/refs.py @@ -0,0 +1,241 @@ +# refs.py +# Copyright (C) 2008, 2009 Michael Trier (mtrier@gmail.com) and contributors +# +# This module is part of GitPython and is released under +# the BSD License: http://www.opensource.org/licenses/bsd-license.php +""" +Module containing all ref based objects +""" +from objects.base import Object +from objects.util import get_object_type_by_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 + (shortest) Name of this reference - it may contain path components + """ + # first two path tokens are can be removed as they are + # refs/heads or refs/tags or refs/remotes + tokens = self.path.split('/') + if len(tokens) < 3: + return self.path # could be refs/HEAD + + return '/'.join(tokens[2:]) + + @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 = get_object_type_by_name(type_name)(repo, hexsha) + obj.size = object_size + return cls(full_path, obj) + + +class Head(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' + """ + + @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 + + + +class TagRef(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 + + ``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 + + @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 diff --git a/lib/git/repo.py b/lib/git/repo.py index 3c872218..6e23dbc6 100644 --- a/lib/git/repo.py +++ b/lib/git/repo.py @@ -5,16 +5,18 @@ # the BSD License: http://www.opensource.org/licenses/bsd-license.php import os +import re import gzip import StringIO +import time + from errors import InvalidGitRepositoryError, NoSuchPathError from utils import touch, is_git_dir from cmd import Git -from head import Head -from blob import Blob -from tag import Tag -from commit import Commit -from tree import Tree +from actor import Actor +from refs import * +from objects import * + class Repo(object): """ @@ -23,6 +25,12 @@ class Repo(object): the log. """ DAEMON_EXPORT_FILE = 'git-daemon-export-ok' + + # 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, path=None): """ @@ -108,6 +116,86 @@ class Repo(object): ``git.Tag[]`` """ return Tag.find_all(self) + + def blame(self, 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 = self.git.blame(commit, '--', file, p=True) + commits = {} + blames = [] + info = None + + for line in data.splitlines(False): + parts = self.re_whitespace.split(line, 1) + firstpart = parts[0] + if self.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 = self.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( self, 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 = self.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 commits(self, start='master', path='', max_count=10, skip=0): """ diff --git a/test/git/test_base.py b/test/git/test_base.py index 8f522cec..a153eb83 100644 --- a/test/git/test_base.py +++ b/test/git/test_base.py @@ -7,8 +7,10 @@ import time from test.testlib import * from git import * -import git.base as base +import git.objects.base as base +import git.refs as refs from itertools import chain +from git.objects.util import get_object_type_by_name class TestBase(object): @@ -60,7 +62,7 @@ class TestBase(object): ref_count = 0 for ref in chain(self.repo.tags, self.repo.heads): ref_count += 1 - assert isinstance(ref, base.Ref) + assert isinstance(ref, refs.Ref) assert str(ref) == ref.name assert repr(ref) assert ref == ref @@ -69,10 +71,10 @@ class TestBase(object): # END for each ref assert len(s) == ref_count - def test_get_type_by_name(self): + def test_get_object_type_by_name(self): for tname in base.Object.TYPES: - assert base.Object in base.Object.get_type_by_name(tname).mro() + assert base.Object in get_object_type_by_name(tname).mro() # END for each known type - assert_raises( ValueError, base.Object.get_type_by_name, "doesntexist" ) + assert_raises( ValueError, get_object_type_by_name, "doesntexist" ) diff --git a/test/git/test_blob.py b/test/git/test_blob.py index 94d3a33b..ebb53d0c 100644 --- a/test/git/test_blob.py +++ b/test/git/test_blob.py @@ -65,34 +65,6 @@ class TestBlob(object): blob = Blob(self.repo, **{'id': 'abc','path': 'something'}) 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 - - 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_repo.py b/test/git/test_repo.py index 421b8256..3e2fb3dc 100644 --- a/test/git/test_repo.py +++ b/test/git/test_repo.py @@ -257,3 +257,30 @@ class TestRepo(object): 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(Git, '_call_process') + def test_should_display_blame_information(self, git): + git.return_value = fixture('blame') + b = self.repo.blame( '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 diff --git a/test/git/test_tag.py b/test/git/test_tag.py index fe3f78cc..2ebb860a 100644 --- a/test/git/test_tag.py +++ b/test/git/test_tag.py @@ -7,7 +7,7 @@ from mock import * from test.testlib import * from git import * -from git.tag import TagObject +from git.objects.tag import TagObject import time class TestTag(object): |