summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Thiel <byronimo@gmail.com>2010-11-16 19:01:27 +0100
committerSebastian Thiel <byronimo@gmail.com>2010-11-16 19:01:27 +0100
commit98e6edb546116cd98abdc3b37c6744e859bbde5c (patch)
treefb8bee3bc39eb5de0e7ef3f18b982cb96134595c
parent3d061a1a506b71234f783628ba54a7bdf79bbce9 (diff)
downloadgitpython-98e6edb546116cd98abdc3b37c6744e859bbde5c.tar.gz
Initial implementation of submodule.add without any tests. These are to come next
-rw-r--r--lib/git/index/base.py8
-rw-r--r--lib/git/objects/submodule.py94
-rw-r--r--test/git/test_submodule.py22
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