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