diff options
author | Sebastian Thiel <byronimo@gmail.com> | 2010-11-16 19:01:27 +0100 |
---|---|---|
committer | Sebastian Thiel <byronimo@gmail.com> | 2010-11-16 19:01:27 +0100 |
commit | 98e6edb546116cd98abdc3b37c6744e859bbde5c (patch) | |
tree | fb8bee3bc39eb5de0e7ef3f18b982cb96134595c | |
parent | 3d061a1a506b71234f783628ba54a7bdf79bbce9 (diff) | |
download | gitpython-98e6edb546116cd98abdc3b37c6744e859bbde5c.tar.gz |
Initial implementation of submodule.add without any tests. These are to come next
-rw-r--r-- | lib/git/index/base.py | 8 | ||||
-rw-r--r-- | lib/git/objects/submodule.py | 94 | ||||
-rw-r--r-- | test/git/test_submodule.py | 22 |
3 files changed, 110 insertions, 14 deletions
diff --git a/lib/git/index/base.py b/lib/git/index/base.py index 05501ba1..a982d5c5 100644 --- a/lib/git/index/base.py +++ b/lib/git/index/base.py @@ -35,7 +35,8 @@ from git.exc import ( ) from git.objects import ( - Blob, + Blob, + Submodule, Tree, Object, Commit, @@ -553,7 +554,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): for item in items: if isinstance(item, basestring): paths.append(self._to_relative_path(item)) - elif isinstance(item, Blob): + elif isinstance(item, (Blob, Submodule)): entries.append(BaseIndexEntry.from_blob(item)) elif isinstance(item, BaseIndexEntry): entries.append(item) @@ -588,7 +589,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): They are added at stage 0 - - Blob object + - Blob or Submodule object Blobs are added as they are assuming a valid mode is set. The file they refer to may or may not exist in the file system, but must be a path relative to our repository. @@ -612,6 +613,7 @@ class IndexFile(LazyMixin, diff.Diffable, Serializable): explicitly set. Please note that Index Entries require binary sha's. :param force: + **CURRENTLY INEFFECTIVE** If True, otherwise ignored or excluded files will be added anyway. As opposed to the git-add command, we enable this flag by default diff --git a/lib/git/objects/submodule.py b/lib/git/objects/submodule.py index 9e8abbd4..93d47999 100644 --- a/lib/git/objects/submodule.py +++ b/lib/git/objects/submodule.py @@ -202,15 +202,101 @@ class Submodule(base.IndexObject, Iterable, Traversable): #{ Edit Interface @classmethod - def add(cls, repo, path, url, skip_init=False): + def add(cls, repo, name, path, url=None, branch=k_head_default, no_checkout=False): """Add a new submodule to the given repository. This will alter the index as well as the .gitmodules file, but will not create a new commit. + If the submodule already exists, no matter if the configuration differs + from the one provided, the existing submodule will be returned. :param repo: Repository instance which should receive the submodule - :param path: repository-relative path at which the submodule should be located + :param name: The name/identifier for the submodule + :param path: repository-relative or absolute path at which the submodule + should be located It will be created as required during the repository initialization. :param url: git-clone compatible URL, see git-clone reference for more information - :param skip_init: if True, the new repository will not be cloned to its location. - :return: The newly created submodule instance""" + If None, the repository is assumed to exist, and the url of the first + remote is taken instead. This is useful if you want to make an existing + repository a submodule of anotherone. + :param branch: branch at which the submodule should (later) be checked out. + The given branch must exist in the remote repository, and will be checked + out locally as a tracking branch. + It will only be written into the configuration if it differs from the + default. + :param no_checkout: if True, and if the repository has to be cloned manually, + no checkout will be performed + :return: The newly created submodule instance + :note: works atomically, such that no change will be done if the repository + update fails for instance""" + if repo.bare: + raise InvalidGitRepositoryError("Cannot add a submodule to bare repositories") + #END handle bare mode + + path = to_native_path_linux(path) + if path.endswith('/'): + path = path[:-1] + # END handle trailing slash + + sm = cls(repo, cls.NULL_BIN_SHA, cls.k_def_mode, path, name) + if sm.exists(): + # reretrieve submodule from tree + return repo.head.commit.tree[path] + # END handle existing + + branch = Head(repo, head.to_full_path(branch)) + has_module = sm.module_exists() + branch_is_default = branch.name == cls.k_head_default + if has_module and url is not None: + if url not in [r.url for r in sm.module().remotes]: + raise ValueError("Specified URL %s does not match any remote url of the repository at %s" % (url, sm.module_path())) + # END check url + # END verify urls match + + mrepo = None + if url is None: + if not has_module: + raise ValueError("A URL was not given and existing repository did not exsit at %s" % path) + # END check url + mrepo = sm.module() + urls = [r.url for r in mrepo.remotes] + if not urls: + raise ValueError("Didn't find any remote url in repository at %s" % sm.module_path()) + # END verify we have url + url = urls[0] + else: + # clone new repo + kwargs = {'n' : no_checkout} + if branch_is_default: + kwargs['b'] = str(branch) + # END setup checkout-branch + mrepo = git.Repo.clone_from(url, path, **kwargs) + # END verify url + + # update configuration and index + writer = sm.config_writer() + writer.set_value('url', url) + writer.set_value('path', path) + + sm._url = url + if not branch_is_default: + # store full path + writer.set_value(cls.k_head_option, branch.path) + sm._branch = branch + # END handle path + del(writer) + + # NOTE: Have to write the repo config file as well, otherwise + # the default implementation will be offended and not update the repository + # Maybe this is a good way to assure it doesn't get into our way, but + # we want to stay backwards compatible too ... . Its so redundant ! + repo.config_writer().set_value(sm_section(sm.name), 'url', url) + + # we deliberatly assume that our head matches our index ! + pcommit = repo.head.commit + sm._parent_commit = pcommit + sm.binsha = mrepo.head.commit.binsha + repo.index.add([sm], write=True) + + return sm + def update(self, recursive=False, init=True, to_latest_revision=False): """Update the repository of this submodule to point to the checkout diff --git a/test/git/test_submodule.py b/test/git/test_submodule.py index 4be7e966..6172fed5 100644 --- a/test/git/test_submodule.py +++ b/test/git/test_submodule.py @@ -50,16 +50,18 @@ class TestSubmodule(TestBase): # test config_reader/writer methods sm.config_reader() + new_smclone_path = None # keep custom paths for later + new_csmclone_path = None # if rwrepo.bare: self.failUnlessRaises(InvalidGitRepositoryError, sm.config_writer) else: writer = sm.config_writer() # for faster checkout, set the url to the local path - new_path = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path)) - writer.set_value('url', new_path) + new_smclone_path = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path)) + writer.set_value('url', new_smclone_path) del(writer) - assert sm.config_reader().get_value('url') == new_path - assert sm.url == new_path + assert sm.config_reader().get_value('url') == new_smclone_path + assert sm.url == new_smclone_path # END handle bare repo smold.config_reader() @@ -88,6 +90,7 @@ class TestSubmodule(TestBase): if rwrepo.bare: self.failUnlessRaises(InvalidGitRepositoryError, sm.module) self.failUnlessRaises(InvalidGitRepositoryError, sm.remove) + self.failUnlessRaises(InvalidGitRepositoryError, sm.add, rwrepo, 'here', 'there') else: # its not checked out in our case self.failUnlessRaises(InvalidGitRepositoryError, sm.module) @@ -121,9 +124,9 @@ class TestSubmodule(TestBase): assert not csm.module_exists() # adjust the path of the submodules module to point to the local destination - new_csm_path = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path, csm.path)) - csm.config_writer().set_value('url', new_csm_path) - assert csm.url == new_csm_path + new_csmclone_path = to_native_path_linux(join_path_native(self.rorepo.working_tree_dir, sm.path, csm.path)) + csm.config_writer().set_value('url', new_csmclone_path) + assert csm.url == new_csmclone_path # update recuesively again sm.update(recursive=True) @@ -205,6 +208,11 @@ class TestSubmodule(TestBase): sm.remove() assert not sm.exists() assert not sm.module_exists() + + # ADD NEW SUBMODULE + ################### + # raise if url does not match remote url of existing repo + # END handle bare mode |