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