|
1 |
| -importbase |
2 |
| -fromutilimportTraversable |
| 1 | +importgit.objects.base |
| 2 | +fromutilimport* |
| 3 | +fromgit.objects.utilimportTraversable |
3 | 4 | fromStringIOimportStringIO# need a dict to set bloody .name field
|
4 | 5 | fromgit.utilimportIterable,join_path_native,to_native_path_linux
|
5 |
| -fromgit.configimportGitConfigParser,SectionConstraint |
| 6 | +fromgit.configimportSectionConstraint |
6 | 7 | fromgit.excimportInvalidGitRepositoryError,NoSuchPathError
|
7 | 8 | importstat
|
8 | 9 | importgit
|
9 | 10 |
|
10 | 11 | importos
|
11 | 12 | importsys
|
12 |
| -importweakref |
| 13 | + |
13 | 14 | importshutil
|
14 | 15 |
|
15 | 16 | __all__= ("Submodule","RootModule")
|
16 | 17 |
|
17 |
| -#{ Utilities |
18 |
| - |
19 |
| -defsm_section(name): |
20 |
| -""":return: section title used in .gitmodules configuration file""" |
21 |
| -return'submodule "%s"'%name |
22 |
| - |
23 |
| -defsm_name(section): |
24 |
| -""":return: name of the submodule as parsed from the section name""" |
25 |
| -section=section.strip() |
26 |
| -returnsection[11:-1] |
27 |
| - |
28 |
| -defmkhead(repo,path): |
29 |
| -""":return: New branch/head instance""" |
30 |
| -returngit.Head(repo,git.Head.to_full_path(path)) |
31 |
| - |
32 |
| -defunbare_repo(func): |
33 |
| -"""Methods with this decorator raise InvalidGitRepositoryError if they |
34 |
| -encounter a bare repository""" |
35 |
| -defwrapper(self,*args,**kwargs): |
36 |
| -ifself.repo.bare: |
37 |
| -raiseInvalidGitRepositoryError("Method '%s' cannot operate on bare repositories"%func.__name__) |
38 |
| -#END bare method |
39 |
| -returnfunc(self,*args,**kwargs) |
40 |
| -# END wrapper |
41 |
| -wrapper.__name__=func.__name__ |
42 |
| -returnwrapper |
43 |
| - |
44 |
| -deffind_first_remote_branch(remotes,branch): |
45 |
| -"""Find the remote branch matching the name of the given branch or raise InvalidGitRepositoryError""" |
46 |
| -forremoteinremotes: |
47 |
| -try: |
48 |
| -returnremote.refs[branch.name] |
49 |
| -exceptIndexError: |
50 |
| -continue |
51 |
| -# END exception handling |
52 |
| -#END for remote |
53 |
| -raiseInvalidGitRepositoryError("Didn't find remote branch %r in any of the given remotes",branch) |
54 |
| - |
55 |
| -#} END utilities |
56 |
| - |
57 |
| - |
58 |
| -#{ Classes |
59 |
| - |
60 |
| -classSubmoduleConfigParser(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 |
| -defset_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 |
| -defflush_to_index(self): |
83 |
| -"""Flush changes in our configuration file to the index""" |
84 |
| -assertself._smrefisnotNone |
85 |
| -# should always have a file here |
86 |
| -assertnotisinstance(self._file_or_files,StringIO) |
87 |
| - |
88 |
| -sm=self._smref() |
89 |
| -ifsmisnotNone: |
90 |
| -index=self._index |
91 |
| -ifindexisNone: |
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 |
| -defwrite(self): |
102 |
| -rval=super(SubmoduleConfigParser,self).write() |
103 |
| -self.flush_to_index() |
104 |
| -returnrval |
105 |
| -# END overridden methods |
106 | 18 |
|
107 | 19 |
|
108 |
| -classSubmodule(base.IndexObject,Iterable,Traversable): |
| 20 | +classSubmodule(git.objects.base.IndexObject,Iterable,Traversable): |
109 | 21 | """Implements access to a git submodule. They are special in that their sha
|
110 | 22 | represents a commit in the submodule's repository which is to be checked out
|
111 | 23 | at the path of this instance.
|
@@ -879,255 +791,4 @@ def iter_items(cls, repo, parent_commit='HEAD'):
|
879 | 791 | # END for each section
|
880 | 792 |
|
881 | 793 | #} END iterable interface
|
882 |
| - |
883 |
| - |
884 |
| -classRootModule(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 |
| -defupdate(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 |
| -ifself.repo.bare: |
934 |
| -raiseInvalidGitRepositoryError("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 |
| -ifprevious_commitisNone: |
943 |
| -symref=repo.head.orig_head() |
944 |
| -try: |
945 |
| -previous_commit=symref.commit |
946 |
| -exceptException: |
947 |
| -pcommits=cur_commit.parents |
948 |
| -ifpcommits: |
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 |
| -forrsmin (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 |
| -forcsmin (spsms&ssms): |
980 |
| -psm=psms[csm.name] |
981 |
| -sm=sms[csm.name] |
982 |
| - |
983 |
| -ifsm.path!=psm.pathandpsm.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 |
| -ifsm.module_exists(): |
989 |
| -# handle url change |
990 |
| -ifsm.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 |
| -iflen([rforrinrmtsifr.url==sm.url])==0: |
1000 |
| - |
1001 |
| - |
1002 |
| -assertnnnotin [r.nameforrinrmts] |
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 |
| -iflen([rforrinsmr.refsifr.remote_head==sm.branch.name])==0: |
1009 |
| -raiseValueError("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 |
| -forremoteinrmts: |
1015 |
| -ifremote.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 |
| -ifrmt_for_deletionisNone: |
1024 |
| -iflen(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 |
| -raiseInvalidGitRepositoryError("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 |
| -forcinrref.commit.traverse(): |
1056 |
| -ifc.binsha==smsha: |
1057 |
| -found=True |
1058 |
| -break |
1059 |
| -# END traverse all commits in search for sha |
1060 |
| -# END for each commit |
1061 |
| - |
1062 |
| -ifnotfound: |
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 |
| -ifsm.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 |
| -exceptgit.GitCommandError,e: |
1084 |
| -ife.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 |
| -iflen(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 |
| -exceptInvalidGitRepositoryError: |
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 |
| -forsminsms: |
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 |
| -ifrecursive: |
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 |
1128 | 794 |
|
1129 |
| -defmodule(self): |
1130 |
| -""":return: the actual repository containing the submodules""" |
1131 |
| -returnself.repo |
1132 |
| -#} END interface |
1133 |
| -#} END classes |