Skip to content

Commit 4c34d5c

Browse files
committed
Split big submodule file into smaller files. Tried to manually get imports right, but its not yet tested
1 parent ebe8f64 commit 4c34d5c

File tree

4 files changed

+369
-345
lines changed

4 files changed

+369
-345
lines changed

Diff for: lib/git/objects/submodule/__init__.py

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2+
from base import *
3+
from root import *

Diff for: lib/git/objects/submodule.py renamed to lib/git/objects/submodule/base.py

+6-345
Original file line numberDiff line numberDiff line change
@@ -1,111 +1,23 @@
1-
import base
2-
from util import Traversable
1+
import git.objects.base
2+
from util import *
3+
from git.objects.util import Traversable
34
from StringIO import StringIO # need a dict to set bloody .name field
45
from git.util import Iterable, join_path_native, to_native_path_linux
5-
from git.config import GitConfigParser, SectionConstraint
6+
from git.config import SectionConstraint
67
from git.exc import InvalidGitRepositoryError, NoSuchPathError
78
import stat
89
import git
910

1011
import os
1112
import sys
12-
import weakref
13+
1314
import shutil
1415

1516
__all__ = ("Submodule", "RootModule")
1617

17-
#{ Utilities
18-
19-
def sm_section(name):
20-
""":return: section title used in .gitmodules configuration file"""
21-
return 'submodule "%s"' % name
22-
23-
def sm_name(section):
24-
""":return: name of the submodule as parsed from the section name"""
25-
section = section.strip()
26-
return section[11:-1]
27-
28-
def mkhead(repo, path):
29-
""":return: New branch/head instance"""
30-
return git.Head(repo, git.Head.to_full_path(path))
31-
32-
def unbare_repo(func):
33-
"""Methods with this decorator raise InvalidGitRepositoryError if they
34-
encounter a bare repository"""
35-
def wrapper(self, *args, **kwargs):
36-
if self.repo.bare:
37-
raise InvalidGitRepositoryError("Method '%s' cannot operate on bare repositories" % func.__name__)
38-
#END bare method
39-
return func(self, *args, **kwargs)
40-
# END wrapper
41-
wrapper.__name__ = func.__name__
42-
return wrapper
43-
44-
def find_first_remote_branch(remotes, branch):
45-
"""Find the remote branch matching the name of the given branch or raise InvalidGitRepositoryError"""
46-
for remote in remotes:
47-
try:
48-
return remote.refs[branch.name]
49-
except IndexError:
50-
continue
51-
# END exception handling
52-
#END for remote
53-
raise InvalidGitRepositoryError("Didn't find remote branch %r in any of the given remotes", branch)
54-
55-
#} END utilities
56-
57-
58-
#{ Classes
59-
60-
class SubmoduleConfigParser(GitConfigParser):
61-
"""
62-
Catches calls to _write, and updates the .gitmodules blob in the index
63-
with the new data, if we have written into a stream. Otherwise it will
64-
add the local file to the index to make it correspond with the working tree.
65-
Additionally, the cache must be cleared
66-
67-
Please note that no mutating method will work in bare mode
68-
"""
69-
70-
def __init__(self, *args, **kwargs):
71-
self._smref = None
72-
self._index = None
73-
self._auto_write = True
74-
super(SubmoduleConfigParser, self).__init__(*args, **kwargs)
75-
76-
#{ Interface
77-
def set_submodule(self, submodule):
78-
"""Set this instance's submodule. It must be called before
79-
the first write operation begins"""
80-
self._smref = weakref.ref(submodule)
81-
82-
def flush_to_index(self):
83-
"""Flush changes in our configuration file to the index"""
84-
assert self._smref is not None
85-
# should always have a file here
86-
assert not isinstance(self._file_or_files, StringIO)
87-
88-
sm = self._smref()
89-
if sm is not None:
90-
index = self._index
91-
if index is None:
92-
index = sm.repo.index
93-
# END handle index
94-
index.add([sm.k_modules_file], write=self._auto_write)
95-
sm._clear_cache()
96-
# END handle weakref
97-
98-
#} END interface
99-
100-
#{ Overridden Methods
101-
def write(self):
102-
rval = super(SubmoduleConfigParser, self).write()
103-
self.flush_to_index()
104-
return rval
105-
# END overridden methods
10618

10719

108-
class Submodule(base.IndexObject, Iterable, Traversable):
20+
class Submodule(git.objects.base.IndexObject, Iterable, Traversable):
10921
"""Implements access to a git submodule. They are special in that their sha
11022
represents a commit in the submodule's repository which is to be checked out
11123
at the path of this instance.
@@ -879,255 +791,4 @@ def iter_items(cls, repo, parent_commit='HEAD'):
879791
# END for each section
880792

881793
#} END iterable interface
882-
883-
884-
class RootModule(Submodule):
885-
"""A (virtual) Root of all submodules in the given repository. It can be used
886-
to more easily traverse all submodules of the master repository"""
887-
888-
__slots__ = tuple()
889-
890-
k_root_name = '__ROOT__'
891-
892-
def __init__(self, repo):
893-
# repo, binsha, mode=None, path=None, name = None, parent_commit=None, url=None, ref=None)
894-
super(RootModule, self).__init__(
895-
repo,
896-
binsha = self.NULL_BIN_SHA,
897-
mode = self.k_default_mode,
898-
path = '',
899-
name = self.k_root_name,
900-
parent_commit = repo.head.commit,
901-
url = '',
902-
branch = mkhead(repo, self.k_head_default)
903-
)
904-
905-
906-
def _clear_cache(self):
907-
"""May not do anything"""
908-
pass
909-
910-
#{ Interface
911-
912-
def update(self, previous_commit=None, recursive=True, force_remove=False, init=True, to_latest_revision=False):
913-
"""Update the submodules of this repository to the current HEAD commit.
914-
This method behaves smartly by determining changes of the path of a submodules
915-
repository, next to changes to the to-be-checked-out commit or the branch to be
916-
checked out. This works if the submodules ID does not change.
917-
Additionally it will detect addition and removal of submodules, which will be handled
918-
gracefully.
919-
920-
:param previous_commit: If set to a commit'ish, the commit we should use
921-
as the previous commit the HEAD pointed to before it was set to the commit it points to now.
922-
If None, it defaults to ORIG_HEAD otherwise, or the parent of the current
923-
commit if it is not given
924-
:param recursive: if True, the children of submodules will be updated as well
925-
using the same technique
926-
:param force_remove: If submodules have been deleted, they will be forcibly removed.
927-
Otherwise the update may fail if a submodule's repository cannot be deleted as
928-
changes have been made to it (see Submodule.update() for more information)
929-
:param init: If we encounter a new module which would need to be initialized, then do it.
930-
:param to_latest_revision: If True, instead of checking out the revision pointed to
931-
by this submodule's sha, the checked out tracking branch will be merged with the
932-
newest remote branch fetched from the repository's origin"""
933-
if self.repo.bare:
934-
raise InvalidGitRepositoryError("Cannot update submodules in bare repositories")
935-
# END handle bare
936-
937-
repo = self.repo
938-
939-
# HANDLE COMMITS
940-
##################
941-
cur_commit = repo.head.commit
942-
if previous_commit is None:
943-
symref = repo.head.orig_head()
944-
try:
945-
previous_commit = symref.commit
946-
except Exception:
947-
pcommits = cur_commit.parents
948-
if pcommits:
949-
previous_commit = pcommits[0]
950-
else:
951-
# in this special case, we just diff against ourselve, which
952-
# means exactly no change
953-
previous_commit = cur_commit
954-
# END handle initial commit
955-
# END no ORIG_HEAD
956-
else:
957-
previous_commit = repo.commit(previous_commit) # obtain commit object
958-
# END handle previous commit
959-
960-
961-
psms = self.list_items(repo, parent_commit=previous_commit)
962-
sms = self.list_items(self.module())
963-
spsms = set(psms)
964-
ssms = set(sms)
965-
966-
# HANDLE REMOVALS
967-
###################
968-
for rsm in (spsms - ssms):
969-
# fake it into thinking its at the current commit to allow deletion
970-
# of previous module. Trigger the cache to be updated before that
971-
#rsm.url
972-
rsm._parent_commit = repo.head.commit
973-
rsm.remove(configuration=False, module=True, force=force_remove)
974-
# END for each removed submodule
975-
976-
# HANDLE PATH RENAMES
977-
#####################
978-
# url changes + branch changes
979-
for csm in (spsms & ssms):
980-
psm = psms[csm.name]
981-
sm = sms[csm.name]
982-
983-
if sm.path != psm.path and psm.module_exists():
984-
# move the module to the new path
985-
psm.move(sm.path, module=True, configuration=False)
986-
# END handle path changes
987-
988-
if sm.module_exists():
989-
# handle url change
990-
if sm.url != psm.url:
991-
# Add the new remote, remove the old one
992-
# This way, if the url just changes, the commits will not
993-
# have to be re-retrieved
994-
nn = '__new_origin__'
995-
smm = sm.module()
996-
rmts = smm.remotes
997-
998-
# don't do anything if we already have the url we search in place
999-
if len([r for r in rmts if r.url == sm.url]) == 0:
1000-
1001-
1002-
assert nn not in [r.name for r in rmts]
1003-
smr = smm.create_remote(nn, sm.url)
1004-
smr.fetch()
1005-
1006-
# If we have a tracking branch, it should be available
1007-
# in the new remote as well.
1008-
if len([r for r in smr.refs if r.remote_head == sm.branch.name]) == 0:
1009-
raise ValueError("Submodule branch named %r was not available in new submodule remote at %r" % (sm.branch.name, sm.url))
1010-
# END head is not detached
1011-
1012-
# now delete the changed one
1013-
rmt_for_deletion = None
1014-
for remote in rmts:
1015-
if remote.url == psm.url:
1016-
rmt_for_deletion = remote
1017-
break
1018-
# END if urls match
1019-
# END for each remote
1020-
1021-
# if we didn't find a matching remote, but have exactly one,
1022-
# we can safely use this one
1023-
if rmt_for_deletion is None:
1024-
if len(rmts) == 1:
1025-
rmt_for_deletion = rmts[0]
1026-
else:
1027-
# if we have not found any remote with the original url
1028-
# we may not have a name. This is a special case,
1029-
# and its okay to fail here
1030-
# Alternatively we could just generate a unique name and leave all
1031-
# existing ones in place
1032-
raise InvalidGitRepositoryError("Couldn't find original remote-repo at url %r" % psm.url)
1033-
#END handle one single remote
1034-
# END handle check we found a remote
1035-
1036-
orig_name = rmt_for_deletion.name
1037-
smm.delete_remote(rmt_for_deletion)
1038-
# NOTE: Currently we leave tags from the deleted remotes
1039-
# as well as separate tracking branches in the possibly totally
1040-
# changed repository ( someone could have changed the url to
1041-
# another project ). At some point, one might want to clean
1042-
# it up, but the danger is high to remove stuff the user
1043-
# has added explicitly
1044-
1045-
# rename the new remote back to what it was
1046-
smr.rename(orig_name)
1047-
1048-
# early on, we verified that the our current tracking branch
1049-
# exists in the remote. Now we have to assure that the
1050-
# sha we point to is still contained in the new remote
1051-
# tracking branch.
1052-
smsha = sm.binsha
1053-
found = False
1054-
rref = smr.refs[self.branch.name]
1055-
for c in rref.commit.traverse():
1056-
if c.binsha == smsha:
1057-
found = True
1058-
break
1059-
# END traverse all commits in search for sha
1060-
# END for each commit
1061-
1062-
if not found:
1063-
# adjust our internal binsha to use the one of the remote
1064-
# this way, it will be checked out in the next step
1065-
# This will change the submodule relative to us, so
1066-
# the user will be able to commit the change easily
1067-
print >> sys.stderr, "WARNING: Current sha %s was not contained in the tracking branch at the new remote, setting it the the remote's tracking branch" % sm.hexsha
1068-
sm.binsha = rref.commit.binsha
1069-
#END reset binsha
1070-
1071-
#NOTE: All checkout is performed by the base implementation of update
1072-
1073-
# END skip remote handling if new url already exists in module
1074-
# END handle url
1075-
1076-
if sm.branch != psm.branch:
1077-
# finally, create a new tracking branch which tracks the
1078-
# new remote branch
1079-
smm = sm.module()
1080-
smmr = smm.remotes
1081-
try:
1082-
tbr = git.Head.create(smm, sm.branch.name)
1083-
except git.GitCommandError, e:
1084-
if e.status != 128:
1085-
raise
1086-
#END handle something unexpected
1087-
1088-
# ... or reuse the existing one
1089-
tbr = git.Head(smm, git.Head.to_full_path(sm.branch.name))
1090-
#END assure tracking branch exists
1091-
1092-
tbr.set_tracking_branch(find_first_remote_branch(smmr, sm.branch))
1093-
# figure out whether the previous tracking branch contains
1094-
# new commits compared to the other one, if not we can
1095-
# delete it.
1096-
try:
1097-
tbr = find_first_remote_branch(smmr, psm.branch)
1098-
if len(smm.git.cherry(tbr, psm.branch)) == 0:
1099-
psm.branch.delete(smm, psm.branch)
1100-
#END delete original tracking branch if there are no changes
1101-
except InvalidGitRepositoryError:
1102-
# ignore it if the previous branch couldn't be found in the
1103-
# current remotes, this just means we can't handle it
1104-
pass
1105-
# END exception handling
1106-
1107-
#NOTE: All checkout is done in the base implementation of update
1108-
1109-
#END handle branch
1110-
#END handle
1111-
# END for each common submodule
1112-
1113-
# FINALLY UPDATE ALL ACTUAL SUBMODULES
1114-
######################################
1115-
for sm in sms:
1116-
# update the submodule using the default method
1117-
sm.update(recursive=True, init=init, to_latest_revision=to_latest_revision)
1118-
1119-
# update recursively depth first - question is which inconsitent
1120-
# state will be better in case it fails somewhere. Defective branch
1121-
# or defective depth. The RootSubmodule type will never process itself,
1122-
# which was done in the previous expression
1123-
if recursive:
1124-
type(self)(sm.module()).update(recursive=True, force_remove=force_remove,
1125-
init=init, to_latest_revision=to_latest_revision)
1126-
#END handle recursive
1127-
# END for each submodule to update
1128794

1129-
def module(self):
1130-
""":return: the actual repository containing the submodules"""
1131-
return self.repo
1132-
#} END interface
1133-
#} END classes

0 commit comments

Comments
 (0)