11import base
2+ from cStringIO import StringIO
3+ from git .config import GitConfigParser
4+ from git .util import join_path_native
5+ from git .exc import InvalidGitRepositoryError , NoSuchPathError
26
37__all__ = ("Submodule" , )
48
@@ -7,10 +11,115 @@ class Submodule(base.IndexObject):
711 represents a commit in the submodule's repository which is to be checked out
812 at the path of this instance.
913 The submodule type does not have a string type associated with it, as it exists
10- solely as a marker in the tree and index"""
14+ solely as a marker in the tree and index.
15+
16+ All methods work in bare and non-bare repositories."""
17+
18+ kModulesFile = '.gitmodules'
1119
1220 # this is a bogus type for base class compatability
1321 type = 'submodule'
1422
15- # TODO: Add functions to retrieve a repo for the submodule, to allow
16- # its initiailization and handling
23+ __slots__ = ('_root_tree' , '_url' , '_ref' )
24+
25+ def _set_cache_ (self , attr ):
26+ if attr == 'size' :
27+ raise ValueError ("Submodules do not have a size as they do not refer to anything in this repository" )
28+ elif attr == '_root_tree' :
29+ # set a default value, which is the root tree of the current head
30+ self ._root_tree = self .repo .tree ()
31+ elif attr in ('path' , '_url' , '_ref' ):
32+ reader = self .config_reader ()
33+ # default submodule values
34+ self ._path = reader .get_value ('path' )
35+ self ._url = reader .get_value ('url' )
36+ # git-python extension values - optional
37+ self ._ref = reader .get_value ('ref' , 'master' )
38+ else :
39+ super (Submodule , self )._set_cache_ (attr )
40+ # END handle attribute name
41+
42+ def _fp_config (self ):
43+ """:return: Configuration file as StringIO - we only access it through the respective blob's data"""
44+ return StringIO (self ._root_tree [self .kModulesFile ].datastream .read ())
45+
46+ def _config_parser (self , read_only ):
47+ """:return: Config Parser constrained to our submodule in read or write mode"""
48+ parser = GitConfigParser (self ._fp_config (), read_only = read_only )
49+ return SectionConstraint (parser , 'submodule "%s"' % self .path )
50+
51+ #{ Edit Interface
52+
53+ @classmethod
54+ def add (cls , repo , path , url , skip_init = False ):
55+ """Add a new submodule to the given repository. This will alter the index
56+ as well as the .gitmodules file, but will not create a new commit.
57+ :param repo: Repository instance which should receive the submodule
58+ :param path: repository-relative path at which the submodule should be located
59+ It will be created as required during the repository initialization.
60+ :param url: git-clone compatible URL, see git-clone reference for more information
61+ :param skip_init: if True, the new repository will not be cloned to its location.
62+ :return: The newly created submodule instance"""
63+
64+ def set_root_tree (self , root_tree ):
65+ """Set this instance to use the given tree which is supposed to contain the
66+ .gitmodules blob.
67+ :param root_tree: Tree'ish reference pointing at the root_tree
68+ :raise ValueError: if the root_tree didn't contain the .gitmodules blob."""
69+ tree = self .repo .tree (root_tree )
70+ if self .kModulesFile not in tree :
71+ raise ValueError ("Tree %s did not contain the %s file" % (root_tree , self .kModulesFile ))
72+ # END handle exceptions
73+ self ._root_tree = tree
74+
75+ # clear the possibly changing values
76+ del (self .path )
77+ del (self ._ref )
78+ del (self ._url )
79+
80+ def config_writer (self ):
81+ """:return: a config writer instance allowing you to read and write the data
82+ belonging to this submodule into the .gitmodules file."""
83+ return self ._config_parser (read_only = False )
84+
85+ #} END edit interface
86+
87+ #{ Query Interface
88+
89+ def module (self ):
90+ """:return: Repo instance initialized from the repository at our submodule path
91+ :raise InvalidGitRepositoryError: if a repository was not available"""
92+ if self .repo .bare :
93+ raise InvalidGitRepositoryError ("Cannot retrieve module repository in bare parent repositories" )
94+ # END handle bare mode
95+
96+ repo_path = join_path_native (self .repo .working_tree_dir , self .path )
97+ try :
98+ return Repo (repo_path )
99+ except (InvalidGitRepositoryError , NoSuchPathError ):
100+ raise InvalidGitRepositoryError ("No valid repository at %s" % self .path )
101+ # END handle exceptions
102+
103+ def ref (self ):
104+ """:return: The reference's name that we are to checkout"""
105+ return self ._ref
106+
107+ def url (self ):
108+ """:return: The url to the repository which our module-repository refers to"""
109+ return self ._url
110+
111+ def root_tree (self ):
112+ """:return: Tree instance referring to the tree which contains the .gitmodules file
113+ we are to use
114+ :note: will always point to the current head's root tree if it was not set explicitly"""
115+ return self ._root_tree
116+
117+ def config_reader (self ):
118+ """:return: ConfigReader instance which allows you to qurey the configuration values
119+ of this submodule, as provided by the .gitmodules file
120+ :note: The config reader will actually read the data directly from the repository
121+ and thus does not need nor care about your working tree.
122+ :note: Should be cached by the caller and only kept as long as needed"""
123+ return self ._config_parser .read_only (read_only = True )
124+
125+ #} END query interface
0 commit comments