##// END OF EJS Templates
clone: don't fail with --update for non-local clones (issue3578)...
Augie Fackler -
r17342:471f30d3 stable
parent child Browse files
Show More
@@ -1,598 +1,598 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, httppeer, sshpeer, statichttprepo, bookmarks
12 import localrepo, bundlerepo, httppeer, sshpeer, statichttprepo, bookmarks
13 import lock, util, extensions, error, node, scmutil
13 import lock, util, extensions, error, node, scmutil
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 _peerorrepo(ui, path, create=False):
92 def _peerorrepo(ui, path, create=False):
93 """return a repository object for the specified path"""
93 """return a repository object for the specified path"""
94 obj = _peerlookup(path).instance(ui, path, create)
94 obj = _peerlookup(path).instance(ui, path, create)
95 ui = getattr(obj, "ui", ui)
95 ui = getattr(obj, "ui", ui)
96 for name, module in extensions.extensions():
96 for name, module in extensions.extensions():
97 hook = getattr(module, 'reposetup', None)
97 hook = getattr(module, 'reposetup', None)
98 if hook:
98 if hook:
99 hook(ui, obj)
99 hook(ui, obj)
100 return obj
100 return obj
101
101
102 def repository(ui, path='', create=False):
102 def repository(ui, path='', create=False):
103 """return a repository object for the specified path"""
103 """return a repository object for the specified path"""
104 peer = _peerorrepo(ui, path, create)
104 peer = _peerorrepo(ui, path, create)
105 repo = peer.local()
105 repo = peer.local()
106 if not repo:
106 if not repo:
107 raise util.Abort(_("repository '%s' is not local") %
107 raise util.Abort(_("repository '%s' is not local") %
108 (path or peer.url()))
108 (path or peer.url()))
109 return repo
109 return repo
110
110
111 def peer(uiorrepo, opts, path, create=False):
111 def peer(uiorrepo, opts, path, create=False):
112 '''return a repository peer for the specified path'''
112 '''return a repository peer for the specified path'''
113 rui = remoteui(uiorrepo, opts)
113 rui = remoteui(uiorrepo, opts)
114 return _peerorrepo(rui, path, create).peer()
114 return _peerorrepo(rui, path, create).peer()
115
115
116 def defaultdest(source):
116 def defaultdest(source):
117 '''return default destination of clone if none is given'''
117 '''return default destination of clone if none is given'''
118 return os.path.basename(os.path.normpath(source))
118 return os.path.basename(os.path.normpath(source))
119
119
120 def share(ui, source, dest=None, update=True):
120 def share(ui, source, dest=None, update=True):
121 '''create a shared repository'''
121 '''create a shared repository'''
122
122
123 if not islocal(source):
123 if not islocal(source):
124 raise util.Abort(_('can only share local repositories'))
124 raise util.Abort(_('can only share local repositories'))
125
125
126 if not dest:
126 if not dest:
127 dest = defaultdest(source)
127 dest = defaultdest(source)
128 else:
128 else:
129 dest = ui.expandpath(dest)
129 dest = ui.expandpath(dest)
130
130
131 if isinstance(source, str):
131 if isinstance(source, str):
132 origsource = ui.expandpath(source)
132 origsource = ui.expandpath(source)
133 source, branches = parseurl(origsource)
133 source, branches = parseurl(origsource)
134 srcrepo = repository(ui, source)
134 srcrepo = repository(ui, source)
135 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
135 rev, checkout = addbranchrevs(srcrepo, srcrepo, branches, None)
136 else:
136 else:
137 srcrepo = source.local()
137 srcrepo = source.local()
138 origsource = source = srcrepo.url()
138 origsource = source = srcrepo.url()
139 checkout = None
139 checkout = None
140
140
141 sharedpath = srcrepo.sharedpath # if our source is already sharing
141 sharedpath = srcrepo.sharedpath # if our source is already sharing
142
142
143 root = os.path.realpath(dest)
143 root = os.path.realpath(dest)
144 roothg = os.path.join(root, '.hg')
144 roothg = os.path.join(root, '.hg')
145
145
146 if os.path.exists(roothg):
146 if os.path.exists(roothg):
147 raise util.Abort(_('destination already exists'))
147 raise util.Abort(_('destination already exists'))
148
148
149 if not os.path.isdir(root):
149 if not os.path.isdir(root):
150 os.mkdir(root)
150 os.mkdir(root)
151 util.makedir(roothg, notindexed=True)
151 util.makedir(roothg, notindexed=True)
152
152
153 requirements = ''
153 requirements = ''
154 try:
154 try:
155 requirements = srcrepo.opener.read('requires')
155 requirements = srcrepo.opener.read('requires')
156 except IOError, inst:
156 except IOError, inst:
157 if inst.errno != errno.ENOENT:
157 if inst.errno != errno.ENOENT:
158 raise
158 raise
159
159
160 requirements += 'shared\n'
160 requirements += 'shared\n'
161 util.writefile(os.path.join(roothg, 'requires'), requirements)
161 util.writefile(os.path.join(roothg, 'requires'), requirements)
162 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
162 util.writefile(os.path.join(roothg, 'sharedpath'), sharedpath)
163
163
164 r = repository(ui, root)
164 r = repository(ui, root)
165
165
166 default = srcrepo.ui.config('paths', 'default')
166 default = srcrepo.ui.config('paths', 'default')
167 if default:
167 if default:
168 fp = r.opener("hgrc", "w", text=True)
168 fp = r.opener("hgrc", "w", text=True)
169 fp.write("[paths]\n")
169 fp.write("[paths]\n")
170 fp.write("default = %s\n" % default)
170 fp.write("default = %s\n" % default)
171 fp.close()
171 fp.close()
172
172
173 if update:
173 if update:
174 r.ui.status(_("updating working directory\n"))
174 r.ui.status(_("updating working directory\n"))
175 if update is not True:
175 if update is not True:
176 checkout = update
176 checkout = update
177 for test in (checkout, 'default', 'tip'):
177 for test in (checkout, 'default', 'tip'):
178 if test is None:
178 if test is None:
179 continue
179 continue
180 try:
180 try:
181 uprev = r.lookup(test)
181 uprev = r.lookup(test)
182 break
182 break
183 except error.RepoLookupError:
183 except error.RepoLookupError:
184 continue
184 continue
185 _update(r, uprev)
185 _update(r, uprev)
186
186
187 def copystore(ui, srcrepo, destpath):
187 def copystore(ui, srcrepo, destpath):
188 '''copy files from store of srcrepo in destpath
188 '''copy files from store of srcrepo in destpath
189
189
190 returns destlock
190 returns destlock
191 '''
191 '''
192 destlock = None
192 destlock = None
193 try:
193 try:
194 hardlink = None
194 hardlink = None
195 num = 0
195 num = 0
196 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
196 srcpublishing = srcrepo.ui.configbool('phases', 'publish', True)
197 for f in srcrepo.store.copylist():
197 for f in srcrepo.store.copylist():
198 if srcpublishing and f.endswith('phaseroots'):
198 if srcpublishing and f.endswith('phaseroots'):
199 continue
199 continue
200 src = os.path.join(srcrepo.sharedpath, f)
200 src = os.path.join(srcrepo.sharedpath, f)
201 dst = os.path.join(destpath, f)
201 dst = os.path.join(destpath, f)
202 dstbase = os.path.dirname(dst)
202 dstbase = os.path.dirname(dst)
203 if dstbase and not os.path.exists(dstbase):
203 if dstbase and not os.path.exists(dstbase):
204 os.mkdir(dstbase)
204 os.mkdir(dstbase)
205 if os.path.exists(src):
205 if os.path.exists(src):
206 if dst.endswith('data'):
206 if dst.endswith('data'):
207 # lock to avoid premature writing to the target
207 # lock to avoid premature writing to the target
208 destlock = lock.lock(os.path.join(dstbase, "lock"))
208 destlock = lock.lock(os.path.join(dstbase, "lock"))
209 hardlink, n = util.copyfiles(src, dst, hardlink)
209 hardlink, n = util.copyfiles(src, dst, hardlink)
210 num += n
210 num += n
211 if hardlink:
211 if hardlink:
212 ui.debug("linked %d files\n" % num)
212 ui.debug("linked %d files\n" % num)
213 else:
213 else:
214 ui.debug("copied %d files\n" % num)
214 ui.debug("copied %d files\n" % num)
215 return destlock
215 return destlock
216 except: # re-raises
216 except: # re-raises
217 release(destlock)
217 release(destlock)
218 raise
218 raise
219
219
220 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
220 def clone(ui, peeropts, source, dest=None, pull=False, rev=None,
221 update=True, stream=False, branch=None):
221 update=True, stream=False, branch=None):
222 """Make a copy of an existing repository.
222 """Make a copy of an existing repository.
223
223
224 Create a copy of an existing repository in a new directory. The
224 Create a copy of an existing repository in a new directory. The
225 source and destination are URLs, as passed to the repository
225 source and destination are URLs, as passed to the repository
226 function. Returns a pair of repository peers, the source and
226 function. Returns a pair of repository peers, the source and
227 newly created destination.
227 newly created destination.
228
228
229 The location of the source is added to the new repository's
229 The location of the source is added to the new repository's
230 .hg/hgrc file, as the default to be used for future pulls and
230 .hg/hgrc file, as the default to be used for future pulls and
231 pushes.
231 pushes.
232
232
233 If an exception is raised, the partly cloned/updated destination
233 If an exception is raised, the partly cloned/updated destination
234 repository will be deleted.
234 repository will be deleted.
235
235
236 Arguments:
236 Arguments:
237
237
238 source: repository object or URL
238 source: repository object or URL
239
239
240 dest: URL of destination repository to create (defaults to base
240 dest: URL of destination repository to create (defaults to base
241 name of source repository)
241 name of source repository)
242
242
243 pull: always pull from source repository, even in local case
243 pull: always pull from source repository, even in local case
244
244
245 stream: stream raw data uncompressed from repository (fast over
245 stream: stream raw data uncompressed from repository (fast over
246 LAN, slow over WAN)
246 LAN, slow over WAN)
247
247
248 rev: revision to clone up to (implies pull=True)
248 rev: revision to clone up to (implies pull=True)
249
249
250 update: update working directory after clone completes, if
250 update: update working directory after clone completes, if
251 destination is local repository (True means update to default rev,
251 destination is local repository (True means update to default rev,
252 anything else is treated as a revision)
252 anything else is treated as a revision)
253
253
254 branch: branches to clone
254 branch: branches to clone
255 """
255 """
256
256
257 if isinstance(source, str):
257 if isinstance(source, str):
258 origsource = ui.expandpath(source)
258 origsource = ui.expandpath(source)
259 source, branch = parseurl(origsource, branch)
259 source, branch = parseurl(origsource, branch)
260 srcpeer = peer(ui, peeropts, source)
260 srcpeer = peer(ui, peeropts, source)
261 else:
261 else:
262 srcpeer = source.peer() # in case we were called with a localrepo
262 srcpeer = source.peer() # in case we were called with a localrepo
263 branch = (None, branch or [])
263 branch = (None, branch or [])
264 origsource = source = srcpeer.url()
264 origsource = source = srcpeer.url()
265 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
265 rev, checkout = addbranchrevs(srcpeer, srcpeer, branch, rev)
266
266
267 if dest is None:
267 if dest is None:
268 dest = defaultdest(source)
268 dest = defaultdest(source)
269 ui.status(_("destination directory: %s\n") % dest)
269 ui.status(_("destination directory: %s\n") % dest)
270 else:
270 else:
271 dest = ui.expandpath(dest)
271 dest = ui.expandpath(dest)
272
272
273 dest = util.urllocalpath(dest)
273 dest = util.urllocalpath(dest)
274 source = util.urllocalpath(source)
274 source = util.urllocalpath(source)
275
275
276 if not dest:
276 if not dest:
277 raise util.Abort(_("empty destination path is not valid"))
277 raise util.Abort(_("empty destination path is not valid"))
278 if os.path.exists(dest):
278 if os.path.exists(dest):
279 if not os.path.isdir(dest):
279 if not os.path.isdir(dest):
280 raise util.Abort(_("destination '%s' already exists") % dest)
280 raise util.Abort(_("destination '%s' already exists") % dest)
281 elif os.listdir(dest):
281 elif os.listdir(dest):
282 raise util.Abort(_("destination '%s' is not empty") % dest)
282 raise util.Abort(_("destination '%s' is not empty") % dest)
283
283
284 class DirCleanup(object):
284 class DirCleanup(object):
285 def __init__(self, dir_):
285 def __init__(self, dir_):
286 self.rmtree = shutil.rmtree
286 self.rmtree = shutil.rmtree
287 self.dir_ = dir_
287 self.dir_ = dir_
288 def close(self):
288 def close(self):
289 self.dir_ = None
289 self.dir_ = None
290 def cleanup(self):
290 def cleanup(self):
291 if self.dir_:
291 if self.dir_:
292 self.rmtree(self.dir_, True)
292 self.rmtree(self.dir_, True)
293
293
294 srclock = destlock = dircleanup = None
294 srclock = destlock = dircleanup = None
295 srcrepo = srcpeer.local()
295 srcrepo = srcpeer.local()
296 try:
296 try:
297 abspath = origsource
297 abspath = origsource
298 if islocal(origsource):
298 if islocal(origsource):
299 abspath = os.path.abspath(util.urllocalpath(origsource))
299 abspath = os.path.abspath(util.urllocalpath(origsource))
300
300
301 if islocal(dest):
301 if islocal(dest):
302 dircleanup = DirCleanup(dest)
302 dircleanup = DirCleanup(dest)
303
303
304 copy = False
304 copy = False
305 if (srcrepo and srcrepo.cancopy() and islocal(dest)
305 if (srcrepo and srcrepo.cancopy() and islocal(dest)
306 and not srcrepo.revs("secret()")):
306 and not srcrepo.revs("secret()")):
307 copy = not pull and not rev
307 copy = not pull and not rev
308
308
309 if copy:
309 if copy:
310 try:
310 try:
311 # we use a lock here because if we race with commit, we
311 # we use a lock here because if we race with commit, we
312 # can end up with extra data in the cloned revlogs that's
312 # can end up with extra data in the cloned revlogs that's
313 # not pointed to by changesets, thus causing verify to
313 # not pointed to by changesets, thus causing verify to
314 # fail
314 # fail
315 srclock = srcrepo.lock(wait=False)
315 srclock = srcrepo.lock(wait=False)
316 except error.LockError:
316 except error.LockError:
317 copy = False
317 copy = False
318
318
319 if copy:
319 if copy:
320 srcrepo.hook('preoutgoing', throw=True, source='clone')
320 srcrepo.hook('preoutgoing', throw=True, source='clone')
321 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
321 hgdir = os.path.realpath(os.path.join(dest, ".hg"))
322 if not os.path.exists(dest):
322 if not os.path.exists(dest):
323 os.mkdir(dest)
323 os.mkdir(dest)
324 else:
324 else:
325 # only clean up directories we create ourselves
325 # only clean up directories we create ourselves
326 dircleanup.dir_ = hgdir
326 dircleanup.dir_ = hgdir
327 try:
327 try:
328 destpath = hgdir
328 destpath = hgdir
329 util.makedir(destpath, notindexed=True)
329 util.makedir(destpath, notindexed=True)
330 except OSError, inst:
330 except OSError, inst:
331 if inst.errno == errno.EEXIST:
331 if inst.errno == errno.EEXIST:
332 dircleanup.close()
332 dircleanup.close()
333 raise util.Abort(_("destination '%s' already exists")
333 raise util.Abort(_("destination '%s' already exists")
334 % dest)
334 % dest)
335 raise
335 raise
336
336
337 destlock = copystore(ui, srcrepo, destpath)
337 destlock = copystore(ui, srcrepo, destpath)
338
338
339 # we need to re-init the repo after manually copying the data
339 # we need to re-init the repo after manually copying the data
340 # into it
340 # into it
341 destpeer = peer(ui, peeropts, dest)
341 destpeer = peer(ui, peeropts, dest)
342 srcrepo.hook('outgoing', source='clone',
342 srcrepo.hook('outgoing', source='clone',
343 node=node.hex(node.nullid))
343 node=node.hex(node.nullid))
344 else:
344 else:
345 try:
345 try:
346 destpeer = peer(ui, peeropts, dest, create=True)
346 destpeer = peer(ui, peeropts, dest, create=True)
347 except OSError, inst:
347 except OSError, inst:
348 if inst.errno == errno.EEXIST:
348 if inst.errno == errno.EEXIST:
349 dircleanup.close()
349 dircleanup.close()
350 raise util.Abort(_("destination '%s' already exists")
350 raise util.Abort(_("destination '%s' already exists")
351 % dest)
351 % dest)
352 raise
352 raise
353
353
354 revs = None
354 revs = None
355 if rev:
355 if rev:
356 if not srcpeer.capable('lookup'):
356 if not srcpeer.capable('lookup'):
357 raise util.Abort(_("src repository does not support "
357 raise util.Abort(_("src repository does not support "
358 "revision lookup and so doesn't "
358 "revision lookup and so doesn't "
359 "support clone by revision"))
359 "support clone by revision"))
360 revs = [srcpeer.lookup(r) for r in rev]
360 revs = [srcpeer.lookup(r) for r in rev]
361 checkout = revs[0]
361 checkout = revs[0]
362 if destpeer.local():
362 if destpeer.local():
363 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
363 destpeer.local().clone(srcpeer, heads=revs, stream=stream)
364 elif srcrepo:
364 elif srcrepo:
365 srcrepo.push(destpeer, revs=revs)
365 srcrepo.push(destpeer, revs=revs)
366 else:
366 else:
367 raise util.Abort(_("clone from remote to remote not supported"))
367 raise util.Abort(_("clone from remote to remote not supported"))
368
368
369 if dircleanup:
369 if dircleanup:
370 dircleanup.close()
370 dircleanup.close()
371
371
372 # clone all bookmarks except divergent ones
372 # clone all bookmarks except divergent ones
373 destrepo = destpeer.local()
373 destrepo = destpeer.local()
374 if destrepo and srcpeer.capable("pushkey"):
374 if destrepo and srcpeer.capable("pushkey"):
375 rb = srcpeer.listkeys('bookmarks')
375 rb = srcpeer.listkeys('bookmarks')
376 for k, n in rb.iteritems():
376 for k, n in rb.iteritems():
377 try:
377 try:
378 m = destrepo.lookup(n)
378 m = destrepo.lookup(n)
379 destrepo._bookmarks[k] = m
379 destrepo._bookmarks[k] = m
380 except error.RepoLookupError:
380 except error.RepoLookupError:
381 pass
381 pass
382 if rb:
382 if rb:
383 bookmarks.write(destrepo)
383 bookmarks.write(destrepo)
384 elif srcrepo and destpeer.capable("pushkey"):
384 elif srcrepo and destpeer.capable("pushkey"):
385 for k, n in srcrepo._bookmarks.iteritems():
385 for k, n in srcrepo._bookmarks.iteritems():
386 destpeer.pushkey('bookmarks', k, '', hex(n))
386 destpeer.pushkey('bookmarks', k, '', hex(n))
387
387
388 if destrepo:
388 if destrepo:
389 fp = destrepo.opener("hgrc", "w", text=True)
389 fp = destrepo.opener("hgrc", "w", text=True)
390 fp.write("[paths]\n")
390 fp.write("[paths]\n")
391 u = util.url(abspath)
391 u = util.url(abspath)
392 u.passwd = None
392 u.passwd = None
393 defaulturl = str(u)
393 defaulturl = str(u)
394 fp.write("default = %s\n" % defaulturl)
394 fp.write("default = %s\n" % defaulturl)
395 fp.close()
395 fp.close()
396
396
397 destrepo.ui.setconfig('paths', 'default', defaulturl)
397 destrepo.ui.setconfig('paths', 'default', defaulturl)
398
398
399 if update:
399 if update:
400 if update is not True:
400 if update is not True:
401 checkout = srcrepo.lookup(update)
401 checkout = srcpeer.lookup(update)
402 for test in (checkout, 'default', 'tip'):
402 for test in (checkout, 'default', 'tip'):
403 if test is None:
403 if test is None:
404 continue
404 continue
405 try:
405 try:
406 uprev = destrepo.lookup(test)
406 uprev = destrepo.lookup(test)
407 break
407 break
408 except error.RepoLookupError:
408 except error.RepoLookupError:
409 continue
409 continue
410 bn = destrepo[uprev].branch()
410 bn = destrepo[uprev].branch()
411 destrepo.ui.status(_("updating to branch %s\n") % bn)
411 destrepo.ui.status(_("updating to branch %s\n") % bn)
412 _update(destrepo, uprev)
412 _update(destrepo, uprev)
413
413
414 return srcpeer, destpeer
414 return srcpeer, destpeer
415 finally:
415 finally:
416 release(srclock, destlock)
416 release(srclock, destlock)
417 if dircleanup is not None:
417 if dircleanup is not None:
418 dircleanup.cleanup()
418 dircleanup.cleanup()
419 if srcpeer is not None:
419 if srcpeer is not None:
420 srcpeer.close()
420 srcpeer.close()
421
421
422 def _showstats(repo, stats):
422 def _showstats(repo, stats):
423 repo.ui.status(_("%d files updated, %d files merged, "
423 repo.ui.status(_("%d files updated, %d files merged, "
424 "%d files removed, %d files unresolved\n") % stats)
424 "%d files removed, %d files unresolved\n") % stats)
425
425
426 def update(repo, node):
426 def update(repo, node):
427 """update the working directory to node, merging linear changes"""
427 """update the working directory to node, merging linear changes"""
428 stats = mergemod.update(repo, node, False, False, None)
428 stats = mergemod.update(repo, node, False, False, None)
429 _showstats(repo, stats)
429 _showstats(repo, stats)
430 if stats[3]:
430 if stats[3]:
431 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
431 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
432 return stats[3] > 0
432 return stats[3] > 0
433
433
434 # naming conflict in clone()
434 # naming conflict in clone()
435 _update = update
435 _update = update
436
436
437 def clean(repo, node, show_stats=True):
437 def clean(repo, node, show_stats=True):
438 """forcibly switch the working directory to node, clobbering changes"""
438 """forcibly switch the working directory to node, clobbering changes"""
439 stats = mergemod.update(repo, node, False, True, None)
439 stats = mergemod.update(repo, node, False, True, None)
440 if show_stats:
440 if show_stats:
441 _showstats(repo, stats)
441 _showstats(repo, stats)
442 return stats[3] > 0
442 return stats[3] > 0
443
443
444 def merge(repo, node, force=None, remind=True):
444 def merge(repo, node, force=None, remind=True):
445 """Branch merge with node, resolving changes. Return true if any
445 """Branch merge with node, resolving changes. Return true if any
446 unresolved conflicts."""
446 unresolved conflicts."""
447 stats = mergemod.update(repo, node, True, force, False)
447 stats = mergemod.update(repo, node, True, force, False)
448 _showstats(repo, stats)
448 _showstats(repo, stats)
449 if stats[3]:
449 if stats[3]:
450 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
450 repo.ui.status(_("use 'hg resolve' to retry unresolved file merges "
451 "or 'hg update -C .' to abandon\n"))
451 "or 'hg update -C .' to abandon\n"))
452 elif remind:
452 elif remind:
453 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
453 repo.ui.status(_("(branch merge, don't forget to commit)\n"))
454 return stats[3] > 0
454 return stats[3] > 0
455
455
456 def _incoming(displaychlist, subreporecurse, ui, repo, source,
456 def _incoming(displaychlist, subreporecurse, ui, repo, source,
457 opts, buffered=False):
457 opts, buffered=False):
458 """
458 """
459 Helper for incoming / gincoming.
459 Helper for incoming / gincoming.
460 displaychlist gets called with
460 displaychlist gets called with
461 (remoterepo, incomingchangesetlist, displayer) parameters,
461 (remoterepo, incomingchangesetlist, displayer) parameters,
462 and is supposed to contain only code that can't be unified.
462 and is supposed to contain only code that can't be unified.
463 """
463 """
464 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
464 source, branches = parseurl(ui.expandpath(source), opts.get('branch'))
465 other = peer(repo, opts, source)
465 other = peer(repo, opts, source)
466 ui.status(_('comparing with %s\n') % util.hidepassword(source))
466 ui.status(_('comparing with %s\n') % util.hidepassword(source))
467 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
467 revs, checkout = addbranchrevs(repo, other, branches, opts.get('rev'))
468
468
469 if revs:
469 if revs:
470 revs = [other.lookup(rev) for rev in revs]
470 revs = [other.lookup(rev) for rev in revs]
471 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
471 other, chlist, cleanupfn = bundlerepo.getremotechanges(ui, repo, other,
472 revs, opts["bundle"], opts["force"])
472 revs, opts["bundle"], opts["force"])
473 try:
473 try:
474 if not chlist:
474 if not chlist:
475 ui.status(_("no changes found\n"))
475 ui.status(_("no changes found\n"))
476 return subreporecurse()
476 return subreporecurse()
477
477
478 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
478 displayer = cmdutil.show_changeset(ui, other, opts, buffered)
479
479
480 # XXX once graphlog extension makes it into core,
480 # XXX once graphlog extension makes it into core,
481 # should be replaced by a if graph/else
481 # should be replaced by a if graph/else
482 displaychlist(other, chlist, displayer)
482 displaychlist(other, chlist, displayer)
483
483
484 displayer.close()
484 displayer.close()
485 finally:
485 finally:
486 cleanupfn()
486 cleanupfn()
487 subreporecurse()
487 subreporecurse()
488 return 0 # exit code is zero since we found incoming changes
488 return 0 # exit code is zero since we found incoming changes
489
489
490 def incoming(ui, repo, source, opts):
490 def incoming(ui, repo, source, opts):
491 def subreporecurse():
491 def subreporecurse():
492 ret = 1
492 ret = 1
493 if opts.get('subrepos'):
493 if opts.get('subrepos'):
494 ctx = repo[None]
494 ctx = repo[None]
495 for subpath in sorted(ctx.substate):
495 for subpath in sorted(ctx.substate):
496 sub = ctx.sub(subpath)
496 sub = ctx.sub(subpath)
497 ret = min(ret, sub.incoming(ui, source, opts))
497 ret = min(ret, sub.incoming(ui, source, opts))
498 return ret
498 return ret
499
499
500 def display(other, chlist, displayer):
500 def display(other, chlist, displayer):
501 limit = cmdutil.loglimit(opts)
501 limit = cmdutil.loglimit(opts)
502 if opts.get('newest_first'):
502 if opts.get('newest_first'):
503 chlist.reverse()
503 chlist.reverse()
504 count = 0
504 count = 0
505 for n in chlist:
505 for n in chlist:
506 if limit is not None and count >= limit:
506 if limit is not None and count >= limit:
507 break
507 break
508 parents = [p for p in other.changelog.parents(n) if p != nullid]
508 parents = [p for p in other.changelog.parents(n) if p != nullid]
509 if opts.get('no_merges') and len(parents) == 2:
509 if opts.get('no_merges') and len(parents) == 2:
510 continue
510 continue
511 count += 1
511 count += 1
512 displayer.show(other[n])
512 displayer.show(other[n])
513 return _incoming(display, subreporecurse, ui, repo, source, opts)
513 return _incoming(display, subreporecurse, ui, repo, source, opts)
514
514
515 def _outgoing(ui, repo, dest, opts):
515 def _outgoing(ui, repo, dest, opts):
516 dest = ui.expandpath(dest or 'default-push', dest or 'default')
516 dest = ui.expandpath(dest or 'default-push', dest or 'default')
517 dest, branches = parseurl(dest, opts.get('branch'))
517 dest, branches = parseurl(dest, opts.get('branch'))
518 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
518 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
519 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
519 revs, checkout = addbranchrevs(repo, repo, branches, opts.get('rev'))
520 if revs:
520 if revs:
521 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
521 revs = [repo.lookup(rev) for rev in scmutil.revrange(repo, revs)]
522
522
523 other = peer(repo, opts, dest)
523 other = peer(repo, opts, dest)
524 outgoing = discovery.findcommonoutgoing(repo, other, revs,
524 outgoing = discovery.findcommonoutgoing(repo, other, revs,
525 force=opts.get('force'))
525 force=opts.get('force'))
526 o = outgoing.missing
526 o = outgoing.missing
527 if not o:
527 if not o:
528 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
528 scmutil.nochangesfound(repo.ui, repo, outgoing.excluded)
529 return None
529 return None
530 return o
530 return o
531
531
532 def outgoing(ui, repo, dest, opts):
532 def outgoing(ui, repo, dest, opts):
533 def recurse():
533 def recurse():
534 ret = 1
534 ret = 1
535 if opts.get('subrepos'):
535 if opts.get('subrepos'):
536 ctx = repo[None]
536 ctx = repo[None]
537 for subpath in sorted(ctx.substate):
537 for subpath in sorted(ctx.substate):
538 sub = ctx.sub(subpath)
538 sub = ctx.sub(subpath)
539 ret = min(ret, sub.outgoing(ui, dest, opts))
539 ret = min(ret, sub.outgoing(ui, dest, opts))
540 return ret
540 return ret
541
541
542 limit = cmdutil.loglimit(opts)
542 limit = cmdutil.loglimit(opts)
543 o = _outgoing(ui, repo, dest, opts)
543 o = _outgoing(ui, repo, dest, opts)
544 if o is None:
544 if o is None:
545 return recurse()
545 return recurse()
546
546
547 if opts.get('newest_first'):
547 if opts.get('newest_first'):
548 o.reverse()
548 o.reverse()
549 displayer = cmdutil.show_changeset(ui, repo, opts)
549 displayer = cmdutil.show_changeset(ui, repo, opts)
550 count = 0
550 count = 0
551 for n in o:
551 for n in o:
552 if limit is not None and count >= limit:
552 if limit is not None and count >= limit:
553 break
553 break
554 parents = [p for p in repo.changelog.parents(n) if p != nullid]
554 parents = [p for p in repo.changelog.parents(n) if p != nullid]
555 if opts.get('no_merges') and len(parents) == 2:
555 if opts.get('no_merges') and len(parents) == 2:
556 continue
556 continue
557 count += 1
557 count += 1
558 displayer.show(repo[n])
558 displayer.show(repo[n])
559 displayer.close()
559 displayer.close()
560 recurse()
560 recurse()
561 return 0 # exit code is zero since we found outgoing changes
561 return 0 # exit code is zero since we found outgoing changes
562
562
563 def revert(repo, node, choose):
563 def revert(repo, node, choose):
564 """revert changes to revision in node without updating dirstate"""
564 """revert changes to revision in node without updating dirstate"""
565 return mergemod.update(repo, node, False, True, choose)[3] > 0
565 return mergemod.update(repo, node, False, True, choose)[3] > 0
566
566
567 def verify(repo):
567 def verify(repo):
568 """verify the consistency of a repository"""
568 """verify the consistency of a repository"""
569 return verifymod.verify(repo)
569 return verifymod.verify(repo)
570
570
571 def remoteui(src, opts):
571 def remoteui(src, opts):
572 'build a remote ui from ui or repo and opts'
572 'build a remote ui from ui or repo and opts'
573 if util.safehasattr(src, 'baseui'): # looks like a repository
573 if util.safehasattr(src, 'baseui'): # looks like a repository
574 dst = src.baseui.copy() # drop repo-specific config
574 dst = src.baseui.copy() # drop repo-specific config
575 src = src.ui # copy target options from repo
575 src = src.ui # copy target options from repo
576 else: # assume it's a global ui object
576 else: # assume it's a global ui object
577 dst = src.copy() # keep all global options
577 dst = src.copy() # keep all global options
578
578
579 # copy ssh-specific options
579 # copy ssh-specific options
580 for o in 'ssh', 'remotecmd':
580 for o in 'ssh', 'remotecmd':
581 v = opts.get(o) or src.config('ui', o)
581 v = opts.get(o) or src.config('ui', o)
582 if v:
582 if v:
583 dst.setconfig("ui", o, v)
583 dst.setconfig("ui", o, v)
584
584
585 # copy bundle-specific options
585 # copy bundle-specific options
586 r = src.config('bundle', 'mainreporoot')
586 r = src.config('bundle', 'mainreporoot')
587 if r:
587 if r:
588 dst.setconfig('bundle', 'mainreporoot', r)
588 dst.setconfig('bundle', 'mainreporoot', r)
589
589
590 # copy selected local settings to the remote ui
590 # copy selected local settings to the remote ui
591 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
591 for sect in ('auth', 'hostfingerprints', 'http_proxy'):
592 for key, val in src.configitems(sect):
592 for key, val in src.configitems(sect):
593 dst.setconfig(sect, key, val)
593 dst.setconfig(sect, key, val)
594 v = src.config('web', 'cacerts')
594 v = src.config('web', 'cacerts')
595 if v:
595 if v:
596 dst.setconfig('web', 'cacerts', util.expandpath(v))
596 dst.setconfig('web', 'cacerts', util.expandpath(v))
597
597
598 return dst
598 return dst
@@ -1,207 +1,225 b''
1 $ "$TESTDIR/hghave" serve || exit 80
1 $ "$TESTDIR/hghave" serve || exit 80
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo foo>foo
5 $ echo foo>foo
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
6 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
7 $ echo foo>foo.d/foo
7 $ echo foo>foo.d/foo
8 $ echo bar>foo.d/bAr.hg.d/BaR
8 $ echo bar>foo.d/bAr.hg.d/BaR
9 $ echo bar>foo.d/baR.d.hg/bAR
9 $ echo bar>foo.d/baR.d.hg/bAR
10 $ hg commit -A -m 1
10 $ hg commit -A -m 1
11 adding foo
11 adding foo
12 adding foo.d/bAr.hg.d/BaR
12 adding foo.d/bAr.hg.d/BaR
13 adding foo.d/baR.d.hg/bAR
13 adding foo.d/baR.d.hg/bAR
14 adding foo.d/foo
14 adding foo.d/foo
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
15 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
16 $ hg --config server.uncompressed=False serve -p $HGPORT1 -d --pid-file=../hg2.pid
17
17
18 Test server address cannot be reused
18 Test server address cannot be reused
19
19
20 #if windows
20 #if windows
21 $ hg serve -p $HGPORT1 2>&1
21 $ hg serve -p $HGPORT1 2>&1
22 abort: cannot start server at ':$HGPORT1': * (glob)
22 abort: cannot start server at ':$HGPORT1': * (glob)
23 [255]
23 [255]
24 #else
24 #else
25 $ hg serve -p $HGPORT1 2>&1
25 $ hg serve -p $HGPORT1 2>&1
26 abort: cannot start server at ':$HGPORT1': Address already in use
26 abort: cannot start server at ':$HGPORT1': Address already in use
27 [255]
27 [255]
28 #endif
28 #endif
29 $ cd ..
29 $ cd ..
30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
30 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
31
31
32 clone via stream
32 clone via stream
33
33
34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
34 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
35 streaming all changes
35 streaming all changes
36 6 files to transfer, 606 bytes of data
36 6 files to transfer, 606 bytes of data
37 transferred * bytes in * seconds (*/sec) (glob)
37 transferred * bytes in * seconds (*/sec) (glob)
38 updating to branch default
38 updating to branch default
39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
39 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
40 $ hg verify -R copy
40 $ hg verify -R copy
41 checking changesets
41 checking changesets
42 checking manifests
42 checking manifests
43 crosschecking files in changesets and manifests
43 crosschecking files in changesets and manifests
44 checking files
44 checking files
45 4 files, 1 changesets, 4 total revisions
45 4 files, 1 changesets, 4 total revisions
46
46
47 try to clone via stream, should use pull instead
47 try to clone via stream, should use pull instead
48
48
49 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
49 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
50 requesting all changes
50 requesting all changes
51 adding changesets
51 adding changesets
52 adding manifests
52 adding manifests
53 adding file changes
53 adding file changes
54 added 1 changesets with 4 changes to 4 files
54 added 1 changesets with 4 changes to 4 files
55 updating to branch default
55 updating to branch default
56 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
57
57
58 clone via pull
58 clone via pull
59
59
60 $ hg clone http://localhost:$HGPORT1/ copy-pull
60 $ hg clone http://localhost:$HGPORT1/ copy-pull
61 requesting all changes
61 requesting all changes
62 adding changesets
62 adding changesets
63 adding manifests
63 adding manifests
64 adding file changes
64 adding file changes
65 added 1 changesets with 4 changes to 4 files
65 added 1 changesets with 4 changes to 4 files
66 updating to branch default
66 updating to branch default
67 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 $ hg verify -R copy-pull
68 $ hg verify -R copy-pull
69 checking changesets
69 checking changesets
70 checking manifests
70 checking manifests
71 crosschecking files in changesets and manifests
71 crosschecking files in changesets and manifests
72 checking files
72 checking files
73 4 files, 1 changesets, 4 total revisions
73 4 files, 1 changesets, 4 total revisions
74 $ cd test
74 $ cd test
75 $ echo bar > bar
75 $ echo bar > bar
76 $ hg commit -A -d '1 0' -m 2
76 $ hg commit -A -d '1 0' -m 2
77 adding bar
77 adding bar
78 $ cd ..
78 $ cd ..
79
79
80 clone over http with --update
81
82 $ hg clone http://localhost:$HGPORT1/ updated --update 0
83 requesting all changes
84 adding changesets
85 adding manifests
86 adding file changes
87 added 2 changesets with 5 changes to 5 files
88 updating to branch default
89 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 $ hg log -r . -R updated
91 changeset: 0:8b6053c928fe
92 user: test
93 date: Thu Jan 01 00:00:00 1970 +0000
94 summary: 1
95
96 $ rm -rf updated
97
80 incoming via HTTP
98 incoming via HTTP
81
99
82 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
100 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
83 adding changesets
101 adding changesets
84 adding manifests
102 adding manifests
85 adding file changes
103 adding file changes
86 added 1 changesets with 4 changes to 4 files
104 added 1 changesets with 4 changes to 4 files
87 updating to branch default
105 updating to branch default
88 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ cd partial
107 $ cd partial
90 $ touch LOCAL
108 $ touch LOCAL
91 $ hg ci -qAm LOCAL
109 $ hg ci -qAm LOCAL
92 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
110 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
93 comparing with http://localhost:$HGPORT1/
111 comparing with http://localhost:$HGPORT1/
94 searching for changes
112 searching for changes
95 2
113 2
96 $ cd ..
114 $ cd ..
97
115
98 pull
116 pull
99
117
100 $ cd copy-pull
118 $ cd copy-pull
101 $ echo '[hooks]' >> .hg/hgrc
119 $ echo '[hooks]' >> .hg/hgrc
102 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
120 $ echo "changegroup = python \"$TESTDIR/printenv.py\" changegroup" >> .hg/hgrc
103 $ hg pull
121 $ hg pull
104 pulling from http://localhost:$HGPORT1/
122 pulling from http://localhost:$HGPORT1/
105 searching for changes
123 searching for changes
106 adding changesets
124 adding changesets
107 adding manifests
125 adding manifests
108 adding file changes
126 adding file changes
109 added 1 changesets with 1 changes to 1 files
127 added 1 changesets with 1 changes to 1 files
110 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost:$HGPORT1/
128 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_URL=http://localhost:$HGPORT1/
111 (run 'hg update' to get a working copy)
129 (run 'hg update' to get a working copy)
112 $ cd ..
130 $ cd ..
113
131
114 clone from invalid URL
132 clone from invalid URL
115
133
116 $ hg clone http://localhost:$HGPORT/bad
134 $ hg clone http://localhost:$HGPORT/bad
117 abort: HTTP Error 404: Not Found
135 abort: HTTP Error 404: Not Found
118 [255]
136 [255]
119
137
120 test http authentication
138 test http authentication
121 + use the same server to test server side streaming preference
139 + use the same server to test server side streaming preference
122
140
123 $ cd test
141 $ cd test
124 $ cat << EOT > userpass.py
142 $ cat << EOT > userpass.py
125 > import base64
143 > import base64
126 > from mercurial.hgweb import common
144 > from mercurial.hgweb import common
127 > def perform_authentication(hgweb, req, op):
145 > def perform_authentication(hgweb, req, op):
128 > auth = req.env.get('HTTP_AUTHORIZATION')
146 > auth = req.env.get('HTTP_AUTHORIZATION')
129 > if not auth:
147 > if not auth:
130 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
148 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
131 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
149 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
132 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
150 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
133 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
151 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
134 > def extsetup():
152 > def extsetup():
135 > common.permhooks.insert(0, perform_authentication)
153 > common.permhooks.insert(0, perform_authentication)
136 > EOT
154 > EOT
137 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
155 $ hg --config extensions.x=userpass.py serve -p $HGPORT2 -d --pid-file=pid \
138 > --config server.preferuncompressed=True
156 > --config server.preferuncompressed=True
139 $ cat pid >> $DAEMON_PIDS
157 $ cat pid >> $DAEMON_PIDS
140
158
141 $ hg id http://localhost:$HGPORT2/
159 $ hg id http://localhost:$HGPORT2/
142 abort: http authorization required
160 abort: http authorization required
143 [255]
161 [255]
144 $ hg id http://user@localhost:$HGPORT2/
162 $ hg id http://user@localhost:$HGPORT2/
145 abort: http authorization required
163 abort: http authorization required
146 [255]
164 [255]
147 $ hg id http://user:pass@localhost:$HGPORT2/
165 $ hg id http://user:pass@localhost:$HGPORT2/
148 5fed3813f7f5
166 5fed3813f7f5
149 $ echo '[auth]' >> .hg/hgrc
167 $ echo '[auth]' >> .hg/hgrc
150 $ echo 'l.schemes=http' >> .hg/hgrc
168 $ echo 'l.schemes=http' >> .hg/hgrc
151 $ echo 'l.prefix=lo' >> .hg/hgrc
169 $ echo 'l.prefix=lo' >> .hg/hgrc
152 $ echo 'l.username=user' >> .hg/hgrc
170 $ echo 'l.username=user' >> .hg/hgrc
153 $ echo 'l.password=pass' >> .hg/hgrc
171 $ echo 'l.password=pass' >> .hg/hgrc
154 $ hg id http://localhost:$HGPORT2/
172 $ hg id http://localhost:$HGPORT2/
155 5fed3813f7f5
173 5fed3813f7f5
156 $ hg id http://localhost:$HGPORT2/
174 $ hg id http://localhost:$HGPORT2/
157 5fed3813f7f5
175 5fed3813f7f5
158 $ hg id http://user@localhost:$HGPORT2/
176 $ hg id http://user@localhost:$HGPORT2/
159 5fed3813f7f5
177 5fed3813f7f5
160 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
178 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
161 streaming all changes
179 streaming all changes
162 7 files to transfer, 916 bytes of data
180 7 files to transfer, 916 bytes of data
163 transferred * bytes in * seconds (*/sec) (glob)
181 transferred * bytes in * seconds (*/sec) (glob)
164 updating to branch default
182 updating to branch default
165 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
183 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
166
184
167 $ hg id http://user2@localhost:$HGPORT2/
185 $ hg id http://user2@localhost:$HGPORT2/
168 abort: http authorization required
186 abort: http authorization required
169 [255]
187 [255]
170 $ hg id http://user:pass2@localhost:$HGPORT2/
188 $ hg id http://user:pass2@localhost:$HGPORT2/
171 abort: HTTP Error 403: no
189 abort: HTTP Error 403: no
172 [255]
190 [255]
173
191
174 $ cd ..
192 $ cd ..
175
193
176 clone of serve with repo in root and unserved subrepo (issue2970)
194 clone of serve with repo in root and unserved subrepo (issue2970)
177
195
178 $ hg --cwd test init sub
196 $ hg --cwd test init sub
179 $ echo empty > test/sub/empty
197 $ echo empty > test/sub/empty
180 $ hg --cwd test/sub add empty
198 $ hg --cwd test/sub add empty
181 $ hg --cwd test/sub commit -qm 'add empty'
199 $ hg --cwd test/sub commit -qm 'add empty'
182 $ hg --cwd test/sub tag -r 0 something
200 $ hg --cwd test/sub tag -r 0 something
183 $ echo sub = sub > test/.hgsub
201 $ echo sub = sub > test/.hgsub
184 $ hg --cwd test add .hgsub
202 $ hg --cwd test add .hgsub
185 $ hg --cwd test commit -qm 'add subrepo'
203 $ hg --cwd test commit -qm 'add subrepo'
186 $ hg clone http://localhost:$HGPORT noslash-clone
204 $ hg clone http://localhost:$HGPORT noslash-clone
187 requesting all changes
205 requesting all changes
188 adding changesets
206 adding changesets
189 adding manifests
207 adding manifests
190 adding file changes
208 adding file changes
191 added 3 changesets with 7 changes to 7 files
209 added 3 changesets with 7 changes to 7 files
192 updating to branch default
210 updating to branch default
193 abort: HTTP Error 404: Not Found
211 abort: HTTP Error 404: Not Found
194 [255]
212 [255]
195 $ hg clone http://localhost:$HGPORT/ slash-clone
213 $ hg clone http://localhost:$HGPORT/ slash-clone
196 requesting all changes
214 requesting all changes
197 adding changesets
215 adding changesets
198 adding manifests
216 adding manifests
199 adding file changes
217 adding file changes
200 added 3 changesets with 7 changes to 7 files
218 added 3 changesets with 7 changes to 7 files
201 updating to branch default
219 updating to branch default
202 abort: HTTP Error 404: Not Found
220 abort: HTTP Error 404: Not Found
203 [255]
221 [255]
204
222
205 check error log
223 check error log
206
224
207 $ cat error.log
225 $ cat error.log
General Comments 0
You need to be logged in to leave comments. Login now