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