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