##// END OF EJS Templates
clone: use `exchange.push` instead of `localrepo.push`...
Pierre-Yves David -
r22618:ce95c15f default
parent child Browse files
Show More
@@ -1,679 +1,679 b''
1 # hg.py - repository classes for mercurial
1 # hg.py - repository classes for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 from i18n import _
9 from i18n import _
10 from lock import release
10 from lock import release
11 from node import hex, nullid
11 from node import hex, nullid
12 import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
12 import localrepo, bundlerepo, unionrepo, httppeer, sshpeer, statichttprepo
13 import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
13 import bookmarks, lock, util, extensions, error, node, scmutil, phases, url
14 import cmdutil, discovery, repoview
14 import cmdutil, discovery, repoview, exchange
15 import merge as mergemod
15 import merge as mergemod
16 import verify as verifymod
16 import verify as verifymod
17 import errno, os, shutil
17 import errno, os, shutil
18
18
19 def _local(path):
19 def _local(path):
20 path = util.expandpath(util.urllocalpath(path))
20 path = util.expandpath(util.urllocalpath(path))
21 return (os.path.isfile(path) and bundlerepo or localrepo)
21 return (os.path.isfile(path) and bundlerepo or localrepo)
22
22
23 def addbranchrevs(lrepo, other, branches, revs):
23 def addbranchrevs(lrepo, other, branches, revs):
24 peer = other.peer() # a courtesy to callers using a localrepo for other
24 peer = other.peer() # a courtesy to callers using a localrepo for other
25 hashbranch, branches = branches
25 hashbranch, branches = branches
26 if not hashbranch and not branches:
26 if not hashbranch and not branches:
27 return revs or None, revs and revs[0] or None
27 return revs or None, revs and revs[0] or None
28 revs = revs and list(revs) or []
28 revs = revs and list(revs) or []
29 if not peer.capable('branchmap'):
29 if not peer.capable('branchmap'):
30 if branches:
30 if branches:
31 raise util.Abort(_("remote branch lookup not supported"))
31 raise util.Abort(_("remote branch lookup not supported"))
32 revs.append(hashbranch)
32 revs.append(hashbranch)
33 return revs, revs[0]
33 return revs, revs[0]
34 branchmap = peer.branchmap()
34 branchmap = peer.branchmap()
35
35
36 def primary(branch):
36 def primary(branch):
37 if branch == '.':
37 if branch == '.':
38 if not lrepo:
38 if not lrepo:
39 raise util.Abort(_("dirstate branch not accessible"))
39 raise util.Abort(_("dirstate branch not accessible"))
40 branch = lrepo.dirstate.branch()
40 branch = lrepo.dirstate.branch()
41 if branch in branchmap:
41 if branch in branchmap:
42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
42 revs.extend(node.hex(r) for r in reversed(branchmap[branch]))
43 return True
43 return True
44 else:
44 else:
45 return False
45 return False
46
46
47 for branch in branches:
47 for branch in branches:
48 if not primary(branch):
48 if not primary(branch):
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
49 raise error.RepoLookupError(_("unknown branch '%s'") % branch)
50 if hashbranch:
50 if hashbranch:
51 if not primary(hashbranch):
51 if not primary(hashbranch):
52 revs.append(hashbranch)
52 revs.append(hashbranch)
53 return revs, revs[0]
53 return revs, revs[0]
54
54
55 def parseurl(path, branches=None):
55 def parseurl(path, branches=None):
56 '''parse url#branch, returning (url, (branch, branches))'''
56 '''parse url#branch, returning (url, (branch, branches))'''
57
57
58 u = util.url(path)
58 u = util.url(path)
59 branch = None
59 branch = None
60 if u.fragment:
60 if u.fragment:
61 branch = u.fragment
61 branch = u.fragment
62 u.fragment = None
62 u.fragment = None
63 return str(u), (branch, branches or [])
63 return str(u), (branch, branches or [])
64
64
65 schemes = {
65 schemes = {
66 'bundle': bundlerepo,
66 'bundle': bundlerepo,
67 'union': unionrepo,
67 'union': unionrepo,
68 'file': _local,
68 'file': _local,
69 'http': httppeer,
69 'http': httppeer,
70 'https': httppeer,
70 'https': httppeer,
71 'ssh': sshpeer,
71 'ssh': sshpeer,
72 'static-http': statichttprepo,
72 'static-http': statichttprepo,
73 }
73 }
74
74
75 def _peerlookup(path):
75 def _peerlookup(path):
76 u = util.url(path)
76 u = util.url(path)
77 scheme = u.scheme or 'file'
77 scheme = u.scheme or 'file'
78 thing = schemes.get(scheme) or schemes['file']
78 thing = schemes.get(scheme) or schemes['file']
79 try:
79 try:
80 return thing(path)
80 return thing(path)
81 except TypeError:
81 except TypeError:
82 return thing
82 return thing
83
83
84 def islocal(repo):
84 def islocal(repo):
85 '''return true if repo (or path pointing to repo) is local'''
85 '''return true if repo (or path pointing to repo) is local'''
86 if isinstance(repo, str):
86 if isinstance(repo, str):
87 try:
87 try:
88 return _peerlookup(repo).islocal(repo)
88 return _peerlookup(repo).islocal(repo)
89 except AttributeError:
89 except AttributeError:
90 return False
90 return False
91 return repo.local()
91 return repo.local()
92
92
93 def openpath(ui, path):
93 def openpath(ui, path):
94 '''open path with open if local, url.open if remote'''
94 '''open path with open if local, url.open if remote'''
95 pathurl = util.url(path, parsequery=False, parsefragment=False)
95 pathurl = util.url(path, parsequery=False, parsefragment=False)
96 if pathurl.islocal():
96 if pathurl.islocal():
97 return util.posixfile(pathurl.localpath(), 'rb')
97 return util.posixfile(pathurl.localpath(), 'rb')
98 else:
98 else:
99 return url.open(ui, path)
99 return url.open(ui, path)
100
100
101 # a list of (ui, repo) functions called for wire peer initialization
101 # a list of (ui, repo) functions called for wire peer initialization
102 wirepeersetupfuncs = []
102 wirepeersetupfuncs = []
103
103
104 def _peerorrepo(ui, path, create=False):
104 def _peerorrepo(ui, path, create=False):
105 """return a repository object for the specified path"""
105 """return a repository object for the specified path"""
106 obj = _peerlookup(path).instance(ui, path, create)
106 obj = _peerlookup(path).instance(ui, path, create)
107 ui = getattr(obj, "ui", ui)
107 ui = getattr(obj, "ui", ui)
108 for name, module in extensions.extensions(ui):
108 for name, module in extensions.extensions(ui):
109 hook = getattr(module, 'reposetup', None)
109 hook = getattr(module, 'reposetup', None)
110 if hook:
110 if hook:
111 hook(ui, obj)
111 hook(ui, obj)
112 if not obj.local():
112 if not obj.local():
113 for f in wirepeersetupfuncs:
113 for f in wirepeersetupfuncs:
114 f(ui, obj)
114 f(ui, obj)
115 return obj
115 return obj
116
116
117 def repository(ui, path='', create=False):
117 def repository(ui, path='', create=False):
118 """return a repository object for the specified path"""
118 """return a repository object for the specified path"""
119 peer = _peerorrepo(ui, path, create)
119 peer = _peerorrepo(ui, path, create)
120 repo = peer.local()
120 repo = peer.local()
121 if not repo:
121 if not repo:
122 raise util.Abort(_("repository '%s' is not local") %
122 raise util.Abort(_("repository '%s' is not local") %
123 (path or peer.url()))
123 (path or peer.url()))
124 return repo.filtered('visible')
124 return repo.filtered('visible')
125
125
126 def peer(uiorrepo, opts, path, create=False):
126 def peer(uiorrepo, opts, path, create=False):
127 '''return a repository peer for the specified path'''
127 '''return a repository peer for the specified path'''
128 rui = remoteui(uiorrepo, opts)
128 rui = remoteui(uiorrepo, opts)
129 return _peerorrepo(rui, path, create).peer()
129 return _peerorrepo(rui, path, create).peer()
130
130
131 def defaultdest(source):
131 def defaultdest(source):
132 '''return default destination of clone if none is given
132 '''return default destination of clone if none is given
133
133
134 >>> defaultdest('foo')
134 >>> defaultdest('foo')
135 'foo'
135 'foo'
136 >>> defaultdest('/foo/bar')
136 >>> defaultdest('/foo/bar')
137 'bar'
137 'bar'
138 >>> defaultdest('/')
138 >>> defaultdest('/')
139 ''
139 ''
140 >>> defaultdest('')
140 >>> defaultdest('')
141 ''
141 ''
142 >>> defaultdest('http://example.org/')
142 >>> defaultdest('http://example.org/')
143 ''
143 ''
144 >>> defaultdest('http://example.org/foo/')
144 >>> defaultdest('http://example.org/foo/')
145 'foo'
145 'foo'
146 '''
146 '''
147 path = util.url(source).path
147 path = util.url(source).path
148 if not path:
148 if not path:
149 return ''
149 return ''
150 return os.path.basename(os.path.normpath(path))
150 return os.path.basename(os.path.normpath(path))
151
151
152 def share(ui, source, dest=None, update=True):
152 def share(ui, source, dest=None, update=True):
153 '''create a shared repository'''
153 '''create a shared repository'''
154
154
155 if not islocal(source):
155 if not islocal(source):
156 raise util.Abort(_('can only share local repositories'))
156 raise util.Abort(_('can only share local repositories'))
157
157
158 if not dest:
158 if not dest:
159 dest = defaultdest(source)
159 dest = defaultdest(source)
160 else:
160 else:
161 dest = ui.expandpath(dest)
161 dest = ui.expandpath(dest)
162
162
163 if isinstance(source, str):
163 if isinstance(source, str):
164 origsource = ui.expandpath(source)
164 origsource = ui.expandpath(source)
165 source, branches = parseurl(origsource)
165 source, branches = parseurl(origsource)
166 srcrepo = repository(ui, source)
166 srcrepo = repository(ui, source)
167 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
167 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
168 else:
168 else:
169 srcrepo = source.local()
169 srcrepo = source.local()
170 origsource = source = srcrepo.url()
170 origsource = source = srcrepo.url()
171 checkout = None
171 checkout = None
172
172
173 sharedpath = srcrepo.sharedpath # if our source is already sharing
173 sharedpath = srcrepo.sharedpath # if our source is already sharing
174
174
175 destwvfs = scmutil.vfs(dest, realpath=True)
175 destwvfs = scmutil.vfs(dest, realpath=True)
176 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
176 destvfs = scmutil.vfs(os.path.join(destwvfs.base, '.hg'), realpath=True)
177
177
178 if destvfs.lexists():
178 if destvfs.lexists():
179 raise util.Abort(_('destination already exists'))
179 raise util.Abort(_('destination already exists'))
180
180
181 if not destwvfs.isdir():
181 if not destwvfs.isdir():
182 destwvfs.mkdir()
182 destwvfs.mkdir()
183 destvfs.makedir()
183 destvfs.makedir()
184
184
185 requirements = ''
185 requirements = ''
186 try:
186 try:
187 requirements = srcrepo.opener.read('requires')
187 requirements = srcrepo.opener.read('requires')
188 except IOError, inst:
188 except IOError, inst:
189 if inst.errno != errno.ENOENT:
189 if inst.errno != errno.ENOENT:
190 raise
190 raise
191
191
192 requirements += 'shared\n'
192 requirements += 'shared\n'
193 destvfs.write('requires', requirements)
193 destvfs.write('requires', requirements)
194 destvfs.write('sharedpath', sharedpath)
194 destvfs.write('sharedpath', sharedpath)
195
195
196 r = repository(ui, destwvfs.base)
196 r = repository(ui, destwvfs.base)
197
197
198 default = srcrepo.ui.config('paths', 'default')
198 default = srcrepo.ui.config('paths', 'default')
199 if default:
199 if default:
200 fp = r.opener("hgrc", "w", text=True)
200 fp = r.opener("hgrc", "w", text=True)
201 fp.write("[paths]\n")
201 fp.write("[paths]\n")
202 fp.write("default = %s\n" % default)
202 fp.write("default = %s\n" % default)
203 fp.close()
203 fp.close()
204
204
205 if update:
205 if update:
206 r.ui.status(_("updating working directory\n"))
206 r.ui.status(_("updating working directory\n"))
207 if update is not True:
207 if update is not True:
208 checkout = update
208 checkout = update
209 for test in (checkout, 'default', 'tip'):
209 for test in (checkout, 'default', 'tip'):
210 if test is None:
210 if test is None:
211 continue
211 continue
212 try:
212 try:
213 uprev = r.lookup(test)
213 uprev = r.lookup(test)
214 break
214 break
215 except error.RepoLookupError:
215 except error.RepoLookupError:
216 continue
216 continue
217 _update(r, uprev)
217 _update(r, uprev)
218
218
219 def copystore(ui, srcrepo, destpath):
219 def copystore(ui, srcrepo, destpath):
220 '''copy files from store of srcrepo in destpath
220 '''copy files from store of srcrepo in destpath
221
221
222 returns destlock
222 returns destlock
223 '''
223 '''
224 destlock = None
224 destlock = None
225 try:
225 try:
226 hardlink = None
226 hardlink = None
227 num = 0
227 num = 0
228 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
228 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
229 srcvfs = scmutil.vfs(srcrepo.sharedpath)
229 srcvfs = scmutil.vfs(srcrepo.sharedpath)
230 dstvfs = scmutil.vfs(destpath)
230 dstvfs = scmutil.vfs(destpath)
231 for f in srcrepo.store.copylist():
231 for f in srcrepo.store.copylist():
232 if srcpublishing and f.endswith('phaseroots'):
232 if srcpublishing and f.endswith('phaseroots'):
233 continue
233 continue
234 dstbase = os.path.dirname(f)
234 dstbase = os.path.dirname(f)
235 if dstbase and not dstvfs.exists(dstbase):
235 if dstbase and not dstvfs.exists(dstbase):
236 dstvfs.mkdir(dstbase)
236 dstvfs.mkdir(dstbase)
237 if srcvfs.exists(f):
237 if srcvfs.exists(f):
238 if f.endswith('data'):
238 if f.endswith('data'):
239 # 'dstbase' may be empty (e.g. revlog format 0)
239 # 'dstbase' may be empty (e.g. revlog format 0)
240 lockfile = os.path.join(dstbase, "lock")
240 lockfile = os.path.join(dstbase, "lock")
241 # lock to avoid premature writing to the target
241 # lock to avoid premature writing to the target
242 destlock = lock.lock(dstvfs, lockfile)
242 destlock = lock.lock(dstvfs, lockfile)
243 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
243 hardlink, n = util.copyfiles(srcvfs.join(f), dstvfs.join(f),
244 hardlink)
244 hardlink)
245 num += n
245 num += n
246 if hardlink:
246 if hardlink:
247 ui.debug("linked %d files\n" % num)
247 ui.debug("linked %d files\n" % num)
248 else:
248 else:
249 ui.debug("copied %d files\n" % num)
249 ui.debug("copied %d files\n" % num)
250 return destlock
250 return destlock
251 except: # re-raises
251 except: # re-raises
252 release(destlock)
252 release(destlock)
253 raise
253 raise
254
254
255 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
255 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
256 update=True, stream=False, branch=None):
256 update=True, stream=False, branch=None):
257 """Make a copy of an existing repository.
257 """Make a copy of an existing repository.
258
258
259 Create a copy of an existing repository in a new directory. The
259 Create a copy of an existing repository in a new directory. The
260 source and destination are URLs, as passed to the repository
260 source and destination are URLs, as passed to the repository
261 function. Returns a pair of repository peers, the source and
261 function. Returns a pair of repository peers, the source and
262 newly created destination.
262 newly created destination.
263
263
264 The location of the source is added to the new repository's
264 The location of the source is added to the new repository's
265 .hg/hgrc file, as the default to be used for future pulls and
265 .hg/hgrc file, as the default to be used for future pulls and
266 pushes.
266 pushes.
267
267
268 If an exception is raised, the partly cloned/updated destination
268 If an exception is raised, the partly cloned/updated destination
269 repository will be deleted.
269 repository will be deleted.
270
270
271 Arguments:
271 Arguments:
272
272
273 source: repository object or URL
273 source: repository object or URL
274
274
275 dest: URL of destination repository to create (defaults to base
275 dest: URL of destination repository to create (defaults to base
276 name of source repository)
276 name of source repository)
277
277
278 pull: always pull from source repository, even in local case
278 pull: always pull from source repository, even in local case
279
279
280 stream: stream raw data uncompressed from repository (fast over
280 stream: stream raw data uncompressed from repository (fast over
281 LAN, slow over WAN)
281 LAN, slow over WAN)
282
282
283 rev: revision to clone up to (implies pull=True)
283 rev: revision to clone up to (implies pull=True)
284
284
285 update: update working directory after clone completes, if
285 update: update working directory after clone completes, if
286 destination is local repository (True means update to default rev,
286 destination is local repository (True means update to default rev,
287 anything else is treated as a revision)
287 anything else is treated as a revision)
288
288
289 branch: branches to clone
289 branch: branches to clone
290 """
290 """
291
291
292 if isinstance(source, str):
292 if isinstance(source, str):
293 origsource = ui.expandpath(source)
293 origsource = ui.expandpath(source)
294 source, branch = parseurl(origsource, branch)
294 source, branch = parseurl(origsource, branch)
295 srcpeer = peer(ui, peeropts, source)
295 srcpeer = peer(ui, peeropts, source)
296 else:
296 else:
297 srcpeer = source.peer() # in case we were called with a localrepo
297 srcpeer = source.peer() # in case we were called with a localrepo
298 branch = (None, branch or [])
298 branch = (None, branch or [])
299 origsource = source = srcpeer.url()
299 origsource = source = srcpeer.url()
300 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
300 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
301
301
302 if dest is None:
302 if dest is None:
303 dest = defaultdest(source)
303 dest = defaultdest(source)
304 if dest:
304 if dest:
305 ui.status(_("destination directory: %s\n") % dest)
305 ui.status(_("destination directory: %s\n") % dest)
306 else:
306 else:
307 dest = ui.expandpath(dest)
307 dest = ui.expandpath(dest)
308
308
309 dest = util.urllocalpath(dest)
309 dest = util.urllocalpath(dest)
310 source = util.urllocalpath(source)
310 source = util.urllocalpath(source)
311
311
312 if not dest:
312 if not dest:
313 raise util.Abort(_("empty destination path is not valid"))
313 raise util.Abort(_("empty destination path is not valid"))
314
314
315 destvfs = scmutil.vfs(dest, expandpath=True)
315 destvfs = scmutil.vfs(dest, expandpath=True)
316 if destvfs.lexists():
316 if destvfs.lexists():
317 if not destvfs.isdir():
317 if not destvfs.isdir():
318 raise util.Abort(_("destination '%s' already exists") % dest)
318 raise util.Abort(_("destination '%s' already exists") % dest)
319 elif destvfs.listdir():
319 elif destvfs.listdir():
320 raise util.Abort(_("destination '%s' is not empty") % dest)
320 raise util.Abort(_("destination '%s' is not empty") % dest)
321
321
322 srclock = destlock = cleandir = None
322 srclock = destlock = cleandir = None
323 srcrepo = srcpeer.local()
323 srcrepo = srcpeer.local()
324 try:
324 try:
325 abspath = origsource
325 abspath = origsource
326 if islocal(origsource):
326 if islocal(origsource):
327 abspath = os.path.abspath(util.urllocalpath(origsource))
327 abspath = os.path.abspath(util.urllocalpath(origsource))
328
328
329 if islocal(dest):
329 if islocal(dest):
330 cleandir = dest
330 cleandir = dest
331
331
332 copy = False
332 copy = False
333 if (srcrepo and srcrepo.cancopy() and islocal(dest)
333 if (srcrepo and srcrepo.cancopy() and islocal(dest)
334 and not phases.hassecret(srcrepo)):
334 and not phases.hassecret(srcrepo)):
335 copy = not pull and not rev
335 copy = not pull and not rev
336
336
337 if copy:
337 if copy:
338 try:
338 try:
339 # we use a lock here because if we race with commit, we
339 # we use a lock here because if we race with commit, we
340 # can end up with extra data in the cloned revlogs that's
340 # can end up with extra data in the cloned revlogs that's
341 # not pointed to by changesets, thus causing verify to
341 # not pointed to by changesets, thus causing verify to
342 # fail
342 # fail
343 srclock = srcrepo.lock(wait=False)
343 srclock = srcrepo.lock(wait=False)
344 except error.LockError:
344 except error.LockError:
345 copy = False
345 copy = False
346
346
347 if copy:
347 if copy:
348 srcrepo.hook('preoutgoing', throw=True, source='clone')
348 srcrepo.hook('preoutgoing', throw=True, source='clone')
349 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
349 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
350 if not os.path.exists(dest):
350 if not os.path.exists(dest):
351 os.mkdir(dest)
351 os.mkdir(dest)
352 else:
352 else:
353 # only clean up directories we create ourselves
353 # only clean up directories we create ourselves
354 cleandir = hgdir
354 cleandir = hgdir
355 try:
355 try:
356 destpath = hgdir
356 destpath = hgdir
357 util.makedir(destpath, notindexed=True)
357 util.makedir(destpath, notindexed=True)
358 except OSError, inst:
358 except OSError, inst:
359 if inst.errno == errno.EEXIST:
359 if inst.errno == errno.EEXIST:
360 cleandir = None
360 cleandir = None
361 raise util.Abort(_("destination '%s' already exists")
361 raise util.Abort(_("destination '%s' already exists")
362 % dest)
362 % dest)
363 raise
363 raise
364
364
365 destlock = copystore(ui, srcrepo, destpath)
365 destlock = copystore(ui, srcrepo, destpath)
366
366
367 # Recomputing branch cache might be slow on big repos,
367 # Recomputing branch cache might be slow on big repos,
368 # so just copy it
368 # so just copy it
369 def copybranchcache(fname):
369 def copybranchcache(fname):
370 srcbranchcache = srcrepo.join('cache/%s' % fname)
370 srcbranchcache = srcrepo.join('cache/%s' % fname)
371 dstbranchcache = os.path.join(dstcachedir, fname)
371 dstbranchcache = os.path.join(dstcachedir, fname)
372 if os.path.exists(srcbranchcache):
372 if os.path.exists(srcbranchcache):
373 if not os.path.exists(dstcachedir):
373 if not os.path.exists(dstcachedir):
374 os.mkdir(dstcachedir)
374 os.mkdir(dstcachedir)
375 util.copyfile(srcbranchcache, dstbranchcache)
375 util.copyfile(srcbranchcache, dstbranchcache)
376
376
377 dstcachedir = os.path.join(destpath, 'cache')
377 dstcachedir = os.path.join(destpath, 'cache')
378 # In local clones we're copying all nodes, not just served
378 # In local clones we're copying all nodes, not just served
379 # ones. Therefore copy all branchcaches over.
379 # ones. Therefore copy all branchcaches over.
380 copybranchcache('branch2')
380 copybranchcache('branch2')
381 for cachename in repoview.filtertable:
381 for cachename in repoview.filtertable:
382 copybranchcache('branch2-%s' % cachename)
382 copybranchcache('branch2-%s' % cachename)
383
383
384 # we need to re-init the repo after manually copying the data
384 # we need to re-init the repo after manually copying the data
385 # into it
385 # into it
386 destpeer = peer(srcrepo, peeropts, dest)
386 destpeer = peer(srcrepo, peeropts, dest)
387 srcrepo.hook('outgoing', source='clone',
387 srcrepo.hook('outgoing', source='clone',
388 node=node.hex(node.nullid))
388 node=node.hex(node.nullid))
389 else:
389 else:
390 try:
390 try:
391 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
391 destpeer = peer(srcrepo or ui, peeropts, dest, create=True)
392 # only pass ui when no srcrepo
392 # only pass ui when no srcrepo
393 except OSError, inst:
393 except OSError, inst:
394 if inst.errno == errno.EEXIST:
394 if inst.errno == errno.EEXIST:
395 cleandir = None
395 cleandir = None
396 raise util.Abort(_("destination '%s' already exists")
396 raise util.Abort(_("destination '%s' already exists")
397 % dest)
397 % dest)
398 raise
398 raise
399
399
400 revs = None
400 revs = None
401 if rev:
401 if rev:
402 if not srcpeer.capable('lookup'):
402 if not srcpeer.capable('lookup'):
403 raise util.Abort(_("src repository does not support "
403 raise util.Abort(_("src repository does not support "
404 "revision lookup and so doesn't "
404 "revision lookup and so doesn't "
405 "support clone by revision"))
405 "support clone by revision"))
406 revs = [srcpeer.lookup(r) for r in rev]
406 revs = [srcpeer.lookup(r) for r in rev]
407 checkout = revs[0]
407 checkout = revs[0]
408 if destpeer.local():
408 if destpeer.local():
409 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
409 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
410 elif srcrepo:
410 elif srcrepo:
411 srcrepo.push(destpeer, revs=revs)
411 exchange.push(srcrepo, destpeer, revs=revs)
412 else:
412 else:
413 raise util.Abort(_("clone from remote to remote not supported"))
413 raise util.Abort(_("clone from remote to remote not supported"))
414
414
415 cleandir = None
415 cleandir = None
416
416
417 # clone all bookmarks except divergent ones
417 # clone all bookmarks except divergent ones
418 destrepo = destpeer.local()
418 destrepo = destpeer.local()
419 if destrepo and srcpeer.capable("pushkey"):
419 if destrepo and srcpeer.capable("pushkey"):
420 rb = srcpeer.listkeys('bookmarks')
420 rb = srcpeer.listkeys('bookmarks')
421 marks = destrepo._bookmarks
421 marks = destrepo._bookmarks
422 for k, n in rb.iteritems():
422 for k, n in rb.iteritems():
423 try:
423 try:
424 m = destrepo.lookup(n)
424 m = destrepo.lookup(n)
425 marks[k] = m
425 marks[k] = m
426 except error.RepoLookupError:
426 except error.RepoLookupError:
427 pass
427 pass
428 if rb:
428 if rb:
429 marks.write()
429 marks.write()
430 elif srcrepo and destpeer.capable("pushkey"):
430 elif srcrepo and destpeer.capable("pushkey"):
431 for k, n in srcrepo._bookmarks.iteritems():
431 for k, n in srcrepo._bookmarks.iteritems():
432 destpeer.pushkey('bookmarks', k, '', hex(n))
432 destpeer.pushkey('bookmarks', k, '', hex(n))
433
433
434 if destrepo:
434 if destrepo:
435 template = (
435 template = (
436 '# You may want to set your username here if it is not set\n'
436 '# You may want to set your username here if it is not set\n'
437 "# globally, or this repository requires a different\n"
437 "# globally, or this repository requires a different\n"
438 '# username from your usual configuration. If you want to\n'
438 '# username from your usual configuration. If you want to\n'
439 '# set something for all of your repositories on this\n'
439 '# set something for all of your repositories on this\n'
440 '# computer, try running the command\n'
440 '# computer, try running the command\n'
441 "# 'hg config --edit --global'\n"
441 "# 'hg config --edit --global'\n"
442 '# [ui]\n'
442 '# [ui]\n'
443 '# username = Jane Doe <jdoe@example.com>\n'
443 '# username = Jane Doe <jdoe@example.com>\n'
444 '[paths]\n'
444 '[paths]\n'
445 'default = %s\n'
445 'default = %s\n'
446 )
446 )
447 fp = destrepo.opener("hgrc", "w", text=True)
447 fp = destrepo.opener("hgrc", "w", text=True)
448 u = util.url(abspath)
448 u = util.url(abspath)
449 u.passwd = None
449 u.passwd = None
450 defaulturl = str(u)
450 defaulturl = str(u)
451 fp.write(template % defaulturl)
451 fp.write(template % defaulturl)
452 fp.close()
452 fp.close()
453
453
454 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
454 destrepo.ui.setconfig('paths', 'default', defaulturl, 'clone')
455
455
456 if update:
456 if update:
457 if update is not True:
457 if update is not True:
458 checkout = srcpeer.lookup(update)
458 checkout = srcpeer.lookup(update)
459 uprev = None
459 uprev = None
460 status = None
460 status = None
461 if checkout is not None:
461 if checkout is not None:
462 try:
462 try:
463 uprev = destrepo.lookup(checkout)
463 uprev = destrepo.lookup(checkout)
464 except error.RepoLookupError:
464 except error.RepoLookupError:
465 pass
465 pass
466 if uprev is None:
466 if uprev is None:
467 try:
467 try:
468 uprev = destrepo._bookmarks['@']
468 uprev = destrepo._bookmarks['@']
469 update = '@'
469 update = '@'
470 bn = destrepo[uprev].branch()
470 bn = destrepo[uprev].branch()
471 if bn == 'default':
471 if bn == 'default':
472 status = _("updating to bookmark @\n")
472 status = _("updating to bookmark @\n")
473 else:
473 else:
474 status = (_("updating to bookmark @ on branch %s\n")
474 status = (_("updating to bookmark @ on branch %s\n")
475 % bn)
475 % bn)
476 except KeyError:
476 except KeyError:
477 try:
477 try:
478 uprev = destrepo.branchtip('default')
478 uprev = destrepo.branchtip('default')
479 except error.RepoLookupError:
479 except error.RepoLookupError:
480 uprev = destrepo.lookup('tip')
480 uprev = destrepo.lookup('tip')
481 if not status:
481 if not status:
482 bn = destrepo[uprev].branch()
482 bn = destrepo[uprev].branch()
483 status = _("updating to branch %s\n") % bn
483 status = _("updating to branch %s\n") % bn
484 destrepo.ui.status(status)
484 destrepo.ui.status(status)
485 _update(destrepo, uprev)
485 _update(destrepo, uprev)
486 if update in destrepo._bookmarks:
486 if update in destrepo._bookmarks:
487 bookmarks.setcurrent(destrepo, update)
487 bookmarks.setcurrent(destrepo, update)
488 finally:
488 finally:
489 release(srclock, destlock)
489 release(srclock, destlock)
490 if cleandir is not None:
490 if cleandir is not None:
491 shutil.rmtree(cleandir, True)
491 shutil.rmtree(cleandir, True)
492 if srcpeer is not None:
492 if srcpeer is not None:
493 srcpeer.close()
493 srcpeer.close()
494 return srcpeer, destpeer
494 return srcpeer, destpeer
495
495
496 def _showstats(repo, stats):
496 def _showstats(repo, stats):
497 repo.ui.status(_("%d files updated, %d files merged, "
497 repo.ui.status(_("%d files updated, %d files merged, "
498 "%d files removed, %d files unresolved\n") % stats)
498 "%d files removed, %d files unresolved\n") % stats)
499
499
500 def updaterepo(repo, node, overwrite):
500 def updaterepo(repo, node, overwrite):
501 """Update the working directory to node.
501 """Update the working directory to node.
502
502
503 When overwrite is set, changes are clobbered, merged else
503 When overwrite is set, changes are clobbered, merged else
504
504
505 returns stats (see pydoc mercurial.merge.applyupdates)"""
505 returns stats (see pydoc mercurial.merge.applyupdates)"""
506 return mergemod.update(repo, node, False, overwrite, None,
506 return mergemod.update(repo, node, False, overwrite, None,
507 labels=['working copy', 'destination'])
507 labels=['working copy', 'destination'])
508
508
509 def update(repo, node):
509 def update(repo, node):
510 """update the working directory to node, merging linear changes"""
510 """update the working directory to node, merging linear changes"""
511 stats = updaterepo(repo, node, False)
511 stats = updaterepo(repo, node, False)
512 _showstats(repo, stats)
512 _showstats(repo, stats)
513 if stats[3]:
513 if stats[3]:
514 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
514 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
515 return stats[3] > 0
515 return stats[3] > 0
516
516
517 # naming conflict in clone()
517 # naming conflict in clone()
518 _update = update
518 _update = update
519
519
520 def clean(repo, node, show_stats=True):
520 def clean(repo, node, show_stats=True):
521 """forcibly switch the working directory to node, clobbering changes"""
521 """forcibly switch the working directory to node, clobbering changes"""
522 stats = updaterepo(repo, node, True)
522 stats = updaterepo(repo, node, True)
523 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
523 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
524 if show_stats:
524 if show_stats:
525 _showstats(repo, stats)
525 _showstats(repo, stats)
526 return stats[3] > 0
526 return stats[3] > 0
527
527
528 def merge(repo, node, force=None, remind=True):
528 def merge(repo, node, force=None, remind=True):
529 """Branch merge with node, resolving changes. Return true if any
529 """Branch merge with node, resolving changes. Return true if any
530 unresolved conflicts."""
530 unresolved conflicts."""
531 stats = mergemod.update(repo, node, True, force, False)
531 stats = mergemod.update(repo, node, True, force, False)
532 _showstats(repo, stats)
532 _showstats(repo, stats)
533 if stats[3]:
533 if stats[3]:
534 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
534 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
535 "or 'hg update -C .' to abandon\n"))
535 "or 'hg update -C .' to abandon\n"))
536 elif remind:
536 elif remind:
537 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
537 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
538 return stats[3] > 0
538 return stats[3] > 0
539
539
540 def _incoming(displaychlist, subreporecurse, ui, repo, source,
540 def _incoming(displaychlist, subreporecurse, ui, repo, source,
541 opts, buffered=False):
541 opts, buffered=False):
542 """
542 """
543 Helper for incoming / gincoming.
543 Helper for incoming / gincoming.
544 displaychlist gets called with
544 displaychlist gets called with
545 (remoterepo, incomingchangesetlist, displayer) parameters,
545 (remoterepo, incomingchangesetlist, displayer) parameters,
546 and is supposed to contain only code that can't be unified.
546 and is supposed to contain only code that can't be unified.
547 """
547 """
548 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
548 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
549 other = peer(repo, opts, source)
549 other = peer(repo, opts, source)
550 ui.status(_('comparing with %s\n') % util.hidepassword(source))
550 ui.status(_('comparing with %s\n') % util.hidepassword(source))
551 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
551 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
552
552
553 if revs:
553 if revs:
554 revs = [other.lookup(rev) for rev in revs]
554 revs = [other.lookup(rev) for rev in revs]
555 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
555 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
556 revs, opts["bundle"], opts["force"])
556 revs, opts["bundle"], opts["force"])
557 try:
557 try:
558 if not chlist:
558 if not chlist:
559 ui.status(_("no changes found\n"))
559 ui.status(_("no changes found\n"))
560 return subreporecurse()
560 return subreporecurse()
561
561
562 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
562 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
563 displaychlist(other, chlist, displayer)
563 displaychlist(other, chlist, displayer)
564 displayer.close()
564 displayer.close()
565 finally:
565 finally:
566 cleanupfn()
566 cleanupfn()
567 subreporecurse()
567 subreporecurse()
568 return 0 # exit code is zero since we found incoming changes
568 return 0 # exit code is zero since we found incoming changes
569
569
570 def incoming(ui, repo, source, opts):
570 def incoming(ui, repo, source, opts):
571 def subreporecurse():
571 def subreporecurse():
572 ret = 1
572 ret = 1
573 if opts.get('subrepos'):
573 if opts.get('subrepos'):
574 ctx = repo[None]
574 ctx = repo[None]
575 for subpath in sorted(ctx.substate):
575 for subpath in sorted(ctx.substate):
576 sub = ctx.sub(subpath)
576 sub = ctx.sub(subpath)
577 ret = min(ret, sub.incoming(ui, source, opts))
577 ret = min(ret, sub.incoming(ui, source, opts))
578 return ret
578 return ret
579
579
580 def display(other, chlist, displayer):
580 def display(other, chlist, displayer):
581 limit = cmdutil.loglimit(opts)
581 limit = cmdutil.loglimit(opts)
582 if opts.get('newest_first'):
582 if opts.get('newest_first'):
583 chlist.reverse()
583 chlist.reverse()
584 count = 0
584 count = 0
585 for n in chlist:
585 for n in chlist:
586 if limit is not None and count >= limit:
586 if limit is not None and count >= limit:
587 break
587 break
588 parents = [p for p in other.changelog.parents(n) if p != nullid]
588 parents = [p for p in other.changelog.parents(n) if p != nullid]
589 if opts.get('no_merges') and len(parents) == 2:
589 if opts.get('no_merges') and len(parents) == 2:
590 continue
590 continue
591 count += 1
591 count += 1
592 displayer.show(other[n])
592 displayer.show(other[n])
593 return _incoming(display, subreporecurse, ui, repo, source, opts)
593 return _incoming(display, subreporecurse, ui, repo, source, opts)
594
594
595 def _outgoing(ui, repo, dest, opts):
595 def _outgoing(ui, repo, dest, opts):
596 dest = ui.expandpath(dest or 'default-push', dest or 'default')
596 dest = ui.expandpath(dest or 'default-push', dest or 'default')
597 dest, branches = parseurl(dest, opts.get('branch'))
597 dest, branches = parseurl(dest, opts.get('branch'))
598 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
598 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
599 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
599 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
600 if revs:
600 if revs:
601 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
601 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
602
602
603 other = peer(repo, opts, dest)
603 other = peer(repo, opts, dest)
604 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
604 outgoing = discovery.findcommonoutgoing(repo.unfiltered(), other, revs,
605 force=opts.get('force'))
605 force=opts.get('force'))
606 o = outgoing.missing
606 o = outgoing.missing
607 if not o:
607 if not o:
608 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
608 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
609 return o, other
609 return o, other
610
610
611 def outgoing(ui, repo, dest, opts):
611 def outgoing(ui, repo, dest, opts):
612 def recurse():
612 def recurse():
613 ret = 1
613 ret = 1
614 if opts.get('subrepos'):
614 if opts.get('subrepos'):
615 ctx = repo[None]
615 ctx = repo[None]
616 for subpath in sorted(ctx.substate):
616 for subpath in sorted(ctx.substate):
617 sub = ctx.sub(subpath)
617 sub = ctx.sub(subpath)
618 ret = min(ret, sub.outgoing(ui, dest, opts))
618 ret = min(ret, sub.outgoing(ui, dest, opts))
619 return ret
619 return ret
620
620
621 limit = cmdutil.loglimit(opts)
621 limit = cmdutil.loglimit(opts)
622 o, other = _outgoing(ui, repo, dest, opts)
622 o, other = _outgoing(ui, repo, dest, opts)
623 if not o:
623 if not o:
624 cmdutil.outgoinghooks(ui, repo, other, opts, o)
624 cmdutil.outgoinghooks(ui, repo, other, opts, o)
625 return recurse()
625 return recurse()
626
626
627 if opts.get('newest_first'):
627 if opts.get('newest_first'):
628 o.reverse()
628 o.reverse()
629 displayer = cmdutil.show_changeset(ui, repo, opts)
629 displayer = cmdutil.show_changeset(ui, repo, opts)
630 count = 0
630 count = 0
631 for n in o:
631 for n in o:
632 if limit is not None and count >= limit:
632 if limit is not None and count >= limit:
633 break
633 break
634 parents = [p for p in repo.changelog.parents(n) if p != nullid]
634 parents = [p for p in repo.changelog.parents(n) if p != nullid]
635 if opts.get('no_merges') and len(parents) == 2:
635 if opts.get('no_merges') and len(parents) == 2:
636 continue
636 continue
637 count += 1
637 count += 1
638 displayer.show(repo[n])
638 displayer.show(repo[n])
639 displayer.close()
639 displayer.close()
640 cmdutil.outgoinghooks(ui, repo, other, opts, o)
640 cmdutil.outgoinghooks(ui, repo, other, opts, o)
641 recurse()
641 recurse()
642 return 0 # exit code is zero since we found outgoing changes
642 return 0 # exit code is zero since we found outgoing changes
643
643
644 def revert(repo, node, choose):
644 def revert(repo, node, choose):
645 """revert changes to revision in node without updating dirstate"""
645 """revert changes to revision in node without updating dirstate"""
646 return mergemod.update(repo, node, False, True, choose)[3] > 0
646 return mergemod.update(repo, node, False, True, choose)[3] > 0
647
647
648 def verify(repo):
648 def verify(repo):
649 """verify the consistency of a repository"""
649 """verify the consistency of a repository"""
650 return verifymod.verify(repo)
650 return verifymod.verify(repo)
651
651
652 def remoteui(src, opts):
652 def remoteui(src, opts):
653 'build a remote ui from ui or repo and opts'
653 'build a remote ui from ui or repo and opts'
654 if util.safehasattr(src, 'baseui'): # looks like a repository
654 if util.safehasattr(src, 'baseui'): # looks like a repository
655 dst = src.baseui.copy() # drop repo-specific config
655 dst = src.baseui.copy() # drop repo-specific config
656 src = src.ui # copy target options from repo
656 src = src.ui # copy target options from repo
657 else: # assume it's a global ui object
657 else: # assume it's a global ui object
658 dst = src.copy() # keep all global options
658 dst = src.copy() # keep all global options
659
659
660 # copy ssh-specific options
660 # copy ssh-specific options
661 for o in 'ssh', 'remotecmd':
661 for o in 'ssh', 'remotecmd':
662 v = opts.get(o) or src.config('ui', o)
662 v = opts.get(o) or src.config('ui', o)
663 if v:
663 if v:
664 dst.setconfig("ui", o, v, 'copied')
664 dst.setconfig("ui", o, v, 'copied')
665
665
666 # copy bundle-specific options
666 # copy bundle-specific options
667 r = src.config('bundle', 'mainreporoot')
667 r = src.config('bundle', 'mainreporoot')
668 if r:
668 if r:
669 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
669 dst.setconfig('bundle', 'mainreporoot', r, 'copied')
670
670
671 # copy selected local settings to the remote ui
671 # copy selected local settings to the remote ui
672 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
672 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
673 for key, val in src.configitems(sect):
673 for key, val in src.configitems(sect):
674 dst.setconfig(sect, key, val, 'copied')
674 dst.setconfig(sect, key, val, 'copied')
675 v = src.config('web', 'cacerts')
675 v = src.config('web', 'cacerts')
676 if v:
676 if v:
677 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
677 dst.setconfig('web', 'cacerts', util.expandpath(v), 'copied')
678
678
679 return dst
679 return dst
General Comments 0
You need to be logged in to leave comments. Login now