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