comparison wrappers.py @ 331:75f082b5897e

Switch to using url scheme wrappers instead of duplicating each command we wrap. The 'hg svn url' command has been killed; the replacement is '.hg/hgrc'. More stuff related to its disappearance has been stripped, including two tests. HgChangeReceiver now takes a UUID argument, which it uses to ensure that remote repositories remain unchanged. This is a temporary solution, and I'm not entirely satisfied with how it's done either. Access to the UUID file has been isolated in a HgChangeReceiver property. Some more tests have been updated to use ui.pushbuffer()/popbuffer(), and to pass through the Mercurial API. Moved the arguments to wrappers.pull() to the UI configuration. Also, remove HgChangeReceiver.opts in favour of a 'usebranchnames' instance & configuration variable. The name is taken from the ConvertExtension.
author Dan Villiom Podlaski Christiansen <danchr@gmail.com>
date Fri, 15 May 2009 19:18:43 +0200
parents 235022089da6
children
comparison
equal deleted inserted replaced
330:5f8f2fd4fd54 331:75f082b5897e
85 'unified': True, 85 'unified': True,
86 'text': False, 86 'text': False,
87 })) 87 }))
88 ui.write(cmdutil.filterdiff(''.join(it), baserev, newrev)) 88 ui.write(cmdutil.filterdiff(''.join(it), baserev, newrev))
89 89
90 90 def push(repo, dest="default", force=False, revs=None):
91 def push(orig, ui, repo, dest=None, *args, **opts):
92 """push revisions starting at a specified head back to Subversion. 91 """push revisions starting at a specified head back to Subversion.
93 """ 92 """
94 opts.pop('svn', None) # unused in this case 93 assert not revs, 'designated revisions for push remains unimplemented.'
95 svnurl = repo.ui.expandpath(dest or 'default-push', dest or 'default') 94 print dest
96 if not cmdutil.issvnurl(svnurl): 95 ui = repo.ui
97 return orig(ui, repo, dest=dest, *args, **opts) 96 svnurl = util.normalize_url(repo.ui.expandpath(dest))
98 old_encoding = util.swap_out_encoding() 97 old_encoding = util.swap_out_encoding()
99 hge = hg_delta_editor.HgChangeReceiver(repo=repo)
100 svnurl = util.normalize_url(svnurl)
101 # split of #rev; TODO: implement --rev/#rev support 98 # split of #rev; TODO: implement --rev/#rev support
102 svnurl, revs, checkout = hg.parseurl(svnurl, opts.get('rev')) 99 svnurl, revs, checkout = hg.parseurl(svnurl, revs)
103 if svnurl != hge.url: 100 # TODO: do credentials specified in the URL still work?
104 raise hgutil.Abort('wrong subversion url!') 101 user = repo.ui.config('hgsubversion', 'username')
105 svn_commit_hashes = dict(zip(hge.revmap.itervalues(), 102 passwd = repo.ui.config('hgsubversion', 'password')
106 hge.revmap.iterkeys())) 103 svn = svnwrap.SubversionRepo(svnurl, user, passwd)
107 user, passwd = util.getuserpass(opts) 104 hge = hg_delta_editor.HgChangeReceiver(repo=repo, uuid=svn.uuid)
105
106 # Check if we are up-to-date with the Subversion repository.
107 if hge.last_known_revision() != svn.last_changed_rev:
108 # Based on localrepository.push() in localrepo.py:1559.
109 # TODO: Ideally, we would behave exactly like other repositories:
110 # - push everything by default
111 # - handle additional heads in the same way
112 # - allow pushing single revisions, branches, tags or heads using
113 # the -r/--rev flag.
114 if force:
115 ui.warn("note: unsynced remote changes!\n")
116 else:
117 ui.warn("abort: unsynced remote changes!\n")
118 return None, 0
119
108 # Strategy: 120 # Strategy:
109 # 1. Find all outgoing commits from this head 121 # 1. Find all outgoing commits from this head
110 if len(repo.parents()) != 1: 122 if len(repo.parents()) != 1:
111 ui.status('Cowardly refusing to push branch merge\n') 123 ui.status('Cowardly refusing to push branch merge\n')
112 return 1 124 return 1
113 workingrev = repo.parents()[0] 125 workingrev = repo.parents()[0]
114 ui.status('searching for changes\n') 126 ui.status('searching for changes\n')
127 svn_commit_hashes = dict(zip(hge.revmap.itervalues(),
128 hge.revmap.iterkeys()))
115 outgoing = util.outgoing_revisions(ui, repo, hge, svn_commit_hashes, workingrev.node()) 129 outgoing = util.outgoing_revisions(ui, repo, hge, svn_commit_hashes, workingrev.node())
116 if not (outgoing and len(outgoing)): 130 if not (outgoing and len(outgoing)):
117 ui.status('no changes found\n') 131 ui.status('no changes found\n')
118 return 0 132 return 0
119 while outgoing: 133 while outgoing:
141 except cmdutil.NoFilesException: 155 except cmdutil.NoFilesException:
142 ui.warn("Could not push revision %s because it had no changes in svn.\n" % 156 ui.warn("Could not push revision %s because it had no changes in svn.\n" %
143 old_ctx) 157 old_ctx)
144 return 1 158 return 1
145 # 3. Fetch revisions from svn 159 # 3. Fetch revisions from svn
146 # TODO this probably should pass in the source explicitly 160 # TODO: this probably should pass in the source explicitly - rev too?
147 r = pull(None, ui, repo, svn=True, stupid=opts.get('svn_stupid', False), 161 r = pull(repo, source=dest, force=force)
148 username=user, password=passwd)
149 assert not r or r == 0 162 assert not r or r == 0
150 # 4. Find the new head of the target branch 163 # 4. Find the new head of the target branch
151 repo = hg.repository(ui, hge.path)
152 oldtipctx = repo[oldtip] 164 oldtipctx = repo[oldtip]
153 replacement = [c for c in oldtipctx.children() if c not in old_children 165 replacement = [c for c in oldtipctx.children() if c not in old_children
154 and c.branch() == oldtipctx.branch()] 166 and c.branch() == oldtipctx.branch()]
155 assert len(replacement) == 1, 'Replacement node came back as: %r' % replacement 167 assert len(replacement) == 1, 'Replacement node came back as: %r' % replacement
156 replacement = replacement[0] 168 replacement = replacement[0]
159 for needs_transplant in heads: 171 for needs_transplant in heads:
160 def extrafn(ctx, extra): 172 def extrafn(ctx, extra):
161 if ctx.node() == oldest: 173 if ctx.node() == oldest:
162 return 174 return
163 extra['branch'] = ctx.branch() 175 extra['branch'] = ctx.branch()
176 # TODO: can we avoid calling our own rebase wrapper here?
164 rebase(hgrebase.rebase, ui, repo, svn=True, svnextrafn=extrafn, 177 rebase(hgrebase.rebase, ui, repo, svn=True, svnextrafn=extrafn,
165 svnsourcerev=needs_transplant, **opts) 178 svnsourcerev=needs_transplant)
166 repo = hg.repository(ui, hge.path) 179 repo = hg.repository(ui, hge.path)
167 for child in repo[replacement.node()].children(): 180 for child in repo[replacement.node()].children():
168 rebasesrc = node.bin(child.extra().get('rebase_source', node.hex(node.nullid))) 181 rebasesrc = node.bin(child.extra().get('rebase_source', node.hex(node.nullid)))
169 if rebasesrc in outgoing: 182 if rebasesrc in outgoing:
170 while rebasesrc in outgoing: 183 while rebasesrc in outgoing:
173 [child.node(), ] + outgoing[rebsrcindex+1:]) 186 [child.node(), ] + outgoing[rebsrcindex+1:])
174 children = [c for c in child.children() if c.branch() == child.branch()] 187 children = [c for c in child.children() if c.branch() == child.branch()]
175 if children: 188 if children:
176 child = children[0] 189 child = children[0]
177 rebasesrc = node.bin(child.extra().get('rebase_source', node.hex(node.nullid))) 190 rebasesrc = node.bin(child.extra().get('rebase_source', node.hex(node.nullid)))
178 hge = hg_delta_editor.HgChangeReceiver(hge.path, ui_=ui) 191 # TODO: stop constantly creating the HgChangeReceiver instances.
192 hge = hg_delta_editor.HgChangeReceiver(hge.repo, ui_=ui, uuid=svn.uuid)
179 svn_commit_hashes = dict(zip(hge.revmap.itervalues(), hge.revmap.iterkeys())) 193 svn_commit_hashes = dict(zip(hge.revmap.itervalues(), hge.revmap.iterkeys()))
180 util.swap_out_encoding(old_encoding) 194 util.swap_out_encoding(old_encoding)
181 return 0 195 return 0
182 196
183 197
232 commands.update(ui, repo, uprev) 246 commands.update(ui, repo, uprev)
233 247
234 return res 248 return res
235 249
236 250
237 def pull(orig, ui, repo, source="default", *args, **opts): 251 def pull(repo, source="default", rev=None, force=False):
238 """pull new revisions from Subversion 252 """pull new revisions from Subversion
239 253
240 Also takes svn, svn_stupid, and create_new_dest kwargs. 254 Also takes svn, svn_stupid, and create_new_dest kwargs.
241 """ 255 """
242 svn = opts.pop('svn', None) 256 url = repo.ui.expandpath(source)
243 svn_stupid = opts.pop('svn_stupid', False) 257 svn_url = util.normalize_url(url)
244 create_new_dest = opts.pop('create_new_dest', False) 258
245 url = ((repo and repo.ui) or ui).expandpath(source)
246 if orig and not (cmdutil.issvnurl(url) or svn or create_new_dest):
247 return orig(ui, repo, source=source, *args, **opts)
248 svn_url = url
249 svn_url = util.normalize_url(svn_url)
250 # Split off #rev; TODO: implement --rev/#rev support limiting the pulled/cloned revisions 259 # Split off #rev; TODO: implement --rev/#rev support limiting the pulled/cloned revisions
251 svn_url, revs, checkout = hg.parseurl(svn_url, opts.get('rev')) 260 svn_url, revs, checkout = hg.parseurl(svn_url, rev)
252 old_encoding = util.swap_out_encoding() 261 old_encoding = util.swap_out_encoding()
253 # TODO implement skipto support 262 # TODO implement skipto support
254 skipto_rev = 0 263 skipto_rev = 0
255 have_replay = not svn_stupid 264 have_replay = not repo.ui.configbool('hgsubversion', 'stupid')
256 if have_replay and not callable( 265 if have_replay and not callable(
257 delta.svn_txdelta_apply(None, None, None)[0]): #pragma: no cover 266 delta.svn_txdelta_apply(None, None, None)[0]): #pragma: no cover
258 ui.status('You are using old Subversion SWIG bindings. Replay will not' 267 ui.status('You are using old Subversion SWIG bindings. Replay will not'
259 ' work until you upgrade to 1.5.0 or newer. Falling back to' 268 ' work until you upgrade to 1.5.0 or newer. Falling back to'
260 ' a slower method that may be buggier. Please upgrade, or' 269 ' a slower method that may be buggier. Please upgrade, or'
261 ' contribute a patch to use the ctypes bindings instead' 270 ' contribute a patch to use the ctypes bindings instead'
262 ' of SWIG.\n') 271 ' of SWIG.\n')
263 have_replay = False 272 have_replay = False
264 initializing_repo = False 273
265 user, passwd = util.getuserpass(opts) 274 # FIXME: enable this
275 user = repo.ui.config('hgsubversion', 'username')
276 passwd = repo.ui.config('hgsubversion', 'password')
266 svn = svnwrap.SubversionRepo(svn_url, user, passwd) 277 svn = svnwrap.SubversionRepo(svn_url, user, passwd)
267 author_host = ui.config('hgsubversion', 'defaulthost', svn.uuid) 278 hg_editor = hg_delta_editor.HgChangeReceiver(repo=repo, subdir=svn.subdir,
268 tag_locations = ['tags', ] 279 uuid=svn.uuid)
269 authors = opts.pop('svn_authors', None) 280
270 filemap = opts.pop('svn_filemap', None) 281 start = max(hg_editor.last_known_revision(), skipto_rev)
271 if repo: 282 initializing_repo = (hg_editor.last_known_revision() <= 0)
272 hg_editor = hg_delta_editor.HgChangeReceiver(repo=repo, 283 ui = repo.ui
273 subdir=svn.subdir,
274 author_host=author_host,
275 tag_locations=tag_locations,
276 authors=authors,
277 filemap=filemap)
278 else:
279 hg_editor = hg_delta_editor.HgChangeReceiver(ui_=ui,
280 path=create_new_dest,
281 subdir=svn.subdir,
282 author_host=author_host,
283 tag_locations=tag_locations,
284 authors=authors,
285 filemap=filemap)
286 hg_editor.opts = opts
287 if os.path.exists(hg_editor.uuid_file):
288 uuid = open(hg_editor.uuid_file).read()
289 assert uuid == svn.uuid
290 start = hg_editor.last_known_revision()
291 else:
292 open(hg_editor.uuid_file, 'w').write(svn.uuid)
293 open(hg_editor.svn_url_file, 'w').write(svn_url)
294 initializing_repo = True
295 start = skipto_rev
296 284
297 if initializing_repo and start > 0: 285 if initializing_repo and start > 0:
298 raise hgutil.Abort('Revision skipping at repository initialization ' 286 raise hgutil.Abort('Revision skipping at repository initialization '
299 'remains unimplemented.') 287 'remains unimplemented.')
300 288
301 revisions = 0 289 revisions = 0
302 if not initializing_repo:
303 oldheads = len(repo.changelog.heads())
304 290
305 # start converting revisions 291 # start converting revisions
306 for r in svn.revisions(start=start): 292 for r in svn.revisions(start=start):
307 valid = True 293 valid = True
308 hg_editor.update_branch_tag_map_for_rev(r) 294 hg_editor.update_branch_tag_map_for_rev(r)
342 if revisions == 0: 328 if revisions == 0:
343 ui.status(i18n._("no changes found\n")) 329 ui.status(i18n._("no changes found\n"))
344 return 330 return
345 else: 331 else:
346 ui.status("added %d svn revisions\n" % revisions) 332 ui.status("added %d svn revisions\n" % revisions)
347 if not initializing_repo:
348 newheads = len(repo.changelog.heads())
349 # postincoming needs to know if heads were added or removed
350 # calculation based on mercurial.localrepo.addchangegroup
351 # 0 means no changes, 1 no new heads, > 1 new heads, < 0 heads removed
352 modheads = newheads - oldheads + (newheads < oldheads and -1 or 1)
353 commands.postincoming(ui, repo, modheads, opts.get('update'), checkout)
354
355 333
356 def rebase(orig, ui, repo, **opts): 334 def rebase(orig, ui, repo, **opts):
357 """rebase current unpushed revisions onto the Subversion head 335 """rebase current unpushed revisions onto the Subversion head
358 336
359 This moves a line of development from making its own head to the top of 337 This moves a line of development from making its own head to the top of