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
0 commit comments