comparison hgsubversion/svnexternals.py @ 1352:30193fdd5da4

Addressed using relative URLs to actually divert to another server & added DocTest strings. Code has been tested on real-world repositories that use relative references but adding tests which do the round trip testing as a standalone has been beyond me.
author Gadget Steve <gadgetsteve@hotmail.com>
date Sat, 19 Sep 2015 07:27:31 +0100
parents 9d58ca6253a3
children c79fdd5f615d
comparison
equal deleted inserted replaced
1351:9d58ca6253a3 1352:30193fdd5da4
123 def resolvedots(url): 123 def resolvedots(url):
124 """ 124 """
125 Fix references that include .. entries. 125 Fix references that include .. entries.
126 Scans a URL for .. type entries and resolves them but will not allow any 126 Scans a URL for .. type entries and resolves them but will not allow any
127 number of ..s to take us out of domain so http://.. will raise an exception. 127 number of ..s to take us out of domain so http://.. will raise an exception.
128
129 Tests, (Don't know how to construct a round trip for this so doctest):
130 >>> # Relative URL within servers svn area
131 >>> resolvedots(
132 ... "http://some.svn.server/svn/some_repo/../other_repo")
133 'http://some.svn.server/svn/other_repo'
134 >>> # Complex One
135 >>> resolvedots(
136 ... "http://some.svn.server/svn/repo/../other/repo/../../other_repo")
137 'http://some.svn.server/svn/other_repo'
138 >>> # Another Complex One
139 >>> resolvedots(
140 ... "http://some.svn.server/svn/repo/dir/subdir/../../../other_repo/dir")
141 'http://some.svn.server/svn/other_repo/dir'
142 >>> # Last Complex One - SVN Allows this & seen it used even if it is BAD!
143 >>> resolvedots(
144 ... "http://svn.server/svn/my_repo/dir/subdir/../../other_dir")
145 'http://svn.server/svn/my_repo/other_dir'
146 >>> # Outside the SVN Area might be OK
147 >>> resolvedots(
148 ... "http://svn.server/svn/some_repo/../../other_svn_repo")
149 'http://svn.server/other_svn_repo'
150 >>> # Complex One
151 >>> resolvedots(
152 ... "http://some.svn.server/svn/repo/../other/repo/../../other_repo")
153 'http://some.svn.server/svn/other_repo'
154 >>> # On another server is not a relative URL should give an exception
155 >>> resolvedots(
156 ... "http://some.svn.server/svn/some_repo/../../../other_server")
157 Traceback (most recent call last):
158 ...
159 RelativeSourceError: Relative URL cannot be to another server
128 """ 160 """
129 orig = url.split('/') 161 orig = url.split('/')
130 fixed = [] 162 fixed = []
131 for item in orig: 163 for item in orig:
132 if item != '..': 164 if item != '..':
133 fixed.append(item) 165 fixed.append(item)
134 elif len(fixed) > 2: # Don't allow things to go out of domain 166 elif len(fixed) > 3: # Don't allow things to go out of domain
135 fixed.pop() 167 fixed.pop()
136 else: 168 else:
137 raise RelativeSourceError() 169 raise RelativeSourceError(
170 'Relative URL cannot be to another server')
138 return '/'.join(fixed) 171 return '/'.join(fixed)
139 172
173
174
140 def resolvesource(ui, svnroot, source): 175 def resolvesource(ui, svnroot, source):
176 """ Resolve the source as either matching the scheme re or by resolving
177 relative URLs which start with ^ and my include relative .. references.
178
179 >>> root = 'http://some.svn.server/svn/some_repo'
180 >>> resolvesource(None, root, 'http://other.svn.server')
181 'http://other.svn.server'
182 >>> resolvesource(None, root, 'ssh://other.svn.server')
183 'ssh://other.svn.server'
184 >>> resolvesource(None, root, '^/other_repo')
185 'http://some.svn.server/svn/some_repo/other_repo'
186 >>> resolvesource(None, root, '^/sub_repo')
187 'http://some.svn.server/svn/some_repo/sub_repo'
188 >>> resolvesource(None, root, '^/../other_repo')
189 'http://some.svn.server/svn/other_repo'
190 >>> resolvesource(None, root, '^/../../../server/other_repo')
191 Traceback (most recent call last):
192 ...
193 RelativeSourceError: Relative URL cannot be to another server
194 """
141 if re_scheme.search(source): 195 if re_scheme.search(source):
142 return source 196 return source
143 if source.startswith('^/'): 197 if source.startswith('^/'):
144 if svnroot is None: 198 if svnroot is None:
145 raise RelativeSourceError() 199 raise RelativeSourceError()
455 def basestate(self): 509 def basestate(self):
456 # basestate() was introduced by bcb973abcc0b in 2.2 510 # basestate() was introduced by bcb973abcc0b in 2.2
457 if self._state[1] == 'HEAD': 511 if self._state[1] == 'HEAD':
458 return 'HEAD' 512 return 'HEAD'
459 return super(svnsubrepo, self).basestate() 513 return super(svnsubrepo, self).basestate()
514
515 if __name__ == "__main__":
516 import doctest
517 doctest.testmod()