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