| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 7bfca5e commit cfd2121
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -71,7 +71,7 @@ def __init__(self, repo, id, tree=None, author=None, authored_date=None, | |||
| 71 | 71 | if parents is not None: | |
| 72 | 72 | self.parents = [Commit(repo, p) for p in parents] | |
| 73 | 73 | if tree is not None: | |
| 74 | - self.tree = Tree(repo, id=tree) | ||
| 74 | + self.tree = Tree(repo, id=tree, commit_context = self.id) | ||
| 75 | 75 | ||
| 76 | 76 | def __bake__(self): | |
| 77 | 77 | """ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,103 @@ | |||
| 1 | + # head.py | ||
| 2 | + # Copyright (C) 2008-2010 Michael Trier (mtrier@gmail.com) and contributors | ||
| 3 | + # | ||
| 4 | + # This module is part of GitPython and is released under | ||
| 5 | + # the BSD License: http://www.opensource.org/licenses/bsd-license.php | ||
| 6 | + | ||
| 7 | + import re | ||
| 8 | + | ||
| 9 | + class Submodule(object): | ||
| 10 | + """ | ||
| 11 | + A Submodule is a named reference to a Commit on another Repo. | ||
| 12 | + Every Submodule instance contains a name and local and remote paths. | ||
| 13 | + | ||
| 14 | + Submodules are very close in behavior to HEAD pointer. It just sits on | ||
| 15 | + top of a structure, in this case, at the end of folders tree, and says | ||
| 16 | + something about that ending. | ||
| 17 | + | ||
| 18 | + Examples:: | ||
| 19 | + >>> repo = Repo("/path/to/repo") | ||
| 20 | + >>> s = repo.commit('master').tree['lib']['mysubmodule_folder'] | ||
| 21 | + >>> s.name | ||
| 22 | + 'mysubmodule_folder' | ||
| 23 | + >>> s.path | ||
| 24 | + '/lib/mysubmodule_folder' | ||
| 25 | + >>> s.url | ||
| 26 | + 'http://example.com/path/to/repo.git' | ||
| 27 | + >>> s.id | ||
| 28 | + "1c09f116cbc2cb4100fb6935bb162daa4723f455" | ||
| 29 | + """ | ||
| 30 | + | ||
| 31 | + def __init__(self, repo=None, id=None, mode=None, name='', | ||
| 32 | + commit_context=None, path=''): | ||
| 33 | + """ | ||
| 34 | + Initialize a newly instanced Submodule | ||
| 35 | + | ||
| 36 | + 'repo' | ||
| 37 | + Pointer to Repo object instance. | ||
| 38 | + 'id' | ||
| 39 | + Is the Sha of the commit on a remote server. This object does NOT | ||
| 40 | + (usually) exist on this, current repo. | ||
| 41 | + 'mode' | ||
| 42 | + A black hole at this time. Trying to keep the input args | ||
| 43 | + similar between Tree, Blob and Subprocess instantiation classes. | ||
| 44 | + 'name' | ||
| 45 | + This is just the last segment in the submodule's full local path. | ||
| 46 | + It's the name of the actual folder to which a submodule is tied. | ||
| 47 | + 'mode' | ||
| 48 | + A black hole at this time. Trying to keep the input args | ||
| 49 | + similar between Tree, Blob and Subprocess instantiation classes. | ||
| 50 | + 'commit_context' | ||
| 51 | + A string with ID of the commit that was the root for the tree | ||
| 52 | + structure that lead us to this folder (Tree object) that contains | ||
| 53 | + this submodule reference. | ||
| 54 | + See comments in Tree object code for background. | ||
| 55 | + 'path' | ||
| 56 | + This is the "longer" version of "name" argument. It includes all | ||
| 57 | + the parent folders we passed on the way from root of the commit to | ||
| 58 | + this point in the folder tree. | ||
| 59 | + Submodules in the .gitmodules are referenced by their full path | ||
| 60 | + and contents of this argument are used to retrieve the URI of the | ||
| 61 | + remote repo tied to this full local path. | ||
| 62 | + Example: "/lib/vendor/vendors_repoA" | ||
| 63 | + """ | ||
| 64 | + self.repo = repo | ||
| 65 | + self.id = id | ||
| 66 | + self.path = path | ||
| 67 | + self.name = name | ||
| 68 | + self._commit_context = commit_context | ||
| 69 | + self._cached_URI = None | ||
| 70 | + | ||
| 71 | + def getURI(self, commit_context = None): | ||
| 72 | + '''Returns the remote repo URI for the submodule. | ||
| 73 | + | ||
| 74 | + This data is NOT stored in the blob or anywhere close. It's in a | ||
| 75 | + .gitmodules file in the root Tree of SOME commit. | ||
| 76 | + | ||
| 77 | + We need to know what commit to look into to look for .gitmodules. | ||
| 78 | + | ||
| 79 | + We try to retain the "origin" commit ID within the object when we | ||
| 80 | + traverse the Tree chain if it started with a particular commit. | ||
| 81 | + | ||
| 82 | + When this does not work, or if you want to override the behavior, | ||
| 83 | + pass the string with commit's ID to the commit_context argument. | ||
| 84 | + ''' | ||
| 85 | + if not self._cached_URI and ( commit_context or self._commit_context ): | ||
| 86 | + _b = self.repo.commit(commit_context or self._commit_context).tree.get('.gitmodules') | ||
| 87 | + if _b: | ||
| 88 | + _m = re.findall( | ||
| 89 | + r'\[submodule "[^\t]+?\s+path\s*=\s*([^\t]+)\s+url\s*=\s*([^\t]+)' | ||
| 90 | + ,'\t'.join(_b.data.splitlines()) | ||
| 91 | + ) | ||
| 92 | + for _e in _m: | ||
| 93 | + if _e[0] == self.path.strip('/'): | ||
| 94 | + self._cached_URI = _e[1].strip().strip('"').strip("'") | ||
| 95 | + break | ||
| 96 | + return self._cached_URI | ||
| 97 | + | ||
| 98 | + @property | ||
| 99 | + def url(self): | ||
| 100 | + return self.getURI() | ||
| 101 | + | ||
| 102 | + def __repr__(self): | ||
| 103 | + return '<git.Submodule "%s">' % self.id | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,14 +7,47 @@ | |||
| 7 | 7 | import os | |
| 8 | 8 | from lazy import LazyMixin | |
| 9 | 9 | import blob | |
| 10 | + import submodule | ||
| 10 | 11 | ||
| 11 | 12 | class Tree(LazyMixin): | |
| 12 | - def __init__(self, repo, id, mode=None, name=None): | ||
| 13 | + def __init__(self, repo, id, mode=None, name=None, commit_context = None, path = ''): | ||
| 13 | 14 | LazyMixin.__init__(self) | |
| 14 | 15 | self.repo = repo | |
| 15 | 16 | self.id = id | |
| 16 | 17 | self.mode = mode | |
| 17 | 18 | self.name = name | |
| 19 | + # commit_context (A string with ID of the commit) is a "crutch" that | ||
| 20 | + # allows us to look up details for submodules, should we find any in | ||
| 21 | + # this particular tree. | ||
| 22 | + # Trees don't have a reference to parent (commit, other tree). | ||
| 23 | + # They can have infinite amounts of parents. | ||
| 24 | + # However, we need to know what commit got us to this particular | ||
| 25 | + # tree if we want to know the URI of the submodule. | ||
| 26 | + # The commit ID of the repo pointed out by submodule is here, in the tree. | ||
| 27 | + # However, the only way to know what URI that submodule refers to is | ||
| 28 | + # to read .gitmodules file that's in the top-most tree of SOME commit. | ||
| 29 | + # Each commit can have a different version of .gitmodule, but through | ||
| 30 | + # tree chain lead to the same Tree instance where the submodule is rooted. | ||
| 31 | + # | ||
| 32 | + # There is a short-cut. If submodule is placed in top-most Tree in a | ||
| 33 | + # commit (i.e. submodule's path value is "mysubmodule") the .gitmodules | ||
| 34 | + # file will be in the same exact tree. YEY! we just read that and know | ||
| 35 | + # the submodule's URI. Shortcut is gone when submodule is nested in the | ||
| 36 | + # commit like so: "commonfolder/otherfolder/mysubmodule" In this case, | ||
| 37 | + # commit's root tree will have "Tree 'commonfolder'" which will have | ||
| 38 | + # "Tree "otherfolder", which will have "Submodule 'mysubmodule'" | ||
| 39 | + # By the time we get to "Tree 'otherfolder'" we don't know where to | ||
| 40 | + # look for ".gitmodules". This is what commit_context is for. | ||
| 41 | + # The only way you get a value here if you either set it by hand, or | ||
| 42 | + # traverse the Tree chain that started with CommitInstance.tree, which | ||
| 43 | + # populates the context upon Tree instantiation. | ||
| 44 | + self.commit_context = commit_context | ||
| 45 | + # path is the friend commit_context. since trees don't have links to | ||
| 46 | + # parents, we have no clue what the "full local path" of a child | ||
| 47 | + # submodule would be. Submodules are listed as "name" in trees and | ||
| 48 | + # as "folder/folder/name" in .gitmodules. path helps us keep up with the | ||
| 49 | + # the folder changes. | ||
| 50 | + self.path = path | ||
| 18 | 51 | self._contents = None | |
| 19 | 52 | ||
| 20 | 53 | def __bake__(self): | |
@@ -26,12 +59,12 @@ def __bake__(self): | |||
| 26 | 59 | # Read the tree contents. | |
| 27 | 60 | self._contents = {} | |
| 28 | 61 | for line in self.repo.git.ls_tree(self.id).splitlines(): | |
| 29 | - obj = self.content_from_string(self.repo, line) | ||
| 62 | + obj = self.content_from_string(self.repo, line, commit_context = self.commit_context, path = self.path) | ||
| 30 | 63 | if obj is not None: | |
| 31 | 64 | self._contents[obj.name] = obj | |
| 32 | 65 | ||
| 33 | 66 | @staticmethod | |
| 34 | - def content_from_string(repo, text): | ||
| 67 | + def content_from_string(repo, text, commit_context = None, path=''): | ||
| 35 | 68 | """ | |
| 36 | 69 | Parse a content item and create the appropriate object | |
| 37 | 70 | ||
@@ -50,11 +83,13 @@ def content_from_string(repo, text): | |||
| 50 | 83 | return None | |
| 51 | 84 | ||
| 52 | 85 | if typ == "tree": | |
| 53 | - return Tree(repo, id=id, mode=mode, name=name) | ||
| 86 | + return Tree(repo, id=id, mode=mode, name=name, | ||
| 87 | + commit_context = commit_context, path='/'.join([path,name])) | ||
| 54 | 88 | elif typ == "blob": | |
| 55 | 89 | return blob.Blob(repo, id=id, mode=mode, name=name) | |
| 56 | - elif typ == "commit": | ||
| 57 | - return None | ||
| 90 | + elif typ == "commit" and mode == '160000': | ||
| 91 | + return submodule.Submodule(repo, id=id, name=name, | ||
| 92 | + commit_context = commit_context, path='/'.join([path,name])) | ||
| 58 | 93 | else: | |
| 59 | 94 | raise(TypeError, "Invalid type: %s" % typ) | |
| 60 | 95 | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments