Skip to content

Commit cfd2121

Browse files
committed
Added submodule type and handling through Tree listing.
1 parent 7bfca5e commit cfd2121

File tree

3 files changed

+145
-7
lines changed

3 files changed

+145
-7
lines changed

lib/git/commit.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ def __init__(self, repo, id, tree=None, author=None, authored_date=None,
7171
if parents is not None:
7272
self.parents = [Commit(repo, p) for p in parents]
7373
if tree is not None:
74-
self.tree = Tree(repo, id=tree)
74+
self.tree = Tree(repo, id=tree, commit_context = self.id)
7575

7676
def __bake__(self):
7777
"""

lib/git/submodule.py

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff 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

lib/git/tree.py

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,47 @@
77
import os
88
from lazy import LazyMixin
99
import blob
10+
import submodule
1011

1112
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 = ''):
1314
LazyMixin.__init__(self)
1415
self.repo = repo
1516
self.id = id
1617
self.mode = mode
1718
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
1851
self._contents = None
1952

2053
def __bake__(self):
@@ -26,12 +59,12 @@ def __bake__(self):
2659
# Read the tree contents.
2760
self._contents = {}
2861
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)
3063
if obj is not None:
3164
self._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):
5083
return None
5184

5285
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]))
5488
elif typ == "blob":
5589
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]))
5893
else:
5994
raise(TypeError, "Invalid type: %s" % typ)
6095

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy