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