77import os
88from lazy import LazyMixin
99import blob
10+ import submodule
1011
1112class 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 = '' ):
1314LazyMixin .__init__ (self )
1415self .repo = repo
1516self .id = id
1617self .mode = mode
1718self .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
1851self ._contents = None
1952
2053def __bake__ (self ):
@@ -26,12 +59,12 @@ def __bake__(self):
2659# Read the tree contents.
2760self ._contents = {}
2861for 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 )
3063if obj is not None :
3164self ._contents [obj .name ]= obj
3265
3366@staticmethod
34- def content_from_string (repo ,text ):
67+ def content_from_string (repo ,text , commit_context = None , path = '' ):
3568"""
3669 Parse a content item and create the appropriate object
3770
@@ -50,11 +83,13 @@ def content_from_string(repo, text):
5083return None
5184
5285if 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 ]))
5488elif typ == "blob" :
5589return 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 ]))
5893else :
5994raise (TypeError ,"Invalid type: %s" % typ )
6095