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