##// END OF EJS Templates
run-tests: auto-replace 'TXNID' output...
Pierre-Yves David -
r31741:728d3735 default
parent child Browse files
Show More
@@ -1,2638 +1,2639 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 #
2 #
3 # run-tests.py - Run a set of tests on Mercurial
3 # run-tests.py - Run a set of tests on Mercurial
4 #
4 #
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
5 # Copyright 2006 Matt Mackall <mpm@selenic.com>
6 #
6 #
7 # This software may be used and distributed according to the terms of the
7 # This software may be used and distributed according to the terms of the
8 # GNU General Public License version 2 or any later version.
8 # GNU General Public License version 2 or any later version.
9
9
10 # Modifying this script is tricky because it has many modes:
10 # Modifying this script is tricky because it has many modes:
11 # - serial (default) vs parallel (-jN, N > 1)
11 # - serial (default) vs parallel (-jN, N > 1)
12 # - no coverage (default) vs coverage (-c, -C, -s)
12 # - no coverage (default) vs coverage (-c, -C, -s)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
13 # - temp install (default) vs specific hg script (--with-hg, --local)
14 # - tests are a mix of shell scripts and Python scripts
14 # - tests are a mix of shell scripts and Python scripts
15 #
15 #
16 # If you change this script, it is recommended that you ensure you
16 # If you change this script, it is recommended that you ensure you
17 # haven't broken it by running it in various modes with a representative
17 # haven't broken it by running it in various modes with a representative
18 # sample of test scripts. For example:
18 # sample of test scripts. For example:
19 #
19 #
20 # 1) serial, no coverage, temp install:
20 # 1) serial, no coverage, temp install:
21 # ./run-tests.py test-s*
21 # ./run-tests.py test-s*
22 # 2) serial, no coverage, local hg:
22 # 2) serial, no coverage, local hg:
23 # ./run-tests.py --local test-s*
23 # ./run-tests.py --local test-s*
24 # 3) serial, coverage, temp install:
24 # 3) serial, coverage, temp install:
25 # ./run-tests.py -c test-s*
25 # ./run-tests.py -c test-s*
26 # 4) serial, coverage, local hg:
26 # 4) serial, coverage, local hg:
27 # ./run-tests.py -c --local test-s* # unsupported
27 # ./run-tests.py -c --local test-s* # unsupported
28 # 5) parallel, no coverage, temp install:
28 # 5) parallel, no coverage, temp install:
29 # ./run-tests.py -j2 test-s*
29 # ./run-tests.py -j2 test-s*
30 # 6) parallel, no coverage, local hg:
30 # 6) parallel, no coverage, local hg:
31 # ./run-tests.py -j2 --local test-s*
31 # ./run-tests.py -j2 --local test-s*
32 # 7) parallel, coverage, temp install:
32 # 7) parallel, coverage, temp install:
33 # ./run-tests.py -j2 -c test-s* # currently broken
33 # ./run-tests.py -j2 -c test-s* # currently broken
34 # 8) parallel, coverage, local install:
34 # 8) parallel, coverage, local install:
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
35 # ./run-tests.py -j2 -c --local test-s* # unsupported (and broken)
36 # 9) parallel, custom tmp dir:
36 # 9) parallel, custom tmp dir:
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
37 # ./run-tests.py -j2 --tmpdir /tmp/myhgtests
38 # 10) parallel, pure, tests that call run-tests:
38 # 10) parallel, pure, tests that call run-tests:
39 # ./run-tests.py --pure `grep -l run-tests.py *.t`
39 # ./run-tests.py --pure `grep -l run-tests.py *.t`
40 #
40 #
41 # (You could use any subset of the tests: test-s* happens to match
41 # (You could use any subset of the tests: test-s* happens to match
42 # enough that it's worth doing parallel runs, few enough that it
42 # enough that it's worth doing parallel runs, few enough that it
43 # completes fairly quickly, includes both shell and Python scripts, and
43 # completes fairly quickly, includes both shell and Python scripts, and
44 # includes some scripts that run daemon processes.)
44 # includes some scripts that run daemon processes.)
45
45
46 from __future__ import absolute_import, print_function
46 from __future__ import absolute_import, print_function
47
47
48 import difflib
48 import difflib
49 import distutils.version as version
49 import distutils.version as version
50 import errno
50 import errno
51 import json
51 import json
52 import optparse
52 import optparse
53 import os
53 import os
54 import random
54 import random
55 import re
55 import re
56 import shutil
56 import shutil
57 import signal
57 import signal
58 import socket
58 import socket
59 import subprocess
59 import subprocess
60 import sys
60 import sys
61 try:
61 try:
62 import sysconfig
62 import sysconfig
63 except ImportError:
63 except ImportError:
64 # sysconfig doesn't exist in Python 2.6
64 # sysconfig doesn't exist in Python 2.6
65 sysconfig = None
65 sysconfig = None
66 import tempfile
66 import tempfile
67 import threading
67 import threading
68 import time
68 import time
69 import unittest
69 import unittest
70 import xml.dom.minidom as minidom
70 import xml.dom.minidom as minidom
71
71
72 try:
72 try:
73 import Queue as queue
73 import Queue as queue
74 except ImportError:
74 except ImportError:
75 import queue
75 import queue
76
76
77 if os.environ.get('RTUNICODEPEDANTRY', False):
77 if os.environ.get('RTUNICODEPEDANTRY', False):
78 try:
78 try:
79 reload(sys)
79 reload(sys)
80 sys.setdefaultencoding("undefined")
80 sys.setdefaultencoding("undefined")
81 except NameError:
81 except NameError:
82 pass
82 pass
83
83
84 osenvironb = getattr(os, 'environb', os.environ)
84 osenvironb = getattr(os, 'environb', os.environ)
85 processlock = threading.Lock()
85 processlock = threading.Lock()
86
86
87 if sys.version_info > (3, 5, 0):
87 if sys.version_info > (3, 5, 0):
88 PYTHON3 = True
88 PYTHON3 = True
89 xrange = range # we use xrange in one place, and we'd rather not use range
89 xrange = range # we use xrange in one place, and we'd rather not use range
90 def _bytespath(p):
90 def _bytespath(p):
91 return p.encode('utf-8')
91 return p.encode('utf-8')
92
92
93 def _strpath(p):
93 def _strpath(p):
94 return p.decode('utf-8')
94 return p.decode('utf-8')
95
95
96 elif sys.version_info >= (3, 0, 0):
96 elif sys.version_info >= (3, 0, 0):
97 print('%s is only supported on Python 3.5+ and 2.6-2.7, not %s' %
97 print('%s is only supported on Python 3.5+ and 2.6-2.7, not %s' %
98 (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])))
98 (sys.argv[0], '.'.join(str(v) for v in sys.version_info[:3])))
99 sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
99 sys.exit(70) # EX_SOFTWARE from `man 3 sysexit`
100 else:
100 else:
101 PYTHON3 = False
101 PYTHON3 = False
102
102
103 # In python 2.x, path operations are generally done using
103 # In python 2.x, path operations are generally done using
104 # bytestrings by default, so we don't have to do any extra
104 # bytestrings by default, so we don't have to do any extra
105 # fiddling there. We define the wrapper functions anyway just to
105 # fiddling there. We define the wrapper functions anyway just to
106 # help keep code consistent between platforms.
106 # help keep code consistent between platforms.
107 def _bytespath(p):
107 def _bytespath(p):
108 return p
108 return p
109
109
110 _strpath = _bytespath
110 _strpath = _bytespath
111
111
112 # For Windows support
112 # For Windows support
113 wifexited = getattr(os, "WIFEXITED", lambda x: False)
113 wifexited = getattr(os, "WIFEXITED", lambda x: False)
114
114
115 # Whether to use IPv6
115 # Whether to use IPv6
116 def checksocketfamily(name, port=20058):
116 def checksocketfamily(name, port=20058):
117 """return true if we can listen on localhost using family=name
117 """return true if we can listen on localhost using family=name
118
118
119 name should be either 'AF_INET', or 'AF_INET6'.
119 name should be either 'AF_INET', or 'AF_INET6'.
120 port being used is okay - EADDRINUSE is considered as successful.
120 port being used is okay - EADDRINUSE is considered as successful.
121 """
121 """
122 family = getattr(socket, name, None)
122 family = getattr(socket, name, None)
123 if family is None:
123 if family is None:
124 return False
124 return False
125 try:
125 try:
126 s = socket.socket(family, socket.SOCK_STREAM)
126 s = socket.socket(family, socket.SOCK_STREAM)
127 s.bind(('localhost', port))
127 s.bind(('localhost', port))
128 s.close()
128 s.close()
129 return True
129 return True
130 except socket.error as exc:
130 except socket.error as exc:
131 if exc.errno == errno.EADDRINUSE:
131 if exc.errno == errno.EADDRINUSE:
132 return True
132 return True
133 elif exc.errno in (errno.EADDRNOTAVAIL, errno.EPROTONOSUPPORT):
133 elif exc.errno in (errno.EADDRNOTAVAIL, errno.EPROTONOSUPPORT):
134 return False
134 return False
135 else:
135 else:
136 raise
136 raise
137 else:
137 else:
138 return False
138 return False
139
139
140 # useipv6 will be set by parseargs
140 # useipv6 will be set by parseargs
141 useipv6 = None
141 useipv6 = None
142
142
143 def checkportisavailable(port):
143 def checkportisavailable(port):
144 """return true if a port seems free to bind on localhost"""
144 """return true if a port seems free to bind on localhost"""
145 if useipv6:
145 if useipv6:
146 family = socket.AF_INET6
146 family = socket.AF_INET6
147 else:
147 else:
148 family = socket.AF_INET
148 family = socket.AF_INET
149 try:
149 try:
150 s = socket.socket(family, socket.SOCK_STREAM)
150 s = socket.socket(family, socket.SOCK_STREAM)
151 s.bind(('localhost', port))
151 s.bind(('localhost', port))
152 s.close()
152 s.close()
153 return True
153 return True
154 except socket.error as exc:
154 except socket.error as exc:
155 if exc.errno not in (errno.EADDRINUSE, errno.EADDRNOTAVAIL,
155 if exc.errno not in (errno.EADDRINUSE, errno.EADDRNOTAVAIL,
156 errno.EPROTONOSUPPORT):
156 errno.EPROTONOSUPPORT):
157 raise
157 raise
158 return False
158 return False
159
159
160 closefds = os.name == 'posix'
160 closefds = os.name == 'posix'
161 def Popen4(cmd, wd, timeout, env=None):
161 def Popen4(cmd, wd, timeout, env=None):
162 processlock.acquire()
162 processlock.acquire()
163 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
163 p = subprocess.Popen(cmd, shell=True, bufsize=-1, cwd=wd, env=env,
164 close_fds=closefds,
164 close_fds=closefds,
165 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
165 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
166 stderr=subprocess.STDOUT)
166 stderr=subprocess.STDOUT)
167 processlock.release()
167 processlock.release()
168
168
169 p.fromchild = p.stdout
169 p.fromchild = p.stdout
170 p.tochild = p.stdin
170 p.tochild = p.stdin
171 p.childerr = p.stderr
171 p.childerr = p.stderr
172
172
173 p.timeout = False
173 p.timeout = False
174 if timeout:
174 if timeout:
175 def t():
175 def t():
176 start = time.time()
176 start = time.time()
177 while time.time() - start < timeout and p.returncode is None:
177 while time.time() - start < timeout and p.returncode is None:
178 time.sleep(.1)
178 time.sleep(.1)
179 p.timeout = True
179 p.timeout = True
180 if p.returncode is None:
180 if p.returncode is None:
181 terminate(p)
181 terminate(p)
182 threading.Thread(target=t).start()
182 threading.Thread(target=t).start()
183
183
184 return p
184 return p
185
185
186 PYTHON = _bytespath(sys.executable.replace('\\', '/'))
186 PYTHON = _bytespath(sys.executable.replace('\\', '/'))
187 IMPL_PATH = b'PYTHONPATH'
187 IMPL_PATH = b'PYTHONPATH'
188 if 'java' in sys.platform:
188 if 'java' in sys.platform:
189 IMPL_PATH = b'JYTHONPATH'
189 IMPL_PATH = b'JYTHONPATH'
190
190
191 defaults = {
191 defaults = {
192 'jobs': ('HGTEST_JOBS', 1),
192 'jobs': ('HGTEST_JOBS', 1),
193 'timeout': ('HGTEST_TIMEOUT', 180),
193 'timeout': ('HGTEST_TIMEOUT', 180),
194 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 500),
194 'slowtimeout': ('HGTEST_SLOWTIMEOUT', 500),
195 'port': ('HGTEST_PORT', 20059),
195 'port': ('HGTEST_PORT', 20059),
196 'shell': ('HGTEST_SHELL', 'sh'),
196 'shell': ('HGTEST_SHELL', 'sh'),
197 }
197 }
198
198
199 def canonpath(path):
199 def canonpath(path):
200 return os.path.realpath(os.path.expanduser(path))
200 return os.path.realpath(os.path.expanduser(path))
201
201
202 def parselistfiles(files, listtype, warn=True):
202 def parselistfiles(files, listtype, warn=True):
203 entries = dict()
203 entries = dict()
204 for filename in files:
204 for filename in files:
205 try:
205 try:
206 path = os.path.expanduser(os.path.expandvars(filename))
206 path = os.path.expanduser(os.path.expandvars(filename))
207 f = open(path, "rb")
207 f = open(path, "rb")
208 except IOError as err:
208 except IOError as err:
209 if err.errno != errno.ENOENT:
209 if err.errno != errno.ENOENT:
210 raise
210 raise
211 if warn:
211 if warn:
212 print("warning: no such %s file: %s" % (listtype, filename))
212 print("warning: no such %s file: %s" % (listtype, filename))
213 continue
213 continue
214
214
215 for line in f.readlines():
215 for line in f.readlines():
216 line = line.split(b'#', 1)[0].strip()
216 line = line.split(b'#', 1)[0].strip()
217 if line:
217 if line:
218 entries[line] = filename
218 entries[line] = filename
219
219
220 f.close()
220 f.close()
221 return entries
221 return entries
222
222
223 def getparser():
223 def getparser():
224 """Obtain the OptionParser used by the CLI."""
224 """Obtain the OptionParser used by the CLI."""
225 parser = optparse.OptionParser("%prog [options] [tests]")
225 parser = optparse.OptionParser("%prog [options] [tests]")
226
226
227 # keep these sorted
227 # keep these sorted
228 parser.add_option("--blacklist", action="append",
228 parser.add_option("--blacklist", action="append",
229 help="skip tests listed in the specified blacklist file")
229 help="skip tests listed in the specified blacklist file")
230 parser.add_option("--whitelist", action="append",
230 parser.add_option("--whitelist", action="append",
231 help="always run tests listed in the specified whitelist file")
231 help="always run tests listed in the specified whitelist file")
232 parser.add_option("--changed", type="string",
232 parser.add_option("--changed", type="string",
233 help="run tests that are changed in parent rev or working directory")
233 help="run tests that are changed in parent rev or working directory")
234 parser.add_option("-C", "--annotate", action="store_true",
234 parser.add_option("-C", "--annotate", action="store_true",
235 help="output files annotated with coverage")
235 help="output files annotated with coverage")
236 parser.add_option("-c", "--cover", action="store_true",
236 parser.add_option("-c", "--cover", action="store_true",
237 help="print a test coverage report")
237 help="print a test coverage report")
238 parser.add_option("-d", "--debug", action="store_true",
238 parser.add_option("-d", "--debug", action="store_true",
239 help="debug mode: write output of test scripts to console"
239 help="debug mode: write output of test scripts to console"
240 " rather than capturing and diffing it (disables timeout)")
240 " rather than capturing and diffing it (disables timeout)")
241 parser.add_option("-f", "--first", action="store_true",
241 parser.add_option("-f", "--first", action="store_true",
242 help="exit on the first test failure")
242 help="exit on the first test failure")
243 parser.add_option("-H", "--htmlcov", action="store_true",
243 parser.add_option("-H", "--htmlcov", action="store_true",
244 help="create an HTML report of the coverage of the files")
244 help="create an HTML report of the coverage of the files")
245 parser.add_option("-i", "--interactive", action="store_true",
245 parser.add_option("-i", "--interactive", action="store_true",
246 help="prompt to accept changed output")
246 help="prompt to accept changed output")
247 parser.add_option("-j", "--jobs", type="int",
247 parser.add_option("-j", "--jobs", type="int",
248 help="number of jobs to run in parallel"
248 help="number of jobs to run in parallel"
249 " (default: $%s or %d)" % defaults['jobs'])
249 " (default: $%s or %d)" % defaults['jobs'])
250 parser.add_option("--keep-tmpdir", action="store_true",
250 parser.add_option("--keep-tmpdir", action="store_true",
251 help="keep temporary directory after running tests")
251 help="keep temporary directory after running tests")
252 parser.add_option("-k", "--keywords",
252 parser.add_option("-k", "--keywords",
253 help="run tests matching keywords")
253 help="run tests matching keywords")
254 parser.add_option("-l", "--local", action="store_true",
254 parser.add_option("-l", "--local", action="store_true",
255 help="shortcut for --with-hg=<testdir>/../hg, "
255 help="shortcut for --with-hg=<testdir>/../hg, "
256 "and --with-chg=<testdir>/../contrib/chg/chg if --chg is set")
256 "and --with-chg=<testdir>/../contrib/chg/chg if --chg is set")
257 parser.add_option("--loop", action="store_true",
257 parser.add_option("--loop", action="store_true",
258 help="loop tests repeatedly")
258 help="loop tests repeatedly")
259 parser.add_option("--runs-per-test", type="int", dest="runs_per_test",
259 parser.add_option("--runs-per-test", type="int", dest="runs_per_test",
260 help="run each test N times (default=1)", default=1)
260 help="run each test N times (default=1)", default=1)
261 parser.add_option("-n", "--nodiff", action="store_true",
261 parser.add_option("-n", "--nodiff", action="store_true",
262 help="skip showing test changes")
262 help="skip showing test changes")
263 parser.add_option("-p", "--port", type="int",
263 parser.add_option("-p", "--port", type="int",
264 help="port on which servers should listen"
264 help="port on which servers should listen"
265 " (default: $%s or %d)" % defaults['port'])
265 " (default: $%s or %d)" % defaults['port'])
266 parser.add_option("--compiler", type="string",
266 parser.add_option("--compiler", type="string",
267 help="compiler to build with")
267 help="compiler to build with")
268 parser.add_option("--pure", action="store_true",
268 parser.add_option("--pure", action="store_true",
269 help="use pure Python code instead of C extensions")
269 help="use pure Python code instead of C extensions")
270 parser.add_option("-R", "--restart", action="store_true",
270 parser.add_option("-R", "--restart", action="store_true",
271 help="restart at last error")
271 help="restart at last error")
272 parser.add_option("-r", "--retest", action="store_true",
272 parser.add_option("-r", "--retest", action="store_true",
273 help="retest failed tests")
273 help="retest failed tests")
274 parser.add_option("-S", "--noskips", action="store_true",
274 parser.add_option("-S", "--noskips", action="store_true",
275 help="don't report skip tests verbosely")
275 help="don't report skip tests verbosely")
276 parser.add_option("--shell", type="string",
276 parser.add_option("--shell", type="string",
277 help="shell to use (default: $%s or %s)" % defaults['shell'])
277 help="shell to use (default: $%s or %s)" % defaults['shell'])
278 parser.add_option("-t", "--timeout", type="int",
278 parser.add_option("-t", "--timeout", type="int",
279 help="kill errant tests after TIMEOUT seconds"
279 help="kill errant tests after TIMEOUT seconds"
280 " (default: $%s or %d)" % defaults['timeout'])
280 " (default: $%s or %d)" % defaults['timeout'])
281 parser.add_option("--slowtimeout", type="int",
281 parser.add_option("--slowtimeout", type="int",
282 help="kill errant slow tests after SLOWTIMEOUT seconds"
282 help="kill errant slow tests after SLOWTIMEOUT seconds"
283 " (default: $%s or %d)" % defaults['slowtimeout'])
283 " (default: $%s or %d)" % defaults['slowtimeout'])
284 parser.add_option("--time", action="store_true",
284 parser.add_option("--time", action="store_true",
285 help="time how long each test takes")
285 help="time how long each test takes")
286 parser.add_option("--json", action="store_true",
286 parser.add_option("--json", action="store_true",
287 help="store test result data in 'report.json' file")
287 help="store test result data in 'report.json' file")
288 parser.add_option("--tmpdir", type="string",
288 parser.add_option("--tmpdir", type="string",
289 help="run tests in the given temporary directory"
289 help="run tests in the given temporary directory"
290 " (implies --keep-tmpdir)")
290 " (implies --keep-tmpdir)")
291 parser.add_option("-v", "--verbose", action="store_true",
291 parser.add_option("-v", "--verbose", action="store_true",
292 help="output verbose messages")
292 help="output verbose messages")
293 parser.add_option("--xunit", type="string",
293 parser.add_option("--xunit", type="string",
294 help="record xunit results at specified path")
294 help="record xunit results at specified path")
295 parser.add_option("--view", type="string",
295 parser.add_option("--view", type="string",
296 help="external diff viewer")
296 help="external diff viewer")
297 parser.add_option("--with-hg", type="string",
297 parser.add_option("--with-hg", type="string",
298 metavar="HG",
298 metavar="HG",
299 help="test using specified hg script rather than a "
299 help="test using specified hg script rather than a "
300 "temporary installation")
300 "temporary installation")
301 parser.add_option("--chg", action="store_true",
301 parser.add_option("--chg", action="store_true",
302 help="install and use chg wrapper in place of hg")
302 help="install and use chg wrapper in place of hg")
303 parser.add_option("--with-chg", metavar="CHG",
303 parser.add_option("--with-chg", metavar="CHG",
304 help="use specified chg wrapper in place of hg")
304 help="use specified chg wrapper in place of hg")
305 parser.add_option("--ipv6", action="store_true",
305 parser.add_option("--ipv6", action="store_true",
306 help="prefer IPv6 to IPv4 for network related tests")
306 help="prefer IPv6 to IPv4 for network related tests")
307 parser.add_option("-3", "--py3k-warnings", action="store_true",
307 parser.add_option("-3", "--py3k-warnings", action="store_true",
308 help="enable Py3k warnings on Python 2.6+")
308 help="enable Py3k warnings on Python 2.6+")
309 # This option should be deleted once test-check-py3-compat.t and other
309 # This option should be deleted once test-check-py3-compat.t and other
310 # Python 3 tests run with Python 3.
310 # Python 3 tests run with Python 3.
311 parser.add_option("--with-python3", metavar="PYTHON3",
311 parser.add_option("--with-python3", metavar="PYTHON3",
312 help="Python 3 interpreter (if running under Python 2)"
312 help="Python 3 interpreter (if running under Python 2)"
313 " (TEMPORARY)")
313 " (TEMPORARY)")
314 parser.add_option('--extra-config-opt', action="append",
314 parser.add_option('--extra-config-opt', action="append",
315 help='set the given config opt in the test hgrc')
315 help='set the given config opt in the test hgrc')
316 parser.add_option('--random', action="store_true",
316 parser.add_option('--random', action="store_true",
317 help='run tests in random order')
317 help='run tests in random order')
318 parser.add_option('--profile-runner', action='store_true',
318 parser.add_option('--profile-runner', action='store_true',
319 help='run statprof on run-tests')
319 help='run statprof on run-tests')
320 parser.add_option('--allow-slow-tests', action='store_true',
320 parser.add_option('--allow-slow-tests', action='store_true',
321 help='allow extremely slow tests')
321 help='allow extremely slow tests')
322 parser.add_option('--showchannels', action='store_true',
322 parser.add_option('--showchannels', action='store_true',
323 help='show scheduling channels')
323 help='show scheduling channels')
324 parser.add_option('--known-good-rev', type="string",
324 parser.add_option('--known-good-rev', type="string",
325 metavar="known_good_rev",
325 metavar="known_good_rev",
326 help=("Automatically bisect any failures using this "
326 help=("Automatically bisect any failures using this "
327 "revision as a known-good revision."))
327 "revision as a known-good revision."))
328
328
329 for option, (envvar, default) in defaults.items():
329 for option, (envvar, default) in defaults.items():
330 defaults[option] = type(default)(os.environ.get(envvar, default))
330 defaults[option] = type(default)(os.environ.get(envvar, default))
331 parser.set_defaults(**defaults)
331 parser.set_defaults(**defaults)
332
332
333 return parser
333 return parser
334
334
335 def parseargs(args, parser):
335 def parseargs(args, parser):
336 """Parse arguments with our OptionParser and validate results."""
336 """Parse arguments with our OptionParser and validate results."""
337 (options, args) = parser.parse_args(args)
337 (options, args) = parser.parse_args(args)
338
338
339 # jython is always pure
339 # jython is always pure
340 if 'java' in sys.platform or '__pypy__' in sys.modules:
340 if 'java' in sys.platform or '__pypy__' in sys.modules:
341 options.pure = True
341 options.pure = True
342
342
343 if options.with_hg:
343 if options.with_hg:
344 options.with_hg = canonpath(_bytespath(options.with_hg))
344 options.with_hg = canonpath(_bytespath(options.with_hg))
345 if not (os.path.isfile(options.with_hg) and
345 if not (os.path.isfile(options.with_hg) and
346 os.access(options.with_hg, os.X_OK)):
346 os.access(options.with_hg, os.X_OK)):
347 parser.error('--with-hg must specify an executable hg script')
347 parser.error('--with-hg must specify an executable hg script')
348 if not os.path.basename(options.with_hg) == b'hg':
348 if not os.path.basename(options.with_hg) == b'hg':
349 sys.stderr.write('warning: --with-hg should specify an hg script\n')
349 sys.stderr.write('warning: --with-hg should specify an hg script\n')
350 if options.local:
350 if options.local:
351 testdir = os.path.dirname(_bytespath(canonpath(sys.argv[0])))
351 testdir = os.path.dirname(_bytespath(canonpath(sys.argv[0])))
352 reporootdir = os.path.dirname(testdir)
352 reporootdir = os.path.dirname(testdir)
353 pathandattrs = [(b'hg', 'with_hg')]
353 pathandattrs = [(b'hg', 'with_hg')]
354 if options.chg:
354 if options.chg:
355 pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
355 pathandattrs.append((b'contrib/chg/chg', 'with_chg'))
356 for relpath, attr in pathandattrs:
356 for relpath, attr in pathandattrs:
357 binpath = os.path.join(reporootdir, relpath)
357 binpath = os.path.join(reporootdir, relpath)
358 if os.name != 'nt' and not os.access(binpath, os.X_OK):
358 if os.name != 'nt' and not os.access(binpath, os.X_OK):
359 parser.error('--local specified, but %r not found or '
359 parser.error('--local specified, but %r not found or '
360 'not executable' % binpath)
360 'not executable' % binpath)
361 setattr(options, attr, binpath)
361 setattr(options, attr, binpath)
362
362
363 if (options.chg or options.with_chg) and os.name == 'nt':
363 if (options.chg or options.with_chg) and os.name == 'nt':
364 parser.error('chg does not work on %s' % os.name)
364 parser.error('chg does not work on %s' % os.name)
365 if options.with_chg:
365 if options.with_chg:
366 options.chg = False # no installation to temporary location
366 options.chg = False # no installation to temporary location
367 options.with_chg = canonpath(_bytespath(options.with_chg))
367 options.with_chg = canonpath(_bytespath(options.with_chg))
368 if not (os.path.isfile(options.with_chg) and
368 if not (os.path.isfile(options.with_chg) and
369 os.access(options.with_chg, os.X_OK)):
369 os.access(options.with_chg, os.X_OK)):
370 parser.error('--with-chg must specify a chg executable')
370 parser.error('--with-chg must specify a chg executable')
371 if options.chg and options.with_hg:
371 if options.chg and options.with_hg:
372 # chg shares installation location with hg
372 # chg shares installation location with hg
373 parser.error('--chg does not work when --with-hg is specified '
373 parser.error('--chg does not work when --with-hg is specified '
374 '(use --with-chg instead)')
374 '(use --with-chg instead)')
375
375
376 global useipv6
376 global useipv6
377 if options.ipv6:
377 if options.ipv6:
378 useipv6 = checksocketfamily('AF_INET6')
378 useipv6 = checksocketfamily('AF_INET6')
379 else:
379 else:
380 # only use IPv6 if IPv4 is unavailable and IPv6 is available
380 # only use IPv6 if IPv4 is unavailable and IPv6 is available
381 useipv6 = ((not checksocketfamily('AF_INET'))
381 useipv6 = ((not checksocketfamily('AF_INET'))
382 and checksocketfamily('AF_INET6'))
382 and checksocketfamily('AF_INET6'))
383
383
384 options.anycoverage = options.cover or options.annotate or options.htmlcov
384 options.anycoverage = options.cover or options.annotate or options.htmlcov
385 if options.anycoverage:
385 if options.anycoverage:
386 try:
386 try:
387 import coverage
387 import coverage
388 covver = version.StrictVersion(coverage.__version__).version
388 covver = version.StrictVersion(coverage.__version__).version
389 if covver < (3, 3):
389 if covver < (3, 3):
390 parser.error('coverage options require coverage 3.3 or later')
390 parser.error('coverage options require coverage 3.3 or later')
391 except ImportError:
391 except ImportError:
392 parser.error('coverage options now require the coverage package')
392 parser.error('coverage options now require the coverage package')
393
393
394 if options.anycoverage and options.local:
394 if options.anycoverage and options.local:
395 # this needs some path mangling somewhere, I guess
395 # this needs some path mangling somewhere, I guess
396 parser.error("sorry, coverage options do not work when --local "
396 parser.error("sorry, coverage options do not work when --local "
397 "is specified")
397 "is specified")
398
398
399 if options.anycoverage and options.with_hg:
399 if options.anycoverage and options.with_hg:
400 parser.error("sorry, coverage options do not work when --with-hg "
400 parser.error("sorry, coverage options do not work when --with-hg "
401 "is specified")
401 "is specified")
402
402
403 global verbose
403 global verbose
404 if options.verbose:
404 if options.verbose:
405 verbose = ''
405 verbose = ''
406
406
407 if options.tmpdir:
407 if options.tmpdir:
408 options.tmpdir = canonpath(options.tmpdir)
408 options.tmpdir = canonpath(options.tmpdir)
409
409
410 if options.jobs < 1:
410 if options.jobs < 1:
411 parser.error('--jobs must be positive')
411 parser.error('--jobs must be positive')
412 if options.interactive and options.debug:
412 if options.interactive and options.debug:
413 parser.error("-i/--interactive and -d/--debug are incompatible")
413 parser.error("-i/--interactive and -d/--debug are incompatible")
414 if options.debug:
414 if options.debug:
415 if options.timeout != defaults['timeout']:
415 if options.timeout != defaults['timeout']:
416 sys.stderr.write(
416 sys.stderr.write(
417 'warning: --timeout option ignored with --debug\n')
417 'warning: --timeout option ignored with --debug\n')
418 if options.slowtimeout != defaults['slowtimeout']:
418 if options.slowtimeout != defaults['slowtimeout']:
419 sys.stderr.write(
419 sys.stderr.write(
420 'warning: --slowtimeout option ignored with --debug\n')
420 'warning: --slowtimeout option ignored with --debug\n')
421 options.timeout = 0
421 options.timeout = 0
422 options.slowtimeout = 0
422 options.slowtimeout = 0
423 if options.py3k_warnings:
423 if options.py3k_warnings:
424 if PYTHON3:
424 if PYTHON3:
425 parser.error(
425 parser.error(
426 '--py3k-warnings can only be used on Python 2.6 and 2.7')
426 '--py3k-warnings can only be used on Python 2.6 and 2.7')
427 if options.with_python3:
427 if options.with_python3:
428 if PYTHON3:
428 if PYTHON3:
429 parser.error('--with-python3 cannot be used when executing with '
429 parser.error('--with-python3 cannot be used when executing with '
430 'Python 3')
430 'Python 3')
431
431
432 options.with_python3 = canonpath(options.with_python3)
432 options.with_python3 = canonpath(options.with_python3)
433 # Verify Python3 executable is acceptable.
433 # Verify Python3 executable is acceptable.
434 proc = subprocess.Popen([options.with_python3, b'--version'],
434 proc = subprocess.Popen([options.with_python3, b'--version'],
435 stdout=subprocess.PIPE,
435 stdout=subprocess.PIPE,
436 stderr=subprocess.STDOUT)
436 stderr=subprocess.STDOUT)
437 out, _err = proc.communicate()
437 out, _err = proc.communicate()
438 ret = proc.wait()
438 ret = proc.wait()
439 if ret != 0:
439 if ret != 0:
440 parser.error('could not determine version of python 3')
440 parser.error('could not determine version of python 3')
441 if not out.startswith('Python '):
441 if not out.startswith('Python '):
442 parser.error('unexpected output from python3 --version: %s' %
442 parser.error('unexpected output from python3 --version: %s' %
443 out)
443 out)
444 vers = version.LooseVersion(out[len('Python '):])
444 vers = version.LooseVersion(out[len('Python '):])
445 if vers < version.LooseVersion('3.5.0'):
445 if vers < version.LooseVersion('3.5.0'):
446 parser.error('--with-python3 version must be 3.5.0 or greater; '
446 parser.error('--with-python3 version must be 3.5.0 or greater; '
447 'got %s' % out)
447 'got %s' % out)
448
448
449 if options.blacklist:
449 if options.blacklist:
450 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
450 options.blacklist = parselistfiles(options.blacklist, 'blacklist')
451 if options.whitelist:
451 if options.whitelist:
452 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
452 options.whitelisted = parselistfiles(options.whitelist, 'whitelist')
453 else:
453 else:
454 options.whitelisted = {}
454 options.whitelisted = {}
455
455
456 if options.showchannels:
456 if options.showchannels:
457 options.nodiff = True
457 options.nodiff = True
458
458
459 return (options, args)
459 return (options, args)
460
460
461 def rename(src, dst):
461 def rename(src, dst):
462 """Like os.rename(), trade atomicity and opened files friendliness
462 """Like os.rename(), trade atomicity and opened files friendliness
463 for existing destination support.
463 for existing destination support.
464 """
464 """
465 shutil.copy(src, dst)
465 shutil.copy(src, dst)
466 os.remove(src)
466 os.remove(src)
467
467
468 _unified_diff = difflib.unified_diff
468 _unified_diff = difflib.unified_diff
469 if PYTHON3:
469 if PYTHON3:
470 import functools
470 import functools
471 _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
471 _unified_diff = functools.partial(difflib.diff_bytes, difflib.unified_diff)
472
472
473 def getdiff(expected, output, ref, err):
473 def getdiff(expected, output, ref, err):
474 servefail = False
474 servefail = False
475 lines = []
475 lines = []
476 for line in _unified_diff(expected, output, ref, err):
476 for line in _unified_diff(expected, output, ref, err):
477 if line.startswith(b'+++') or line.startswith(b'---'):
477 if line.startswith(b'+++') or line.startswith(b'---'):
478 line = line.replace(b'\\', b'/')
478 line = line.replace(b'\\', b'/')
479 if line.endswith(b' \n'):
479 if line.endswith(b' \n'):
480 line = line[:-2] + b'\n'
480 line = line[:-2] + b'\n'
481 lines.append(line)
481 lines.append(line)
482 if not servefail and line.startswith(
482 if not servefail and line.startswith(
483 b'+ abort: child process failed to start'):
483 b'+ abort: child process failed to start'):
484 servefail = True
484 servefail = True
485
485
486 return servefail, lines
486 return servefail, lines
487
487
488 verbose = False
488 verbose = False
489 def vlog(*msg):
489 def vlog(*msg):
490 """Log only when in verbose mode."""
490 """Log only when in verbose mode."""
491 if verbose is False:
491 if verbose is False:
492 return
492 return
493
493
494 return log(*msg)
494 return log(*msg)
495
495
496 # Bytes that break XML even in a CDATA block: control characters 0-31
496 # Bytes that break XML even in a CDATA block: control characters 0-31
497 # sans \t, \n and \r
497 # sans \t, \n and \r
498 CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
498 CDATA_EVIL = re.compile(br"[\000-\010\013\014\016-\037]")
499
499
500 def cdatasafe(data):
500 def cdatasafe(data):
501 """Make a string safe to include in a CDATA block.
501 """Make a string safe to include in a CDATA block.
502
502
503 Certain control characters are illegal in a CDATA block, and
503 Certain control characters are illegal in a CDATA block, and
504 there's no way to include a ]]> in a CDATA either. This function
504 there's no way to include a ]]> in a CDATA either. This function
505 replaces illegal bytes with ? and adds a space between the ]] so
505 replaces illegal bytes with ? and adds a space between the ]] so
506 that it won't break the CDATA block.
506 that it won't break the CDATA block.
507 """
507 """
508 return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
508 return CDATA_EVIL.sub(b'?', data).replace(b']]>', b'] ]>')
509
509
510 def log(*msg):
510 def log(*msg):
511 """Log something to stdout.
511 """Log something to stdout.
512
512
513 Arguments are strings to print.
513 Arguments are strings to print.
514 """
514 """
515 with iolock:
515 with iolock:
516 if verbose:
516 if verbose:
517 print(verbose, end=' ')
517 print(verbose, end=' ')
518 for m in msg:
518 for m in msg:
519 print(m, end=' ')
519 print(m, end=' ')
520 print()
520 print()
521 sys.stdout.flush()
521 sys.stdout.flush()
522
522
523 def terminate(proc):
523 def terminate(proc):
524 """Terminate subprocess (with fallback for Python versions < 2.6)"""
524 """Terminate subprocess (with fallback for Python versions < 2.6)"""
525 vlog('# Terminating process %d' % proc.pid)
525 vlog('# Terminating process %d' % proc.pid)
526 try:
526 try:
527 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
527 getattr(proc, 'terminate', lambda : os.kill(proc.pid, signal.SIGTERM))()
528 except OSError:
528 except OSError:
529 pass
529 pass
530
530
531 def killdaemons(pidfile):
531 def killdaemons(pidfile):
532 import killdaemons as killmod
532 import killdaemons as killmod
533 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
533 return killmod.killdaemons(pidfile, tryhard=False, remove=True,
534 logfn=vlog)
534 logfn=vlog)
535
535
536 class Test(unittest.TestCase):
536 class Test(unittest.TestCase):
537 """Encapsulates a single, runnable test.
537 """Encapsulates a single, runnable test.
538
538
539 While this class conforms to the unittest.TestCase API, it differs in that
539 While this class conforms to the unittest.TestCase API, it differs in that
540 instances need to be instantiated manually. (Typically, unittest.TestCase
540 instances need to be instantiated manually. (Typically, unittest.TestCase
541 classes are instantiated automatically by scanning modules.)
541 classes are instantiated automatically by scanning modules.)
542 """
542 """
543
543
544 # Status code reserved for skipped tests (used by hghave).
544 # Status code reserved for skipped tests (used by hghave).
545 SKIPPED_STATUS = 80
545 SKIPPED_STATUS = 80
546
546
547 def __init__(self, path, tmpdir, keeptmpdir=False,
547 def __init__(self, path, tmpdir, keeptmpdir=False,
548 debug=False,
548 debug=False,
549 timeout=defaults['timeout'],
549 timeout=defaults['timeout'],
550 startport=defaults['port'], extraconfigopts=None,
550 startport=defaults['port'], extraconfigopts=None,
551 py3kwarnings=False, shell=None, hgcommand=None,
551 py3kwarnings=False, shell=None, hgcommand=None,
552 slowtimeout=defaults['slowtimeout'], usechg=False,
552 slowtimeout=defaults['slowtimeout'], usechg=False,
553 useipv6=False):
553 useipv6=False):
554 """Create a test from parameters.
554 """Create a test from parameters.
555
555
556 path is the full path to the file defining the test.
556 path is the full path to the file defining the test.
557
557
558 tmpdir is the main temporary directory to use for this test.
558 tmpdir is the main temporary directory to use for this test.
559
559
560 keeptmpdir determines whether to keep the test's temporary directory
560 keeptmpdir determines whether to keep the test's temporary directory
561 after execution. It defaults to removal (False).
561 after execution. It defaults to removal (False).
562
562
563 debug mode will make the test execute verbosely, with unfiltered
563 debug mode will make the test execute verbosely, with unfiltered
564 output.
564 output.
565
565
566 timeout controls the maximum run time of the test. It is ignored when
566 timeout controls the maximum run time of the test. It is ignored when
567 debug is True. See slowtimeout for tests with #require slow.
567 debug is True. See slowtimeout for tests with #require slow.
568
568
569 slowtimeout overrides timeout if the test has #require slow.
569 slowtimeout overrides timeout if the test has #require slow.
570
570
571 startport controls the starting port number to use for this test. Each
571 startport controls the starting port number to use for this test. Each
572 test will reserve 3 port numbers for execution. It is the caller's
572 test will reserve 3 port numbers for execution. It is the caller's
573 responsibility to allocate a non-overlapping port range to Test
573 responsibility to allocate a non-overlapping port range to Test
574 instances.
574 instances.
575
575
576 extraconfigopts is an iterable of extra hgrc config options. Values
576 extraconfigopts is an iterable of extra hgrc config options. Values
577 must have the form "key=value" (something understood by hgrc). Values
577 must have the form "key=value" (something understood by hgrc). Values
578 of the form "foo.key=value" will result in "[foo] key=value".
578 of the form "foo.key=value" will result in "[foo] key=value".
579
579
580 py3kwarnings enables Py3k warnings.
580 py3kwarnings enables Py3k warnings.
581
581
582 shell is the shell to execute tests in.
582 shell is the shell to execute tests in.
583 """
583 """
584 self.path = path
584 self.path = path
585 self.bname = os.path.basename(path)
585 self.bname = os.path.basename(path)
586 self.name = _strpath(self.bname)
586 self.name = _strpath(self.bname)
587 self._testdir = os.path.dirname(path)
587 self._testdir = os.path.dirname(path)
588 self.errpath = os.path.join(self._testdir, b'%s.err' % self.bname)
588 self.errpath = os.path.join(self._testdir, b'%s.err' % self.bname)
589
589
590 self._threadtmp = tmpdir
590 self._threadtmp = tmpdir
591 self._keeptmpdir = keeptmpdir
591 self._keeptmpdir = keeptmpdir
592 self._debug = debug
592 self._debug = debug
593 self._timeout = timeout
593 self._timeout = timeout
594 self._slowtimeout = slowtimeout
594 self._slowtimeout = slowtimeout
595 self._startport = startport
595 self._startport = startport
596 self._extraconfigopts = extraconfigopts or []
596 self._extraconfigopts = extraconfigopts or []
597 self._py3kwarnings = py3kwarnings
597 self._py3kwarnings = py3kwarnings
598 self._shell = _bytespath(shell)
598 self._shell = _bytespath(shell)
599 self._hgcommand = hgcommand or b'hg'
599 self._hgcommand = hgcommand or b'hg'
600 self._usechg = usechg
600 self._usechg = usechg
601 self._useipv6 = useipv6
601 self._useipv6 = useipv6
602
602
603 self._aborted = False
603 self._aborted = False
604 self._daemonpids = []
604 self._daemonpids = []
605 self._finished = None
605 self._finished = None
606 self._ret = None
606 self._ret = None
607 self._out = None
607 self._out = None
608 self._skipped = None
608 self._skipped = None
609 self._testtmp = None
609 self._testtmp = None
610 self._chgsockdir = None
610 self._chgsockdir = None
611
611
612 # If we're not in --debug mode and reference output file exists,
612 # If we're not in --debug mode and reference output file exists,
613 # check test output against it.
613 # check test output against it.
614 if debug:
614 if debug:
615 self._refout = None # to match "out is None"
615 self._refout = None # to match "out is None"
616 elif os.path.exists(self.refpath):
616 elif os.path.exists(self.refpath):
617 f = open(self.refpath, 'rb')
617 f = open(self.refpath, 'rb')
618 self._refout = f.read().splitlines(True)
618 self._refout = f.read().splitlines(True)
619 f.close()
619 f.close()
620 else:
620 else:
621 self._refout = []
621 self._refout = []
622
622
623 # needed to get base class __repr__ running
623 # needed to get base class __repr__ running
624 @property
624 @property
625 def _testMethodName(self):
625 def _testMethodName(self):
626 return self.name
626 return self.name
627
627
628 def __str__(self):
628 def __str__(self):
629 return self.name
629 return self.name
630
630
631 def shortDescription(self):
631 def shortDescription(self):
632 return self.name
632 return self.name
633
633
634 def setUp(self):
634 def setUp(self):
635 """Tasks to perform before run()."""
635 """Tasks to perform before run()."""
636 self._finished = False
636 self._finished = False
637 self._ret = None
637 self._ret = None
638 self._out = None
638 self._out = None
639 self._skipped = None
639 self._skipped = None
640
640
641 try:
641 try:
642 os.mkdir(self._threadtmp)
642 os.mkdir(self._threadtmp)
643 except OSError as e:
643 except OSError as e:
644 if e.errno != errno.EEXIST:
644 if e.errno != errno.EEXIST:
645 raise
645 raise
646
646
647 name = os.path.basename(self.path)
647 name = os.path.basename(self.path)
648 self._testtmp = os.path.join(self._threadtmp, name)
648 self._testtmp = os.path.join(self._threadtmp, name)
649 os.mkdir(self._testtmp)
649 os.mkdir(self._testtmp)
650
650
651 # Remove any previous output files.
651 # Remove any previous output files.
652 if os.path.exists(self.errpath):
652 if os.path.exists(self.errpath):
653 try:
653 try:
654 os.remove(self.errpath)
654 os.remove(self.errpath)
655 except OSError as e:
655 except OSError as e:
656 # We might have raced another test to clean up a .err
656 # We might have raced another test to clean up a .err
657 # file, so ignore ENOENT when removing a previous .err
657 # file, so ignore ENOENT when removing a previous .err
658 # file.
658 # file.
659 if e.errno != errno.ENOENT:
659 if e.errno != errno.ENOENT:
660 raise
660 raise
661
661
662 if self._usechg:
662 if self._usechg:
663 self._chgsockdir = os.path.join(self._threadtmp,
663 self._chgsockdir = os.path.join(self._threadtmp,
664 b'%s.chgsock' % name)
664 b'%s.chgsock' % name)
665 os.mkdir(self._chgsockdir)
665 os.mkdir(self._chgsockdir)
666
666
667 def run(self, result):
667 def run(self, result):
668 """Run this test and report results against a TestResult instance."""
668 """Run this test and report results against a TestResult instance."""
669 # This function is extremely similar to unittest.TestCase.run(). Once
669 # This function is extremely similar to unittest.TestCase.run(). Once
670 # we require Python 2.7 (or at least its version of unittest), this
670 # we require Python 2.7 (or at least its version of unittest), this
671 # function can largely go away.
671 # function can largely go away.
672 self._result = result
672 self._result = result
673 result.startTest(self)
673 result.startTest(self)
674 try:
674 try:
675 try:
675 try:
676 self.setUp()
676 self.setUp()
677 except (KeyboardInterrupt, SystemExit):
677 except (KeyboardInterrupt, SystemExit):
678 self._aborted = True
678 self._aborted = True
679 raise
679 raise
680 except Exception:
680 except Exception:
681 result.addError(self, sys.exc_info())
681 result.addError(self, sys.exc_info())
682 return
682 return
683
683
684 success = False
684 success = False
685 try:
685 try:
686 self.runTest()
686 self.runTest()
687 except KeyboardInterrupt:
687 except KeyboardInterrupt:
688 self._aborted = True
688 self._aborted = True
689 raise
689 raise
690 except SkipTest as e:
690 except SkipTest as e:
691 result.addSkip(self, str(e))
691 result.addSkip(self, str(e))
692 # The base class will have already counted this as a
692 # The base class will have already counted this as a
693 # test we "ran", but we want to exclude skipped tests
693 # test we "ran", but we want to exclude skipped tests
694 # from those we count towards those run.
694 # from those we count towards those run.
695 result.testsRun -= 1
695 result.testsRun -= 1
696 except IgnoreTest as e:
696 except IgnoreTest as e:
697 result.addIgnore(self, str(e))
697 result.addIgnore(self, str(e))
698 # As with skips, ignores also should be excluded from
698 # As with skips, ignores also should be excluded from
699 # the number of tests executed.
699 # the number of tests executed.
700 result.testsRun -= 1
700 result.testsRun -= 1
701 except WarnTest as e:
701 except WarnTest as e:
702 result.addWarn(self, str(e))
702 result.addWarn(self, str(e))
703 except ReportedTest as e:
703 except ReportedTest as e:
704 pass
704 pass
705 except self.failureException as e:
705 except self.failureException as e:
706 # This differs from unittest in that we don't capture
706 # This differs from unittest in that we don't capture
707 # the stack trace. This is for historical reasons and
707 # the stack trace. This is for historical reasons and
708 # this decision could be revisited in the future,
708 # this decision could be revisited in the future,
709 # especially for PythonTest instances.
709 # especially for PythonTest instances.
710 if result.addFailure(self, str(e)):
710 if result.addFailure(self, str(e)):
711 success = True
711 success = True
712 except Exception:
712 except Exception:
713 result.addError(self, sys.exc_info())
713 result.addError(self, sys.exc_info())
714 else:
714 else:
715 success = True
715 success = True
716
716
717 try:
717 try:
718 self.tearDown()
718 self.tearDown()
719 except (KeyboardInterrupt, SystemExit):
719 except (KeyboardInterrupt, SystemExit):
720 self._aborted = True
720 self._aborted = True
721 raise
721 raise
722 except Exception:
722 except Exception:
723 result.addError(self, sys.exc_info())
723 result.addError(self, sys.exc_info())
724 success = False
724 success = False
725
725
726 if success:
726 if success:
727 result.addSuccess(self)
727 result.addSuccess(self)
728 finally:
728 finally:
729 result.stopTest(self, interrupted=self._aborted)
729 result.stopTest(self, interrupted=self._aborted)
730
730
731 def runTest(self):
731 def runTest(self):
732 """Run this test instance.
732 """Run this test instance.
733
733
734 This will return a tuple describing the result of the test.
734 This will return a tuple describing the result of the test.
735 """
735 """
736 env = self._getenv()
736 env = self._getenv()
737 self._daemonpids.append(env['DAEMON_PIDS'])
737 self._daemonpids.append(env['DAEMON_PIDS'])
738 self._createhgrc(env['HGRCPATH'])
738 self._createhgrc(env['HGRCPATH'])
739
739
740 vlog('# Test', self.name)
740 vlog('# Test', self.name)
741
741
742 ret, out = self._run(env)
742 ret, out = self._run(env)
743 self._finished = True
743 self._finished = True
744 self._ret = ret
744 self._ret = ret
745 self._out = out
745 self._out = out
746
746
747 def describe(ret):
747 def describe(ret):
748 if ret < 0:
748 if ret < 0:
749 return 'killed by signal: %d' % -ret
749 return 'killed by signal: %d' % -ret
750 return 'returned error code %d' % ret
750 return 'returned error code %d' % ret
751
751
752 self._skipped = False
752 self._skipped = False
753
753
754 if ret == self.SKIPPED_STATUS:
754 if ret == self.SKIPPED_STATUS:
755 if out is None: # Debug mode, nothing to parse.
755 if out is None: # Debug mode, nothing to parse.
756 missing = ['unknown']
756 missing = ['unknown']
757 failed = None
757 failed = None
758 else:
758 else:
759 missing, failed = TTest.parsehghaveoutput(out)
759 missing, failed = TTest.parsehghaveoutput(out)
760
760
761 if not missing:
761 if not missing:
762 missing = ['skipped']
762 missing = ['skipped']
763
763
764 if failed:
764 if failed:
765 self.fail('hg have failed checking for %s' % failed[-1])
765 self.fail('hg have failed checking for %s' % failed[-1])
766 else:
766 else:
767 self._skipped = True
767 self._skipped = True
768 raise SkipTest(missing[-1])
768 raise SkipTest(missing[-1])
769 elif ret == 'timeout':
769 elif ret == 'timeout':
770 self.fail('timed out')
770 self.fail('timed out')
771 elif ret is False:
771 elif ret is False:
772 raise WarnTest('no result code from test')
772 raise WarnTest('no result code from test')
773 elif out != self._refout:
773 elif out != self._refout:
774 # Diff generation may rely on written .err file.
774 # Diff generation may rely on written .err file.
775 if (ret != 0 or out != self._refout) and not self._skipped \
775 if (ret != 0 or out != self._refout) and not self._skipped \
776 and not self._debug:
776 and not self._debug:
777 f = open(self.errpath, 'wb')
777 f = open(self.errpath, 'wb')
778 for line in out:
778 for line in out:
779 f.write(line)
779 f.write(line)
780 f.close()
780 f.close()
781
781
782 # The result object handles diff calculation for us.
782 # The result object handles diff calculation for us.
783 if self._result.addOutputMismatch(self, ret, out, self._refout):
783 if self._result.addOutputMismatch(self, ret, out, self._refout):
784 # change was accepted, skip failing
784 # change was accepted, skip failing
785 return
785 return
786
786
787 if ret:
787 if ret:
788 msg = 'output changed and ' + describe(ret)
788 msg = 'output changed and ' + describe(ret)
789 else:
789 else:
790 msg = 'output changed'
790 msg = 'output changed'
791
791
792 self.fail(msg)
792 self.fail(msg)
793 elif ret:
793 elif ret:
794 self.fail(describe(ret))
794 self.fail(describe(ret))
795
795
796 def tearDown(self):
796 def tearDown(self):
797 """Tasks to perform after run()."""
797 """Tasks to perform after run()."""
798 for entry in self._daemonpids:
798 for entry in self._daemonpids:
799 killdaemons(entry)
799 killdaemons(entry)
800 self._daemonpids = []
800 self._daemonpids = []
801
801
802 if self._keeptmpdir:
802 if self._keeptmpdir:
803 log('\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s' %
803 log('\nKeeping testtmp dir: %s\nKeeping threadtmp dir: %s' %
804 (self._testtmp.decode('utf-8'),
804 (self._testtmp.decode('utf-8'),
805 self._threadtmp.decode('utf-8')))
805 self._threadtmp.decode('utf-8')))
806 else:
806 else:
807 shutil.rmtree(self._testtmp, True)
807 shutil.rmtree(self._testtmp, True)
808 shutil.rmtree(self._threadtmp, True)
808 shutil.rmtree(self._threadtmp, True)
809
809
810 if self._usechg:
810 if self._usechg:
811 # chgservers will stop automatically after they find the socket
811 # chgservers will stop automatically after they find the socket
812 # files are deleted
812 # files are deleted
813 shutil.rmtree(self._chgsockdir, True)
813 shutil.rmtree(self._chgsockdir, True)
814
814
815 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
815 if (self._ret != 0 or self._out != self._refout) and not self._skipped \
816 and not self._debug and self._out:
816 and not self._debug and self._out:
817 f = open(self.errpath, 'wb')
817 f = open(self.errpath, 'wb')
818 for line in self._out:
818 for line in self._out:
819 f.write(line)
819 f.write(line)
820 f.close()
820 f.close()
821
821
822 vlog("# Ret was:", self._ret, '(%s)' % self.name)
822 vlog("# Ret was:", self._ret, '(%s)' % self.name)
823
823
824 def _run(self, env):
824 def _run(self, env):
825 # This should be implemented in child classes to run tests.
825 # This should be implemented in child classes to run tests.
826 raise SkipTest('unknown test type')
826 raise SkipTest('unknown test type')
827
827
828 def abort(self):
828 def abort(self):
829 """Terminate execution of this test."""
829 """Terminate execution of this test."""
830 self._aborted = True
830 self._aborted = True
831
831
832 def _portmap(self, i):
832 def _portmap(self, i):
833 offset = b'' if i == 0 else b'%d' % i
833 offset = b'' if i == 0 else b'%d' % i
834 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
834 return (br':%d\b' % (self._startport + i), b':$HGPORT%s' % offset)
835
835
836 def _getreplacements(self):
836 def _getreplacements(self):
837 """Obtain a mapping of text replacements to apply to test output.
837 """Obtain a mapping of text replacements to apply to test output.
838
838
839 Test output needs to be normalized so it can be compared to expected
839 Test output needs to be normalized so it can be compared to expected
840 output. This function defines how some of that normalization will
840 output. This function defines how some of that normalization will
841 occur.
841 occur.
842 """
842 """
843 r = [
843 r = [
844 # This list should be parallel to defineport in _getenv
844 # This list should be parallel to defineport in _getenv
845 self._portmap(0),
845 self._portmap(0),
846 self._portmap(1),
846 self._portmap(1),
847 self._portmap(2),
847 self._portmap(2),
848 (br'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
848 (br'(?m)^(saved backup bundle to .*\.hg)( \(glob\))?$',
849 br'\1 (glob)'),
849 br'\1 (glob)'),
850 (br'([^0-9])%s' % re.escape(self._localip()), br'\1$LOCALIP'),
850 (br'([^0-9])%s' % re.escape(self._localip()), br'\1$LOCALIP'),
851 (br'\bHG_TXNID=TXN:[a-f0-9]{40}\b', br'HG_TXNID=TXN:$ID$'),
851 ]
852 ]
852 r.append((self._escapepath(self._testtmp), b'$TESTTMP'))
853 r.append((self._escapepath(self._testtmp), b'$TESTTMP'))
853
854
854 return r
855 return r
855
856
856 def _escapepath(self, p):
857 def _escapepath(self, p):
857 if os.name == 'nt':
858 if os.name == 'nt':
858 return (
859 return (
859 (b''.join(c.isalpha() and b'[%s%s]' % (c.lower(), c.upper()) or
860 (b''.join(c.isalpha() and b'[%s%s]' % (c.lower(), c.upper()) or
860 c in b'/\\' and br'[/\\]' or c.isdigit() and c or b'\\' + c
861 c in b'/\\' and br'[/\\]' or c.isdigit() and c or b'\\' + c
861 for c in p))
862 for c in p))
862 )
863 )
863 else:
864 else:
864 return re.escape(p)
865 return re.escape(p)
865
866
866 def _localip(self):
867 def _localip(self):
867 if self._useipv6:
868 if self._useipv6:
868 return b'::1'
869 return b'::1'
869 else:
870 else:
870 return b'127.0.0.1'
871 return b'127.0.0.1'
871
872
872 def _getenv(self):
873 def _getenv(self):
873 """Obtain environment variables to use during test execution."""
874 """Obtain environment variables to use during test execution."""
874 def defineport(i):
875 def defineport(i):
875 offset = '' if i == 0 else '%s' % i
876 offset = '' if i == 0 else '%s' % i
876 env["HGPORT%s" % offset] = '%s' % (self._startport + i)
877 env["HGPORT%s" % offset] = '%s' % (self._startport + i)
877 env = os.environ.copy()
878 env = os.environ.copy()
878 if sysconfig is not None:
879 if sysconfig is not None:
879 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase')
880 env['PYTHONUSERBASE'] = sysconfig.get_config_var('userbase')
880 env['TESTTMP'] = self._testtmp
881 env['TESTTMP'] = self._testtmp
881 env['HOME'] = self._testtmp
882 env['HOME'] = self._testtmp
882 # This number should match portneeded in _getport
883 # This number should match portneeded in _getport
883 for port in xrange(3):
884 for port in xrange(3):
884 # This list should be parallel to _portmap in _getreplacements
885 # This list should be parallel to _portmap in _getreplacements
885 defineport(port)
886 defineport(port)
886 env["HGRCPATH"] = os.path.join(self._threadtmp, b'.hgrc')
887 env["HGRCPATH"] = os.path.join(self._threadtmp, b'.hgrc')
887 env["DAEMON_PIDS"] = os.path.join(self._threadtmp, b'daemon.pids')
888 env["DAEMON_PIDS"] = os.path.join(self._threadtmp, b'daemon.pids')
888 env["HGEDITOR"] = ('"' + sys.executable + '"'
889 env["HGEDITOR"] = ('"' + sys.executable + '"'
889 + ' -c "import sys; sys.exit(0)"')
890 + ' -c "import sys; sys.exit(0)"')
890 env["HGMERGE"] = "internal:merge"
891 env["HGMERGE"] = "internal:merge"
891 env["HGUSER"] = "test"
892 env["HGUSER"] = "test"
892 env["HGENCODING"] = "ascii"
893 env["HGENCODING"] = "ascii"
893 env["HGENCODINGMODE"] = "strict"
894 env["HGENCODINGMODE"] = "strict"
894 env['HGIPV6'] = str(int(self._useipv6))
895 env['HGIPV6'] = str(int(self._useipv6))
895
896
896 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
897 # LOCALIP could be ::1 or 127.0.0.1. Useful for tests that require raw
897 # IP addresses.
898 # IP addresses.
898 env['LOCALIP'] = self._localip()
899 env['LOCALIP'] = self._localip()
899
900
900 # Reset some environment variables to well-known values so that
901 # Reset some environment variables to well-known values so that
901 # the tests produce repeatable output.
902 # the tests produce repeatable output.
902 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
903 env['LANG'] = env['LC_ALL'] = env['LANGUAGE'] = 'C'
903 env['TZ'] = 'GMT'
904 env['TZ'] = 'GMT'
904 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
905 env["EMAIL"] = "Foo Bar <foo.bar@example.com>"
905 env['COLUMNS'] = '80'
906 env['COLUMNS'] = '80'
906 env['TERM'] = 'xterm'
907 env['TERM'] = 'xterm'
907
908
908 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
909 for k in ('HG HGPROF CDPATH GREP_OPTIONS http_proxy no_proxy ' +
909 'HGPLAIN HGPLAINEXCEPT EDITOR VISUAL PAGER ' +
910 'HGPLAIN HGPLAINEXCEPT EDITOR VISUAL PAGER ' +
910 'NO_PROXY CHGDEBUG').split():
911 'NO_PROXY CHGDEBUG').split():
911 if k in env:
912 if k in env:
912 del env[k]
913 del env[k]
913
914
914 # unset env related to hooks
915 # unset env related to hooks
915 for k in env.keys():
916 for k in env.keys():
916 if k.startswith('HG_'):
917 if k.startswith('HG_'):
917 del env[k]
918 del env[k]
918
919
919 if self._usechg:
920 if self._usechg:
920 env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
921 env['CHGSOCKNAME'] = os.path.join(self._chgsockdir, b'server')
921
922
922 return env
923 return env
923
924
924 def _createhgrc(self, path):
925 def _createhgrc(self, path):
925 """Create an hgrc file for this test."""
926 """Create an hgrc file for this test."""
926 hgrc = open(path, 'wb')
927 hgrc = open(path, 'wb')
927 hgrc.write(b'[ui]\n')
928 hgrc.write(b'[ui]\n')
928 hgrc.write(b'slash = True\n')
929 hgrc.write(b'slash = True\n')
929 hgrc.write(b'interactive = False\n')
930 hgrc.write(b'interactive = False\n')
930 hgrc.write(b'mergemarkers = detailed\n')
931 hgrc.write(b'mergemarkers = detailed\n')
931 hgrc.write(b'promptecho = True\n')
932 hgrc.write(b'promptecho = True\n')
932 hgrc.write(b'[defaults]\n')
933 hgrc.write(b'[defaults]\n')
933 hgrc.write(b'backout = -d "0 0"\n')
934 hgrc.write(b'backout = -d "0 0"\n')
934 hgrc.write(b'commit = -d "0 0"\n')
935 hgrc.write(b'commit = -d "0 0"\n')
935 hgrc.write(b'shelve = --date "0 0"\n')
936 hgrc.write(b'shelve = --date "0 0"\n')
936 hgrc.write(b'tag = -d "0 0"\n')
937 hgrc.write(b'tag = -d "0 0"\n')
937 hgrc.write(b'[devel]\n')
938 hgrc.write(b'[devel]\n')
938 hgrc.write(b'all-warnings = true\n')
939 hgrc.write(b'all-warnings = true\n')
939 hgrc.write(b'[largefiles]\n')
940 hgrc.write(b'[largefiles]\n')
940 hgrc.write(b'usercache = %s\n' %
941 hgrc.write(b'usercache = %s\n' %
941 (os.path.join(self._testtmp, b'.cache/largefiles')))
942 (os.path.join(self._testtmp, b'.cache/largefiles')))
942 hgrc.write(b'[web]\n')
943 hgrc.write(b'[web]\n')
943 hgrc.write(b'address = localhost\n')
944 hgrc.write(b'address = localhost\n')
944 hgrc.write(b'ipv6 = %s\n' % str(self._useipv6).encode('ascii'))
945 hgrc.write(b'ipv6 = %s\n' % str(self._useipv6).encode('ascii'))
945
946
946 for opt in self._extraconfigopts:
947 for opt in self._extraconfigopts:
947 section, key = opt.split('.', 1)
948 section, key = opt.split('.', 1)
948 assert '=' in key, ('extra config opt %s must '
949 assert '=' in key, ('extra config opt %s must '
949 'have an = for assignment' % opt)
950 'have an = for assignment' % opt)
950 hgrc.write(b'[%s]\n%s\n' % (section, key))
951 hgrc.write(b'[%s]\n%s\n' % (section, key))
951 hgrc.close()
952 hgrc.close()
952
953
953 def fail(self, msg):
954 def fail(self, msg):
954 # unittest differentiates between errored and failed.
955 # unittest differentiates between errored and failed.
955 # Failed is denoted by AssertionError (by default at least).
956 # Failed is denoted by AssertionError (by default at least).
956 raise AssertionError(msg)
957 raise AssertionError(msg)
957
958
958 def _runcommand(self, cmd, env, normalizenewlines=False):
959 def _runcommand(self, cmd, env, normalizenewlines=False):
959 """Run command in a sub-process, capturing the output (stdout and
960 """Run command in a sub-process, capturing the output (stdout and
960 stderr).
961 stderr).
961
962
962 Return a tuple (exitcode, output). output is None in debug mode.
963 Return a tuple (exitcode, output). output is None in debug mode.
963 """
964 """
964 if self._debug:
965 if self._debug:
965 proc = subprocess.Popen(cmd, shell=True, cwd=self._testtmp,
966 proc = subprocess.Popen(cmd, shell=True, cwd=self._testtmp,
966 env=env)
967 env=env)
967 ret = proc.wait()
968 ret = proc.wait()
968 return (ret, None)
969 return (ret, None)
969
970
970 proc = Popen4(cmd, self._testtmp, self._timeout, env)
971 proc = Popen4(cmd, self._testtmp, self._timeout, env)
971 def cleanup():
972 def cleanup():
972 terminate(proc)
973 terminate(proc)
973 ret = proc.wait()
974 ret = proc.wait()
974 if ret == 0:
975 if ret == 0:
975 ret = signal.SIGTERM << 8
976 ret = signal.SIGTERM << 8
976 killdaemons(env['DAEMON_PIDS'])
977 killdaemons(env['DAEMON_PIDS'])
977 return ret
978 return ret
978
979
979 output = ''
980 output = ''
980 proc.tochild.close()
981 proc.tochild.close()
981
982
982 try:
983 try:
983 output = proc.fromchild.read()
984 output = proc.fromchild.read()
984 except KeyboardInterrupt:
985 except KeyboardInterrupt:
985 vlog('# Handling keyboard interrupt')
986 vlog('# Handling keyboard interrupt')
986 cleanup()
987 cleanup()
987 raise
988 raise
988
989
989 ret = proc.wait()
990 ret = proc.wait()
990 if wifexited(ret):
991 if wifexited(ret):
991 ret = os.WEXITSTATUS(ret)
992 ret = os.WEXITSTATUS(ret)
992
993
993 if proc.timeout:
994 if proc.timeout:
994 ret = 'timeout'
995 ret = 'timeout'
995
996
996 if ret:
997 if ret:
997 killdaemons(env['DAEMON_PIDS'])
998 killdaemons(env['DAEMON_PIDS'])
998
999
999 for s, r in self._getreplacements():
1000 for s, r in self._getreplacements():
1000 output = re.sub(s, r, output)
1001 output = re.sub(s, r, output)
1001
1002
1002 if normalizenewlines:
1003 if normalizenewlines:
1003 output = output.replace('\r\n', '\n')
1004 output = output.replace('\r\n', '\n')
1004
1005
1005 return ret, output.splitlines(True)
1006 return ret, output.splitlines(True)
1006
1007
1007 class PythonTest(Test):
1008 class PythonTest(Test):
1008 """A Python-based test."""
1009 """A Python-based test."""
1009
1010
1010 @property
1011 @property
1011 def refpath(self):
1012 def refpath(self):
1012 return os.path.join(self._testdir, b'%s.out' % self.bname)
1013 return os.path.join(self._testdir, b'%s.out' % self.bname)
1013
1014
1014 def _run(self, env):
1015 def _run(self, env):
1015 py3kswitch = self._py3kwarnings and b' -3' or b''
1016 py3kswitch = self._py3kwarnings and b' -3' or b''
1016 cmd = b'%s%s "%s"' % (PYTHON, py3kswitch, self.path)
1017 cmd = b'%s%s "%s"' % (PYTHON, py3kswitch, self.path)
1017 vlog("# Running", cmd)
1018 vlog("# Running", cmd)
1018 normalizenewlines = os.name == 'nt'
1019 normalizenewlines = os.name == 'nt'
1019 result = self._runcommand(cmd, env,
1020 result = self._runcommand(cmd, env,
1020 normalizenewlines=normalizenewlines)
1021 normalizenewlines=normalizenewlines)
1021 if self._aborted:
1022 if self._aborted:
1022 raise KeyboardInterrupt()
1023 raise KeyboardInterrupt()
1023
1024
1024 return result
1025 return result
1025
1026
1026 # Some glob patterns apply only in some circumstances, so the script
1027 # Some glob patterns apply only in some circumstances, so the script
1027 # might want to remove (glob) annotations that otherwise should be
1028 # might want to remove (glob) annotations that otherwise should be
1028 # retained.
1029 # retained.
1029 checkcodeglobpats = [
1030 checkcodeglobpats = [
1030 # On Windows it looks like \ doesn't require a (glob), but we know
1031 # On Windows it looks like \ doesn't require a (glob), but we know
1031 # better.
1032 # better.
1032 re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
1033 re.compile(br'^pushing to \$TESTTMP/.*[^)]$'),
1033 re.compile(br'^moving \S+/.*[^)]$'),
1034 re.compile(br'^moving \S+/.*[^)]$'),
1034 re.compile(br'^pulling from \$TESTTMP/.*[^)]$'),
1035 re.compile(br'^pulling from \$TESTTMP/.*[^)]$'),
1035 # Not all platforms have 127.0.0.1 as loopback (though most do),
1036 # Not all platforms have 127.0.0.1 as loopback (though most do),
1036 # so we always glob that too.
1037 # so we always glob that too.
1037 re.compile(br'.*\$LOCALIP.*$'),
1038 re.compile(br'.*\$LOCALIP.*$'),
1038 ]
1039 ]
1039
1040
1040 bchr = chr
1041 bchr = chr
1041 if PYTHON3:
1042 if PYTHON3:
1042 bchr = lambda x: bytes([x])
1043 bchr = lambda x: bytes([x])
1043
1044
1044 class TTest(Test):
1045 class TTest(Test):
1045 """A "t test" is a test backed by a .t file."""
1046 """A "t test" is a test backed by a .t file."""
1046
1047
1047 SKIPPED_PREFIX = b'skipped: '
1048 SKIPPED_PREFIX = b'skipped: '
1048 FAILED_PREFIX = b'hghave check failed: '
1049 FAILED_PREFIX = b'hghave check failed: '
1049 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
1050 NEEDESCAPE = re.compile(br'[\x00-\x08\x0b-\x1f\x7f-\xff]').search
1050
1051
1051 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
1052 ESCAPESUB = re.compile(br'[\x00-\x08\x0b-\x1f\\\x7f-\xff]').sub
1052 ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
1053 ESCAPEMAP = dict((bchr(i), br'\x%02x' % i) for i in range(256))
1053 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
1054 ESCAPEMAP.update({b'\\': b'\\\\', b'\r': br'\r'})
1054
1055
1055 @property
1056 @property
1056 def refpath(self):
1057 def refpath(self):
1057 return os.path.join(self._testdir, self.bname)
1058 return os.path.join(self._testdir, self.bname)
1058
1059
1059 def _run(self, env):
1060 def _run(self, env):
1060 f = open(self.path, 'rb')
1061 f = open(self.path, 'rb')
1061 lines = f.readlines()
1062 lines = f.readlines()
1062 f.close()
1063 f.close()
1063
1064
1064 salt, script, after, expected = self._parsetest(lines)
1065 salt, script, after, expected = self._parsetest(lines)
1065
1066
1066 # Write out the generated script.
1067 # Write out the generated script.
1067 fname = b'%s.sh' % self._testtmp
1068 fname = b'%s.sh' % self._testtmp
1068 f = open(fname, 'wb')
1069 f = open(fname, 'wb')
1069 for l in script:
1070 for l in script:
1070 f.write(l)
1071 f.write(l)
1071 f.close()
1072 f.close()
1072
1073
1073 cmd = b'%s "%s"' % (self._shell, fname)
1074 cmd = b'%s "%s"' % (self._shell, fname)
1074 vlog("# Running", cmd)
1075 vlog("# Running", cmd)
1075
1076
1076 exitcode, output = self._runcommand(cmd, env)
1077 exitcode, output = self._runcommand(cmd, env)
1077
1078
1078 if self._aborted:
1079 if self._aborted:
1079 raise KeyboardInterrupt()
1080 raise KeyboardInterrupt()
1080
1081
1081 # Do not merge output if skipped. Return hghave message instead.
1082 # Do not merge output if skipped. Return hghave message instead.
1082 # Similarly, with --debug, output is None.
1083 # Similarly, with --debug, output is None.
1083 if exitcode == self.SKIPPED_STATUS or output is None:
1084 if exitcode == self.SKIPPED_STATUS or output is None:
1084 return exitcode, output
1085 return exitcode, output
1085
1086
1086 return self._processoutput(exitcode, output, salt, after, expected)
1087 return self._processoutput(exitcode, output, salt, after, expected)
1087
1088
1088 def _hghave(self, reqs):
1089 def _hghave(self, reqs):
1089 # TODO do something smarter when all other uses of hghave are gone.
1090 # TODO do something smarter when all other uses of hghave are gone.
1090 runtestdir = os.path.abspath(os.path.dirname(_bytespath(__file__)))
1091 runtestdir = os.path.abspath(os.path.dirname(_bytespath(__file__)))
1091 tdir = runtestdir.replace(b'\\', b'/')
1092 tdir = runtestdir.replace(b'\\', b'/')
1092 proc = Popen4(b'%s -c "%s/hghave %s"' %
1093 proc = Popen4(b'%s -c "%s/hghave %s"' %
1093 (self._shell, tdir, b' '.join(reqs)),
1094 (self._shell, tdir, b' '.join(reqs)),
1094 self._testtmp, 0, self._getenv())
1095 self._testtmp, 0, self._getenv())
1095 stdout, stderr = proc.communicate()
1096 stdout, stderr = proc.communicate()
1096 ret = proc.wait()
1097 ret = proc.wait()
1097 if wifexited(ret):
1098 if wifexited(ret):
1098 ret = os.WEXITSTATUS(ret)
1099 ret = os.WEXITSTATUS(ret)
1099 if ret == 2:
1100 if ret == 2:
1100 print(stdout.decode('utf-8'))
1101 print(stdout.decode('utf-8'))
1101 sys.exit(1)
1102 sys.exit(1)
1102
1103
1103 if ret != 0:
1104 if ret != 0:
1104 return False, stdout
1105 return False, stdout
1105
1106
1106 if 'slow' in reqs:
1107 if 'slow' in reqs:
1107 self._timeout = self._slowtimeout
1108 self._timeout = self._slowtimeout
1108 return True, None
1109 return True, None
1109
1110
1110 def _parsetest(self, lines):
1111 def _parsetest(self, lines):
1111 # We generate a shell script which outputs unique markers to line
1112 # We generate a shell script which outputs unique markers to line
1112 # up script results with our source. These markers include input
1113 # up script results with our source. These markers include input
1113 # line number and the last return code.
1114 # line number and the last return code.
1114 salt = b"SALT%d" % time.time()
1115 salt = b"SALT%d" % time.time()
1115 def addsalt(line, inpython):
1116 def addsalt(line, inpython):
1116 if inpython:
1117 if inpython:
1117 script.append(b'%s %d 0\n' % (salt, line))
1118 script.append(b'%s %d 0\n' % (salt, line))
1118 else:
1119 else:
1119 script.append(b'echo %s %d $?\n' % (salt, line))
1120 script.append(b'echo %s %d $?\n' % (salt, line))
1120
1121
1121 script = []
1122 script = []
1122
1123
1123 # After we run the shell script, we re-unify the script output
1124 # After we run the shell script, we re-unify the script output
1124 # with non-active parts of the source, with synchronization by our
1125 # with non-active parts of the source, with synchronization by our
1125 # SALT line number markers. The after table contains the non-active
1126 # SALT line number markers. The after table contains the non-active
1126 # components, ordered by line number.
1127 # components, ordered by line number.
1127 after = {}
1128 after = {}
1128
1129
1129 # Expected shell script output.
1130 # Expected shell script output.
1130 expected = {}
1131 expected = {}
1131
1132
1132 pos = prepos = -1
1133 pos = prepos = -1
1133
1134
1134 # True or False when in a true or false conditional section
1135 # True or False when in a true or false conditional section
1135 skipping = None
1136 skipping = None
1136
1137
1137 # We keep track of whether or not we're in a Python block so we
1138 # We keep track of whether or not we're in a Python block so we
1138 # can generate the surrounding doctest magic.
1139 # can generate the surrounding doctest magic.
1139 inpython = False
1140 inpython = False
1140
1141
1141 if self._debug:
1142 if self._debug:
1142 script.append(b'set -x\n')
1143 script.append(b'set -x\n')
1143 if self._hgcommand != b'hg':
1144 if self._hgcommand != b'hg':
1144 script.append(b'alias hg="%s"\n' % self._hgcommand)
1145 script.append(b'alias hg="%s"\n' % self._hgcommand)
1145 if os.getenv('MSYSTEM'):
1146 if os.getenv('MSYSTEM'):
1146 script.append(b'alias pwd="pwd -W"\n')
1147 script.append(b'alias pwd="pwd -W"\n')
1147
1148
1148 n = 0
1149 n = 0
1149 for n, l in enumerate(lines):
1150 for n, l in enumerate(lines):
1150 if not l.endswith(b'\n'):
1151 if not l.endswith(b'\n'):
1151 l += b'\n'
1152 l += b'\n'
1152 if l.startswith(b'#require'):
1153 if l.startswith(b'#require'):
1153 lsplit = l.split()
1154 lsplit = l.split()
1154 if len(lsplit) < 2 or lsplit[0] != b'#require':
1155 if len(lsplit) < 2 or lsplit[0] != b'#require':
1155 after.setdefault(pos, []).append(' !!! invalid #require\n')
1156 after.setdefault(pos, []).append(' !!! invalid #require\n')
1156 haveresult, message = self._hghave(lsplit[1:])
1157 haveresult, message = self._hghave(lsplit[1:])
1157 if not haveresult:
1158 if not haveresult:
1158 script = [b'echo "%s"\nexit 80\n' % message]
1159 script = [b'echo "%s"\nexit 80\n' % message]
1159 break
1160 break
1160 after.setdefault(pos, []).append(l)
1161 after.setdefault(pos, []).append(l)
1161 elif l.startswith(b'#if'):
1162 elif l.startswith(b'#if'):
1162 lsplit = l.split()
1163 lsplit = l.split()
1163 if len(lsplit) < 2 or lsplit[0] != b'#if':
1164 if len(lsplit) < 2 or lsplit[0] != b'#if':
1164 after.setdefault(pos, []).append(' !!! invalid #if\n')
1165 after.setdefault(pos, []).append(' !!! invalid #if\n')
1165 if skipping is not None:
1166 if skipping is not None:
1166 after.setdefault(pos, []).append(' !!! nested #if\n')
1167 after.setdefault(pos, []).append(' !!! nested #if\n')
1167 skipping = not self._hghave(lsplit[1:])[0]
1168 skipping = not self._hghave(lsplit[1:])[0]
1168 after.setdefault(pos, []).append(l)
1169 after.setdefault(pos, []).append(l)
1169 elif l.startswith(b'#else'):
1170 elif l.startswith(b'#else'):
1170 if skipping is None:
1171 if skipping is None:
1171 after.setdefault(pos, []).append(' !!! missing #if\n')
1172 after.setdefault(pos, []).append(' !!! missing #if\n')
1172 skipping = not skipping
1173 skipping = not skipping
1173 after.setdefault(pos, []).append(l)
1174 after.setdefault(pos, []).append(l)
1174 elif l.startswith(b'#endif'):
1175 elif l.startswith(b'#endif'):
1175 if skipping is None:
1176 if skipping is None:
1176 after.setdefault(pos, []).append(' !!! missing #if\n')
1177 after.setdefault(pos, []).append(' !!! missing #if\n')
1177 skipping = None
1178 skipping = None
1178 after.setdefault(pos, []).append(l)
1179 after.setdefault(pos, []).append(l)
1179 elif skipping:
1180 elif skipping:
1180 after.setdefault(pos, []).append(l)
1181 after.setdefault(pos, []).append(l)
1181 elif l.startswith(b' >>> '): # python inlines
1182 elif l.startswith(b' >>> '): # python inlines
1182 after.setdefault(pos, []).append(l)
1183 after.setdefault(pos, []).append(l)
1183 prepos = pos
1184 prepos = pos
1184 pos = n
1185 pos = n
1185 if not inpython:
1186 if not inpython:
1186 # We've just entered a Python block. Add the header.
1187 # We've just entered a Python block. Add the header.
1187 inpython = True
1188 inpython = True
1188 addsalt(prepos, False) # Make sure we report the exit code.
1189 addsalt(prepos, False) # Make sure we report the exit code.
1189 script.append(b'%s -m heredoctest <<EOF\n' % PYTHON)
1190 script.append(b'%s -m heredoctest <<EOF\n' % PYTHON)
1190 addsalt(n, True)
1191 addsalt(n, True)
1191 script.append(l[2:])
1192 script.append(l[2:])
1192 elif l.startswith(b' ... '): # python inlines
1193 elif l.startswith(b' ... '): # python inlines
1193 after.setdefault(prepos, []).append(l)
1194 after.setdefault(prepos, []).append(l)
1194 script.append(l[2:])
1195 script.append(l[2:])
1195 elif l.startswith(b' $ '): # commands
1196 elif l.startswith(b' $ '): # commands
1196 if inpython:
1197 if inpython:
1197 script.append(b'EOF\n')
1198 script.append(b'EOF\n')
1198 inpython = False
1199 inpython = False
1199 after.setdefault(pos, []).append(l)
1200 after.setdefault(pos, []).append(l)
1200 prepos = pos
1201 prepos = pos
1201 pos = n
1202 pos = n
1202 addsalt(n, False)
1203 addsalt(n, False)
1203 cmd = l[4:].split()
1204 cmd = l[4:].split()
1204 if len(cmd) == 2 and cmd[0] == b'cd':
1205 if len(cmd) == 2 and cmd[0] == b'cd':
1205 l = b' $ cd %s || exit 1\n' % cmd[1]
1206 l = b' $ cd %s || exit 1\n' % cmd[1]
1206 script.append(l[4:])
1207 script.append(l[4:])
1207 elif l.startswith(b' > '): # continuations
1208 elif l.startswith(b' > '): # continuations
1208 after.setdefault(prepos, []).append(l)
1209 after.setdefault(prepos, []).append(l)
1209 script.append(l[4:])
1210 script.append(l[4:])
1210 elif l.startswith(b' '): # results
1211 elif l.startswith(b' '): # results
1211 # Queue up a list of expected results.
1212 # Queue up a list of expected results.
1212 expected.setdefault(pos, []).append(l[2:])
1213 expected.setdefault(pos, []).append(l[2:])
1213 else:
1214 else:
1214 if inpython:
1215 if inpython:
1215 script.append(b'EOF\n')
1216 script.append(b'EOF\n')
1216 inpython = False
1217 inpython = False
1217 # Non-command/result. Queue up for merged output.
1218 # Non-command/result. Queue up for merged output.
1218 after.setdefault(pos, []).append(l)
1219 after.setdefault(pos, []).append(l)
1219
1220
1220 if inpython:
1221 if inpython:
1221 script.append(b'EOF\n')
1222 script.append(b'EOF\n')
1222 if skipping is not None:
1223 if skipping is not None:
1223 after.setdefault(pos, []).append(' !!! missing #endif\n')
1224 after.setdefault(pos, []).append(' !!! missing #endif\n')
1224 addsalt(n + 1, False)
1225 addsalt(n + 1, False)
1225
1226
1226 return salt, script, after, expected
1227 return salt, script, after, expected
1227
1228
1228 def _processoutput(self, exitcode, output, salt, after, expected):
1229 def _processoutput(self, exitcode, output, salt, after, expected):
1229 # Merge the script output back into a unified test.
1230 # Merge the script output back into a unified test.
1230 warnonly = 1 # 1: not yet; 2: yes; 3: for sure not
1231 warnonly = 1 # 1: not yet; 2: yes; 3: for sure not
1231 if exitcode != 0:
1232 if exitcode != 0:
1232 warnonly = 3
1233 warnonly = 3
1233
1234
1234 pos = -1
1235 pos = -1
1235 postout = []
1236 postout = []
1236 for l in output:
1237 for l in output:
1237 lout, lcmd = l, None
1238 lout, lcmd = l, None
1238 if salt in l:
1239 if salt in l:
1239 lout, lcmd = l.split(salt, 1)
1240 lout, lcmd = l.split(salt, 1)
1240
1241
1241 while lout:
1242 while lout:
1242 if not lout.endswith(b'\n'):
1243 if not lout.endswith(b'\n'):
1243 lout += b' (no-eol)\n'
1244 lout += b' (no-eol)\n'
1244
1245
1245 # Find the expected output at the current position.
1246 # Find the expected output at the current position.
1246 els = [None]
1247 els = [None]
1247 if expected.get(pos, None):
1248 if expected.get(pos, None):
1248 els = expected[pos]
1249 els = expected[pos]
1249
1250
1250 i = 0
1251 i = 0
1251 optional = []
1252 optional = []
1252 while i < len(els):
1253 while i < len(els):
1253 el = els[i]
1254 el = els[i]
1254
1255
1255 r = TTest.linematch(el, lout)
1256 r = TTest.linematch(el, lout)
1256 if isinstance(r, str):
1257 if isinstance(r, str):
1257 if r == '+glob':
1258 if r == '+glob':
1258 lout = el[:-1] + ' (glob)\n'
1259 lout = el[:-1] + ' (glob)\n'
1259 r = '' # Warn only this line.
1260 r = '' # Warn only this line.
1260 elif r == '-glob':
1261 elif r == '-glob':
1261 lout = ''.join(el.rsplit(' (glob)', 1))
1262 lout = ''.join(el.rsplit(' (glob)', 1))
1262 r = '' # Warn only this line.
1263 r = '' # Warn only this line.
1263 elif r == "retry":
1264 elif r == "retry":
1264 postout.append(b' ' + el)
1265 postout.append(b' ' + el)
1265 els.pop(i)
1266 els.pop(i)
1266 break
1267 break
1267 else:
1268 else:
1268 log('\ninfo, unknown linematch result: %r\n' % r)
1269 log('\ninfo, unknown linematch result: %r\n' % r)
1269 r = False
1270 r = False
1270 if r:
1271 if r:
1271 els.pop(i)
1272 els.pop(i)
1272 break
1273 break
1273 if el and el.endswith(b" (?)\n"):
1274 if el and el.endswith(b" (?)\n"):
1274 optional.append(i)
1275 optional.append(i)
1275 i += 1
1276 i += 1
1276
1277
1277 if r:
1278 if r:
1278 if r == "retry":
1279 if r == "retry":
1279 continue
1280 continue
1280 # clean up any optional leftovers
1281 # clean up any optional leftovers
1281 for i in optional:
1282 for i in optional:
1282 postout.append(b' ' + els[i])
1283 postout.append(b' ' + els[i])
1283 for i in reversed(optional):
1284 for i in reversed(optional):
1284 del els[i]
1285 del els[i]
1285 postout.append(b' ' + el)
1286 postout.append(b' ' + el)
1286 else:
1287 else:
1287 if self.NEEDESCAPE(lout):
1288 if self.NEEDESCAPE(lout):
1288 lout = TTest._stringescape(b'%s (esc)\n' %
1289 lout = TTest._stringescape(b'%s (esc)\n' %
1289 lout.rstrip(b'\n'))
1290 lout.rstrip(b'\n'))
1290 postout.append(b' ' + lout) # Let diff deal with it.
1291 postout.append(b' ' + lout) # Let diff deal with it.
1291 if r != '': # If line failed.
1292 if r != '': # If line failed.
1292 warnonly = 3 # for sure not
1293 warnonly = 3 # for sure not
1293 elif warnonly == 1: # Is "not yet" and line is warn only.
1294 elif warnonly == 1: # Is "not yet" and line is warn only.
1294 warnonly = 2 # Yes do warn.
1295 warnonly = 2 # Yes do warn.
1295 break
1296 break
1296 else:
1297 else:
1297 # clean up any optional leftovers
1298 # clean up any optional leftovers
1298 while expected.get(pos, None):
1299 while expected.get(pos, None):
1299 el = expected[pos].pop(0)
1300 el = expected[pos].pop(0)
1300 if el and not el.endswith(b" (?)\n"):
1301 if el and not el.endswith(b" (?)\n"):
1301 break
1302 break
1302 postout.append(b' ' + el)
1303 postout.append(b' ' + el)
1303
1304
1304 if lcmd:
1305 if lcmd:
1305 # Add on last return code.
1306 # Add on last return code.
1306 ret = int(lcmd.split()[1])
1307 ret = int(lcmd.split()[1])
1307 if ret != 0:
1308 if ret != 0:
1308 postout.append(b' [%d]\n' % ret)
1309 postout.append(b' [%d]\n' % ret)
1309 if pos in after:
1310 if pos in after:
1310 # Merge in non-active test bits.
1311 # Merge in non-active test bits.
1311 postout += after.pop(pos)
1312 postout += after.pop(pos)
1312 pos = int(lcmd.split()[0])
1313 pos = int(lcmd.split()[0])
1313
1314
1314 if pos in after:
1315 if pos in after:
1315 postout += after.pop(pos)
1316 postout += after.pop(pos)
1316
1317
1317 if warnonly == 2:
1318 if warnonly == 2:
1318 exitcode = False # Set exitcode to warned.
1319 exitcode = False # Set exitcode to warned.
1319
1320
1320 return exitcode, postout
1321 return exitcode, postout
1321
1322
1322 @staticmethod
1323 @staticmethod
1323 def rematch(el, l):
1324 def rematch(el, l):
1324 try:
1325 try:
1325 # use \Z to ensure that the regex matches to the end of the string
1326 # use \Z to ensure that the regex matches to the end of the string
1326 if os.name == 'nt':
1327 if os.name == 'nt':
1327 return re.match(el + br'\r?\n\Z', l)
1328 return re.match(el + br'\r?\n\Z', l)
1328 return re.match(el + br'\n\Z', l)
1329 return re.match(el + br'\n\Z', l)
1329 except re.error:
1330 except re.error:
1330 # el is an invalid regex
1331 # el is an invalid regex
1331 return False
1332 return False
1332
1333
1333 @staticmethod
1334 @staticmethod
1334 def globmatch(el, l):
1335 def globmatch(el, l):
1335 # The only supported special characters are * and ? plus / which also
1336 # The only supported special characters are * and ? plus / which also
1336 # matches \ on windows. Escaping of these characters is supported.
1337 # matches \ on windows. Escaping of these characters is supported.
1337 if el + b'\n' == l:
1338 if el + b'\n' == l:
1338 if os.altsep:
1339 if os.altsep:
1339 # matching on "/" is not needed for this line
1340 # matching on "/" is not needed for this line
1340 for pat in checkcodeglobpats:
1341 for pat in checkcodeglobpats:
1341 if pat.match(el):
1342 if pat.match(el):
1342 return True
1343 return True
1343 return b'-glob'
1344 return b'-glob'
1344 return True
1345 return True
1345 el = el.replace(b'$LOCALIP', b'*')
1346 el = el.replace(b'$LOCALIP', b'*')
1346 i, n = 0, len(el)
1347 i, n = 0, len(el)
1347 res = b''
1348 res = b''
1348 while i < n:
1349 while i < n:
1349 c = el[i:i + 1]
1350 c = el[i:i + 1]
1350 i += 1
1351 i += 1
1351 if c == b'\\' and i < n and el[i:i + 1] in b'*?\\/':
1352 if c == b'\\' and i < n and el[i:i + 1] in b'*?\\/':
1352 res += el[i - 1:i + 1]
1353 res += el[i - 1:i + 1]
1353 i += 1
1354 i += 1
1354 elif c == b'*':
1355 elif c == b'*':
1355 res += b'.*'
1356 res += b'.*'
1356 elif c == b'?':
1357 elif c == b'?':
1357 res += b'.'
1358 res += b'.'
1358 elif c == b'/' and os.altsep:
1359 elif c == b'/' and os.altsep:
1359 res += b'[/\\\\]'
1360 res += b'[/\\\\]'
1360 else:
1361 else:
1361 res += re.escape(c)
1362 res += re.escape(c)
1362 return TTest.rematch(res, l)
1363 return TTest.rematch(res, l)
1363
1364
1364 @staticmethod
1365 @staticmethod
1365 def linematch(el, l):
1366 def linematch(el, l):
1366 retry = False
1367 retry = False
1367 if el == l: # perfect match (fast)
1368 if el == l: # perfect match (fast)
1368 return True
1369 return True
1369 if el:
1370 if el:
1370 if el.endswith(b" (?)\n"):
1371 if el.endswith(b" (?)\n"):
1371 retry = "retry"
1372 retry = "retry"
1372 el = el[:-5] + b"\n"
1373 el = el[:-5] + b"\n"
1373 if el.endswith(b" (esc)\n"):
1374 if el.endswith(b" (esc)\n"):
1374 if PYTHON3:
1375 if PYTHON3:
1375 el = el[:-7].decode('unicode_escape') + '\n'
1376 el = el[:-7].decode('unicode_escape') + '\n'
1376 el = el.encode('utf-8')
1377 el = el.encode('utf-8')
1377 else:
1378 else:
1378 el = el[:-7].decode('string-escape') + '\n'
1379 el = el[:-7].decode('string-escape') + '\n'
1379 if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
1380 if el == l or os.name == 'nt' and el[:-1] + b'\r\n' == l:
1380 return True
1381 return True
1381 if el.endswith(b" (re)\n"):
1382 if el.endswith(b" (re)\n"):
1382 return TTest.rematch(el[:-6], l) or retry
1383 return TTest.rematch(el[:-6], l) or retry
1383 if el.endswith(b" (glob)\n"):
1384 if el.endswith(b" (glob)\n"):
1384 # ignore '(glob)' added to l by 'replacements'
1385 # ignore '(glob)' added to l by 'replacements'
1385 if l.endswith(b" (glob)\n"):
1386 if l.endswith(b" (glob)\n"):
1386 l = l[:-8] + b"\n"
1387 l = l[:-8] + b"\n"
1387 return TTest.globmatch(el[:-8], l)
1388 return TTest.globmatch(el[:-8], l)
1388 if os.altsep and l.replace(b'\\', b'/') == el:
1389 if os.altsep and l.replace(b'\\', b'/') == el:
1389 return b'+glob'
1390 return b'+glob'
1390 return retry
1391 return retry
1391
1392
1392 @staticmethod
1393 @staticmethod
1393 def parsehghaveoutput(lines):
1394 def parsehghaveoutput(lines):
1394 '''Parse hghave log lines.
1395 '''Parse hghave log lines.
1395
1396
1396 Return tuple of lists (missing, failed):
1397 Return tuple of lists (missing, failed):
1397 * the missing/unknown features
1398 * the missing/unknown features
1398 * the features for which existence check failed'''
1399 * the features for which existence check failed'''
1399 missing = []
1400 missing = []
1400 failed = []
1401 failed = []
1401 for line in lines:
1402 for line in lines:
1402 if line.startswith(TTest.SKIPPED_PREFIX):
1403 if line.startswith(TTest.SKIPPED_PREFIX):
1403 line = line.splitlines()[0]
1404 line = line.splitlines()[0]
1404 missing.append(line[len(TTest.SKIPPED_PREFIX):].decode('utf-8'))
1405 missing.append(line[len(TTest.SKIPPED_PREFIX):].decode('utf-8'))
1405 elif line.startswith(TTest.FAILED_PREFIX):
1406 elif line.startswith(TTest.FAILED_PREFIX):
1406 line = line.splitlines()[0]
1407 line = line.splitlines()[0]
1407 failed.append(line[len(TTest.FAILED_PREFIX):].decode('utf-8'))
1408 failed.append(line[len(TTest.FAILED_PREFIX):].decode('utf-8'))
1408
1409
1409 return missing, failed
1410 return missing, failed
1410
1411
1411 @staticmethod
1412 @staticmethod
1412 def _escapef(m):
1413 def _escapef(m):
1413 return TTest.ESCAPEMAP[m.group(0)]
1414 return TTest.ESCAPEMAP[m.group(0)]
1414
1415
1415 @staticmethod
1416 @staticmethod
1416 def _stringescape(s):
1417 def _stringescape(s):
1417 return TTest.ESCAPESUB(TTest._escapef, s)
1418 return TTest.ESCAPESUB(TTest._escapef, s)
1418
1419
1419 iolock = threading.RLock()
1420 iolock = threading.RLock()
1420
1421
1421 class SkipTest(Exception):
1422 class SkipTest(Exception):
1422 """Raised to indicate that a test is to be skipped."""
1423 """Raised to indicate that a test is to be skipped."""
1423
1424
1424 class IgnoreTest(Exception):
1425 class IgnoreTest(Exception):
1425 """Raised to indicate that a test is to be ignored."""
1426 """Raised to indicate that a test is to be ignored."""
1426
1427
1427 class WarnTest(Exception):
1428 class WarnTest(Exception):
1428 """Raised to indicate that a test warned."""
1429 """Raised to indicate that a test warned."""
1429
1430
1430 class ReportedTest(Exception):
1431 class ReportedTest(Exception):
1431 """Raised to indicate that a test already reported."""
1432 """Raised to indicate that a test already reported."""
1432
1433
1433 class TestResult(unittest._TextTestResult):
1434 class TestResult(unittest._TextTestResult):
1434 """Holds results when executing via unittest."""
1435 """Holds results when executing via unittest."""
1435 # Don't worry too much about accessing the non-public _TextTestResult.
1436 # Don't worry too much about accessing the non-public _TextTestResult.
1436 # It is relatively common in Python testing tools.
1437 # It is relatively common in Python testing tools.
1437 def __init__(self, options, *args, **kwargs):
1438 def __init__(self, options, *args, **kwargs):
1438 super(TestResult, self).__init__(*args, **kwargs)
1439 super(TestResult, self).__init__(*args, **kwargs)
1439
1440
1440 self._options = options
1441 self._options = options
1441
1442
1442 # unittest.TestResult didn't have skipped until 2.7. We need to
1443 # unittest.TestResult didn't have skipped until 2.7. We need to
1443 # polyfill it.
1444 # polyfill it.
1444 self.skipped = []
1445 self.skipped = []
1445
1446
1446 # We have a custom "ignored" result that isn't present in any Python
1447 # We have a custom "ignored" result that isn't present in any Python
1447 # unittest implementation. It is very similar to skipped. It may make
1448 # unittest implementation. It is very similar to skipped. It may make
1448 # sense to map it into skip some day.
1449 # sense to map it into skip some day.
1449 self.ignored = []
1450 self.ignored = []
1450
1451
1451 # We have a custom "warned" result that isn't present in any Python
1452 # We have a custom "warned" result that isn't present in any Python
1452 # unittest implementation. It is very similar to failed. It may make
1453 # unittest implementation. It is very similar to failed. It may make
1453 # sense to map it into fail some day.
1454 # sense to map it into fail some day.
1454 self.warned = []
1455 self.warned = []
1455
1456
1456 self.times = []
1457 self.times = []
1457 self._firststarttime = None
1458 self._firststarttime = None
1458 # Data stored for the benefit of generating xunit reports.
1459 # Data stored for the benefit of generating xunit reports.
1459 self.successes = []
1460 self.successes = []
1460 self.faildata = {}
1461 self.faildata = {}
1461
1462
1462 def addFailure(self, test, reason):
1463 def addFailure(self, test, reason):
1463 self.failures.append((test, reason))
1464 self.failures.append((test, reason))
1464
1465
1465 if self._options.first:
1466 if self._options.first:
1466 self.stop()
1467 self.stop()
1467 else:
1468 else:
1468 with iolock:
1469 with iolock:
1469 if reason == "timed out":
1470 if reason == "timed out":
1470 self.stream.write('t')
1471 self.stream.write('t')
1471 else:
1472 else:
1472 if not self._options.nodiff:
1473 if not self._options.nodiff:
1473 self.stream.write('\nERROR: %s output changed\n' % test)
1474 self.stream.write('\nERROR: %s output changed\n' % test)
1474 self.stream.write('!')
1475 self.stream.write('!')
1475
1476
1476 self.stream.flush()
1477 self.stream.flush()
1477
1478
1478 def addSuccess(self, test):
1479 def addSuccess(self, test):
1479 with iolock:
1480 with iolock:
1480 super(TestResult, self).addSuccess(test)
1481 super(TestResult, self).addSuccess(test)
1481 self.successes.append(test)
1482 self.successes.append(test)
1482
1483
1483 def addError(self, test, err):
1484 def addError(self, test, err):
1484 super(TestResult, self).addError(test, err)
1485 super(TestResult, self).addError(test, err)
1485 if self._options.first:
1486 if self._options.first:
1486 self.stop()
1487 self.stop()
1487
1488
1488 # Polyfill.
1489 # Polyfill.
1489 def addSkip(self, test, reason):
1490 def addSkip(self, test, reason):
1490 self.skipped.append((test, reason))
1491 self.skipped.append((test, reason))
1491 with iolock:
1492 with iolock:
1492 if self.showAll:
1493 if self.showAll:
1493 self.stream.writeln('skipped %s' % reason)
1494 self.stream.writeln('skipped %s' % reason)
1494 else:
1495 else:
1495 self.stream.write('s')
1496 self.stream.write('s')
1496 self.stream.flush()
1497 self.stream.flush()
1497
1498
1498 def addIgnore(self, test, reason):
1499 def addIgnore(self, test, reason):
1499 self.ignored.append((test, reason))
1500 self.ignored.append((test, reason))
1500 with iolock:
1501 with iolock:
1501 if self.showAll:
1502 if self.showAll:
1502 self.stream.writeln('ignored %s' % reason)
1503 self.stream.writeln('ignored %s' % reason)
1503 else:
1504 else:
1504 if reason not in ('not retesting', "doesn't match keyword"):
1505 if reason not in ('not retesting', "doesn't match keyword"):
1505 self.stream.write('i')
1506 self.stream.write('i')
1506 else:
1507 else:
1507 self.testsRun += 1
1508 self.testsRun += 1
1508 self.stream.flush()
1509 self.stream.flush()
1509
1510
1510 def addWarn(self, test, reason):
1511 def addWarn(self, test, reason):
1511 self.warned.append((test, reason))
1512 self.warned.append((test, reason))
1512
1513
1513 if self._options.first:
1514 if self._options.first:
1514 self.stop()
1515 self.stop()
1515
1516
1516 with iolock:
1517 with iolock:
1517 if self.showAll:
1518 if self.showAll:
1518 self.stream.writeln('warned %s' % reason)
1519 self.stream.writeln('warned %s' % reason)
1519 else:
1520 else:
1520 self.stream.write('~')
1521 self.stream.write('~')
1521 self.stream.flush()
1522 self.stream.flush()
1522
1523
1523 def addOutputMismatch(self, test, ret, got, expected):
1524 def addOutputMismatch(self, test, ret, got, expected):
1524 """Record a mismatch in test output for a particular test."""
1525 """Record a mismatch in test output for a particular test."""
1525 if self.shouldStop:
1526 if self.shouldStop:
1526 # don't print, some other test case already failed and
1527 # don't print, some other test case already failed and
1527 # printed, we're just stale and probably failed due to our
1528 # printed, we're just stale and probably failed due to our
1528 # temp dir getting cleaned up.
1529 # temp dir getting cleaned up.
1529 return
1530 return
1530
1531
1531 accepted = False
1532 accepted = False
1532 lines = []
1533 lines = []
1533
1534
1534 with iolock:
1535 with iolock:
1535 if self._options.nodiff:
1536 if self._options.nodiff:
1536 pass
1537 pass
1537 elif self._options.view:
1538 elif self._options.view:
1538 v = self._options.view
1539 v = self._options.view
1539 if PYTHON3:
1540 if PYTHON3:
1540 v = _bytespath(v)
1541 v = _bytespath(v)
1541 os.system(b"%s %s %s" %
1542 os.system(b"%s %s %s" %
1542 (v, test.refpath, test.errpath))
1543 (v, test.refpath, test.errpath))
1543 else:
1544 else:
1544 servefail, lines = getdiff(expected, got,
1545 servefail, lines = getdiff(expected, got,
1545 test.refpath, test.errpath)
1546 test.refpath, test.errpath)
1546 if servefail:
1547 if servefail:
1547 self.addFailure(
1548 self.addFailure(
1548 test,
1549 test,
1549 'server failed to start (HGPORT=%s)' % test._startport)
1550 'server failed to start (HGPORT=%s)' % test._startport)
1550 raise ReportedTest('server failed to start')
1551 raise ReportedTest('server failed to start')
1551 else:
1552 else:
1552 self.stream.write('\n')
1553 self.stream.write('\n')
1553 for line in lines:
1554 for line in lines:
1554 if PYTHON3:
1555 if PYTHON3:
1555 self.stream.flush()
1556 self.stream.flush()
1556 self.stream.buffer.write(line)
1557 self.stream.buffer.write(line)
1557 self.stream.buffer.flush()
1558 self.stream.buffer.flush()
1558 else:
1559 else:
1559 self.stream.write(line)
1560 self.stream.write(line)
1560 self.stream.flush()
1561 self.stream.flush()
1561
1562
1562 # handle interactive prompt without releasing iolock
1563 # handle interactive prompt without releasing iolock
1563 if self._options.interactive:
1564 if self._options.interactive:
1564 self.stream.write('Accept this change? [n] ')
1565 self.stream.write('Accept this change? [n] ')
1565 answer = sys.stdin.readline().strip()
1566 answer = sys.stdin.readline().strip()
1566 if answer.lower() in ('y', 'yes'):
1567 if answer.lower() in ('y', 'yes'):
1567 if test.name.endswith('.t'):
1568 if test.name.endswith('.t'):
1568 rename(test.errpath, test.path)
1569 rename(test.errpath, test.path)
1569 else:
1570 else:
1570 rename(test.errpath, '%s.out' % test.path)
1571 rename(test.errpath, '%s.out' % test.path)
1571 accepted = True
1572 accepted = True
1572 if not accepted:
1573 if not accepted:
1573 self.faildata[test.name] = b''.join(lines)
1574 self.faildata[test.name] = b''.join(lines)
1574
1575
1575 return accepted
1576 return accepted
1576
1577
1577 def startTest(self, test):
1578 def startTest(self, test):
1578 super(TestResult, self).startTest(test)
1579 super(TestResult, self).startTest(test)
1579
1580
1580 # os.times module computes the user time and system time spent by
1581 # os.times module computes the user time and system time spent by
1581 # child's processes along with real elapsed time taken by a process.
1582 # child's processes along with real elapsed time taken by a process.
1582 # This module has one limitation. It can only work for Linux user
1583 # This module has one limitation. It can only work for Linux user
1583 # and not for Windows.
1584 # and not for Windows.
1584 test.started = os.times()
1585 test.started = os.times()
1585 if self._firststarttime is None: # thread racy but irrelevant
1586 if self._firststarttime is None: # thread racy but irrelevant
1586 self._firststarttime = test.started[4]
1587 self._firststarttime = test.started[4]
1587
1588
1588 def stopTest(self, test, interrupted=False):
1589 def stopTest(self, test, interrupted=False):
1589 super(TestResult, self).stopTest(test)
1590 super(TestResult, self).stopTest(test)
1590
1591
1591 test.stopped = os.times()
1592 test.stopped = os.times()
1592
1593
1593 starttime = test.started
1594 starttime = test.started
1594 endtime = test.stopped
1595 endtime = test.stopped
1595 origin = self._firststarttime
1596 origin = self._firststarttime
1596 self.times.append((test.name,
1597 self.times.append((test.name,
1597 endtime[2] - starttime[2], # user space CPU time
1598 endtime[2] - starttime[2], # user space CPU time
1598 endtime[3] - starttime[3], # sys space CPU time
1599 endtime[3] - starttime[3], # sys space CPU time
1599 endtime[4] - starttime[4], # real time
1600 endtime[4] - starttime[4], # real time
1600 starttime[4] - origin, # start date in run context
1601 starttime[4] - origin, # start date in run context
1601 endtime[4] - origin, # end date in run context
1602 endtime[4] - origin, # end date in run context
1602 ))
1603 ))
1603
1604
1604 if interrupted:
1605 if interrupted:
1605 with iolock:
1606 with iolock:
1606 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
1607 self.stream.writeln('INTERRUPTED: %s (after %d seconds)' % (
1607 test.name, self.times[-1][3]))
1608 test.name, self.times[-1][3]))
1608
1609
1609 class TestSuite(unittest.TestSuite):
1610 class TestSuite(unittest.TestSuite):
1610 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
1611 """Custom unittest TestSuite that knows how to execute Mercurial tests."""
1611
1612
1612 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
1613 def __init__(self, testdir, jobs=1, whitelist=None, blacklist=None,
1613 retest=False, keywords=None, loop=False, runs_per_test=1,
1614 retest=False, keywords=None, loop=False, runs_per_test=1,
1614 loadtest=None, showchannels=False,
1615 loadtest=None, showchannels=False,
1615 *args, **kwargs):
1616 *args, **kwargs):
1616 """Create a new instance that can run tests with a configuration.
1617 """Create a new instance that can run tests with a configuration.
1617
1618
1618 testdir specifies the directory where tests are executed from. This
1619 testdir specifies the directory where tests are executed from. This
1619 is typically the ``tests`` directory from Mercurial's source
1620 is typically the ``tests`` directory from Mercurial's source
1620 repository.
1621 repository.
1621
1622
1622 jobs specifies the number of jobs to run concurrently. Each test
1623 jobs specifies the number of jobs to run concurrently. Each test
1623 executes on its own thread. Tests actually spawn new processes, so
1624 executes on its own thread. Tests actually spawn new processes, so
1624 state mutation should not be an issue.
1625 state mutation should not be an issue.
1625
1626
1626 If there is only one job, it will use the main thread.
1627 If there is only one job, it will use the main thread.
1627
1628
1628 whitelist and blacklist denote tests that have been whitelisted and
1629 whitelist and blacklist denote tests that have been whitelisted and
1629 blacklisted, respectively. These arguments don't belong in TestSuite.
1630 blacklisted, respectively. These arguments don't belong in TestSuite.
1630 Instead, whitelist and blacklist should be handled by the thing that
1631 Instead, whitelist and blacklist should be handled by the thing that
1631 populates the TestSuite with tests. They are present to preserve
1632 populates the TestSuite with tests. They are present to preserve
1632 backwards compatible behavior which reports skipped tests as part
1633 backwards compatible behavior which reports skipped tests as part
1633 of the results.
1634 of the results.
1634
1635
1635 retest denotes whether to retest failed tests. This arguably belongs
1636 retest denotes whether to retest failed tests. This arguably belongs
1636 outside of TestSuite.
1637 outside of TestSuite.
1637
1638
1638 keywords denotes key words that will be used to filter which tests
1639 keywords denotes key words that will be used to filter which tests
1639 to execute. This arguably belongs outside of TestSuite.
1640 to execute. This arguably belongs outside of TestSuite.
1640
1641
1641 loop denotes whether to loop over tests forever.
1642 loop denotes whether to loop over tests forever.
1642 """
1643 """
1643 super(TestSuite, self).__init__(*args, **kwargs)
1644 super(TestSuite, self).__init__(*args, **kwargs)
1644
1645
1645 self._jobs = jobs
1646 self._jobs = jobs
1646 self._whitelist = whitelist
1647 self._whitelist = whitelist
1647 self._blacklist = blacklist
1648 self._blacklist = blacklist
1648 self._retest = retest
1649 self._retest = retest
1649 self._keywords = keywords
1650 self._keywords = keywords
1650 self._loop = loop
1651 self._loop = loop
1651 self._runs_per_test = runs_per_test
1652 self._runs_per_test = runs_per_test
1652 self._loadtest = loadtest
1653 self._loadtest = loadtest
1653 self._showchannels = showchannels
1654 self._showchannels = showchannels
1654
1655
1655 def run(self, result):
1656 def run(self, result):
1656 # We have a number of filters that need to be applied. We do this
1657 # We have a number of filters that need to be applied. We do this
1657 # here instead of inside Test because it makes the running logic for
1658 # here instead of inside Test because it makes the running logic for
1658 # Test simpler.
1659 # Test simpler.
1659 tests = []
1660 tests = []
1660 num_tests = [0]
1661 num_tests = [0]
1661 for test in self._tests:
1662 for test in self._tests:
1662 def get():
1663 def get():
1663 num_tests[0] += 1
1664 num_tests[0] += 1
1664 if getattr(test, 'should_reload', False):
1665 if getattr(test, 'should_reload', False):
1665 return self._loadtest(test.path, num_tests[0])
1666 return self._loadtest(test.path, num_tests[0])
1666 return test
1667 return test
1667 if not os.path.exists(test.path):
1668 if not os.path.exists(test.path):
1668 result.addSkip(test, "Doesn't exist")
1669 result.addSkip(test, "Doesn't exist")
1669 continue
1670 continue
1670
1671
1671 if not (self._whitelist and test.name in self._whitelist):
1672 if not (self._whitelist and test.name in self._whitelist):
1672 if self._blacklist and test.bname in self._blacklist:
1673 if self._blacklist and test.bname in self._blacklist:
1673 result.addSkip(test, 'blacklisted')
1674 result.addSkip(test, 'blacklisted')
1674 continue
1675 continue
1675
1676
1676 if self._retest and not os.path.exists(test.errpath):
1677 if self._retest and not os.path.exists(test.errpath):
1677 result.addIgnore(test, 'not retesting')
1678 result.addIgnore(test, 'not retesting')
1678 continue
1679 continue
1679
1680
1680 if self._keywords:
1681 if self._keywords:
1681 f = open(test.path, 'rb')
1682 f = open(test.path, 'rb')
1682 t = f.read().lower() + test.bname.lower()
1683 t = f.read().lower() + test.bname.lower()
1683 f.close()
1684 f.close()
1684 ignored = False
1685 ignored = False
1685 for k in self._keywords.lower().split():
1686 for k in self._keywords.lower().split():
1686 if k not in t:
1687 if k not in t:
1687 result.addIgnore(test, "doesn't match keyword")
1688 result.addIgnore(test, "doesn't match keyword")
1688 ignored = True
1689 ignored = True
1689 break
1690 break
1690
1691
1691 if ignored:
1692 if ignored:
1692 continue
1693 continue
1693 for _ in xrange(self._runs_per_test):
1694 for _ in xrange(self._runs_per_test):
1694 tests.append(get())
1695 tests.append(get())
1695
1696
1696 runtests = list(tests)
1697 runtests = list(tests)
1697 done = queue.Queue()
1698 done = queue.Queue()
1698 running = 0
1699 running = 0
1699
1700
1700 channels = [""] * self._jobs
1701 channels = [""] * self._jobs
1701
1702
1702 def job(test, result):
1703 def job(test, result):
1703 for n, v in enumerate(channels):
1704 for n, v in enumerate(channels):
1704 if not v:
1705 if not v:
1705 channel = n
1706 channel = n
1706 break
1707 break
1707 channels[channel] = "=" + test.name[5:].split(".")[0]
1708 channels[channel] = "=" + test.name[5:].split(".")[0]
1708 try:
1709 try:
1709 test(result)
1710 test(result)
1710 done.put(None)
1711 done.put(None)
1711 except KeyboardInterrupt:
1712 except KeyboardInterrupt:
1712 pass
1713 pass
1713 except: # re-raises
1714 except: # re-raises
1714 done.put(('!', test, 'run-test raised an error, see traceback'))
1715 done.put(('!', test, 'run-test raised an error, see traceback'))
1715 raise
1716 raise
1716 try:
1717 try:
1717 channels[channel] = ''
1718 channels[channel] = ''
1718 except IndexError:
1719 except IndexError:
1719 pass
1720 pass
1720
1721
1721 def stat():
1722 def stat():
1722 count = 0
1723 count = 0
1723 while channels:
1724 while channels:
1724 d = '\n%03s ' % count
1725 d = '\n%03s ' % count
1725 for n, v in enumerate(channels):
1726 for n, v in enumerate(channels):
1726 if v:
1727 if v:
1727 d += v[0]
1728 d += v[0]
1728 channels[n] = v[1:] or '.'
1729 channels[n] = v[1:] or '.'
1729 else:
1730 else:
1730 d += ' '
1731 d += ' '
1731 d += ' '
1732 d += ' '
1732 with iolock:
1733 with iolock:
1733 sys.stdout.write(d + ' ')
1734 sys.stdout.write(d + ' ')
1734 sys.stdout.flush()
1735 sys.stdout.flush()
1735 for x in xrange(10):
1736 for x in xrange(10):
1736 if channels:
1737 if channels:
1737 time.sleep(.1)
1738 time.sleep(.1)
1738 count += 1
1739 count += 1
1739
1740
1740 stoppedearly = False
1741 stoppedearly = False
1741
1742
1742 if self._showchannels:
1743 if self._showchannels:
1743 statthread = threading.Thread(target=stat, name="stat")
1744 statthread = threading.Thread(target=stat, name="stat")
1744 statthread.start()
1745 statthread.start()
1745
1746
1746 try:
1747 try:
1747 while tests or running:
1748 while tests or running:
1748 if not done.empty() or running == self._jobs or not tests:
1749 if not done.empty() or running == self._jobs or not tests:
1749 try:
1750 try:
1750 done.get(True, 1)
1751 done.get(True, 1)
1751 running -= 1
1752 running -= 1
1752 if result and result.shouldStop:
1753 if result and result.shouldStop:
1753 stoppedearly = True
1754 stoppedearly = True
1754 break
1755 break
1755 except queue.Empty:
1756 except queue.Empty:
1756 continue
1757 continue
1757 if tests and not running == self._jobs:
1758 if tests and not running == self._jobs:
1758 test = tests.pop(0)
1759 test = tests.pop(0)
1759 if self._loop:
1760 if self._loop:
1760 if getattr(test, 'should_reload', False):
1761 if getattr(test, 'should_reload', False):
1761 num_tests[0] += 1
1762 num_tests[0] += 1
1762 tests.append(
1763 tests.append(
1763 self._loadtest(test.name, num_tests[0]))
1764 self._loadtest(test.name, num_tests[0]))
1764 else:
1765 else:
1765 tests.append(test)
1766 tests.append(test)
1766 if self._jobs == 1:
1767 if self._jobs == 1:
1767 job(test, result)
1768 job(test, result)
1768 else:
1769 else:
1769 t = threading.Thread(target=job, name=test.name,
1770 t = threading.Thread(target=job, name=test.name,
1770 args=(test, result))
1771 args=(test, result))
1771 t.start()
1772 t.start()
1772 running += 1
1773 running += 1
1773
1774
1774 # If we stop early we still need to wait on started tests to
1775 # If we stop early we still need to wait on started tests to
1775 # finish. Otherwise, there is a race between the test completing
1776 # finish. Otherwise, there is a race between the test completing
1776 # and the test's cleanup code running. This could result in the
1777 # and the test's cleanup code running. This could result in the
1777 # test reporting incorrect.
1778 # test reporting incorrect.
1778 if stoppedearly:
1779 if stoppedearly:
1779 while running:
1780 while running:
1780 try:
1781 try:
1781 done.get(True, 1)
1782 done.get(True, 1)
1782 running -= 1
1783 running -= 1
1783 except queue.Empty:
1784 except queue.Empty:
1784 continue
1785 continue
1785 except KeyboardInterrupt:
1786 except KeyboardInterrupt:
1786 for test in runtests:
1787 for test in runtests:
1787 test.abort()
1788 test.abort()
1788
1789
1789 channels = []
1790 channels = []
1790
1791
1791 return result
1792 return result
1792
1793
1793 # Save the most recent 5 wall-clock runtimes of each test to a
1794 # Save the most recent 5 wall-clock runtimes of each test to a
1794 # human-readable text file named .testtimes. Tests are sorted
1795 # human-readable text file named .testtimes. Tests are sorted
1795 # alphabetically, while times for each test are listed from oldest to
1796 # alphabetically, while times for each test are listed from oldest to
1796 # newest.
1797 # newest.
1797
1798
1798 def loadtimes(testdir):
1799 def loadtimes(testdir):
1799 times = []
1800 times = []
1800 try:
1801 try:
1801 with open(os.path.join(testdir, b'.testtimes-')) as fp:
1802 with open(os.path.join(testdir, b'.testtimes-')) as fp:
1802 for line in fp:
1803 for line in fp:
1803 ts = line.split()
1804 ts = line.split()
1804 times.append((ts[0], [float(t) for t in ts[1:]]))
1805 times.append((ts[0], [float(t) for t in ts[1:]]))
1805 except IOError as err:
1806 except IOError as err:
1806 if err.errno != errno.ENOENT:
1807 if err.errno != errno.ENOENT:
1807 raise
1808 raise
1808 return times
1809 return times
1809
1810
1810 def savetimes(testdir, result):
1811 def savetimes(testdir, result):
1811 saved = dict(loadtimes(testdir))
1812 saved = dict(loadtimes(testdir))
1812 maxruns = 5
1813 maxruns = 5
1813 skipped = set([str(t[0]) for t in result.skipped])
1814 skipped = set([str(t[0]) for t in result.skipped])
1814 for tdata in result.times:
1815 for tdata in result.times:
1815 test, real = tdata[0], tdata[3]
1816 test, real = tdata[0], tdata[3]
1816 if test not in skipped:
1817 if test not in skipped:
1817 ts = saved.setdefault(test, [])
1818 ts = saved.setdefault(test, [])
1818 ts.append(real)
1819 ts.append(real)
1819 ts[:] = ts[-maxruns:]
1820 ts[:] = ts[-maxruns:]
1820
1821
1821 fd, tmpname = tempfile.mkstemp(prefix=b'.testtimes',
1822 fd, tmpname = tempfile.mkstemp(prefix=b'.testtimes',
1822 dir=testdir, text=True)
1823 dir=testdir, text=True)
1823 with os.fdopen(fd, 'w') as fp:
1824 with os.fdopen(fd, 'w') as fp:
1824 for name, ts in sorted(saved.items()):
1825 for name, ts in sorted(saved.items()):
1825 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
1826 fp.write('%s %s\n' % (name, ' '.join(['%.3f' % (t,) for t in ts])))
1826 timepath = os.path.join(testdir, b'.testtimes')
1827 timepath = os.path.join(testdir, b'.testtimes')
1827 try:
1828 try:
1828 os.unlink(timepath)
1829 os.unlink(timepath)
1829 except OSError:
1830 except OSError:
1830 pass
1831 pass
1831 try:
1832 try:
1832 os.rename(tmpname, timepath)
1833 os.rename(tmpname, timepath)
1833 except OSError:
1834 except OSError:
1834 pass
1835 pass
1835
1836
1836 class TextTestRunner(unittest.TextTestRunner):
1837 class TextTestRunner(unittest.TextTestRunner):
1837 """Custom unittest test runner that uses appropriate settings."""
1838 """Custom unittest test runner that uses appropriate settings."""
1838
1839
1839 def __init__(self, runner, *args, **kwargs):
1840 def __init__(self, runner, *args, **kwargs):
1840 super(TextTestRunner, self).__init__(*args, **kwargs)
1841 super(TextTestRunner, self).__init__(*args, **kwargs)
1841
1842
1842 self._runner = runner
1843 self._runner = runner
1843
1844
1844 def run(self, test):
1845 def run(self, test):
1845 result = TestResult(self._runner.options, self.stream,
1846 result = TestResult(self._runner.options, self.stream,
1846 self.descriptions, self.verbosity)
1847 self.descriptions, self.verbosity)
1847
1848
1848 test(result)
1849 test(result)
1849
1850
1850 failed = len(result.failures)
1851 failed = len(result.failures)
1851 warned = len(result.warned)
1852 warned = len(result.warned)
1852 skipped = len(result.skipped)
1853 skipped = len(result.skipped)
1853 ignored = len(result.ignored)
1854 ignored = len(result.ignored)
1854
1855
1855 with iolock:
1856 with iolock:
1856 self.stream.writeln('')
1857 self.stream.writeln('')
1857
1858
1858 if not self._runner.options.noskips:
1859 if not self._runner.options.noskips:
1859 for test, msg in result.skipped:
1860 for test, msg in result.skipped:
1860 self.stream.writeln('Skipped %s: %s' % (test.name, msg))
1861 self.stream.writeln('Skipped %s: %s' % (test.name, msg))
1861 for test, msg in result.warned:
1862 for test, msg in result.warned:
1862 self.stream.writeln('Warned %s: %s' % (test.name, msg))
1863 self.stream.writeln('Warned %s: %s' % (test.name, msg))
1863 for test, msg in result.failures:
1864 for test, msg in result.failures:
1864 self.stream.writeln('Failed %s: %s' % (test.name, msg))
1865 self.stream.writeln('Failed %s: %s' % (test.name, msg))
1865 for test, msg in result.errors:
1866 for test, msg in result.errors:
1866 self.stream.writeln('Errored %s: %s' % (test.name, msg))
1867 self.stream.writeln('Errored %s: %s' % (test.name, msg))
1867
1868
1868 if self._runner.options.xunit:
1869 if self._runner.options.xunit:
1869 with open(self._runner.options.xunit, 'wb') as xuf:
1870 with open(self._runner.options.xunit, 'wb') as xuf:
1870 timesd = dict((t[0], t[3]) for t in result.times)
1871 timesd = dict((t[0], t[3]) for t in result.times)
1871 doc = minidom.Document()
1872 doc = minidom.Document()
1872 s = doc.createElement('testsuite')
1873 s = doc.createElement('testsuite')
1873 s.setAttribute('name', 'run-tests')
1874 s.setAttribute('name', 'run-tests')
1874 s.setAttribute('tests', str(result.testsRun))
1875 s.setAttribute('tests', str(result.testsRun))
1875 s.setAttribute('errors', "0") # TODO
1876 s.setAttribute('errors', "0") # TODO
1876 s.setAttribute('failures', str(failed))
1877 s.setAttribute('failures', str(failed))
1877 s.setAttribute('skipped', str(skipped + ignored))
1878 s.setAttribute('skipped', str(skipped + ignored))
1878 doc.appendChild(s)
1879 doc.appendChild(s)
1879 for tc in result.successes:
1880 for tc in result.successes:
1880 t = doc.createElement('testcase')
1881 t = doc.createElement('testcase')
1881 t.setAttribute('name', tc.name)
1882 t.setAttribute('name', tc.name)
1882 t.setAttribute('time', '%.3f' % timesd[tc.name])
1883 t.setAttribute('time', '%.3f' % timesd[tc.name])
1883 s.appendChild(t)
1884 s.appendChild(t)
1884 for tc, err in sorted(result.faildata.items()):
1885 for tc, err in sorted(result.faildata.items()):
1885 t = doc.createElement('testcase')
1886 t = doc.createElement('testcase')
1886 t.setAttribute('name', tc)
1887 t.setAttribute('name', tc)
1887 t.setAttribute('time', '%.3f' % timesd[tc])
1888 t.setAttribute('time', '%.3f' % timesd[tc])
1888 # createCDATASection expects a unicode or it will
1889 # createCDATASection expects a unicode or it will
1889 # convert using default conversion rules, which will
1890 # convert using default conversion rules, which will
1890 # fail if string isn't ASCII.
1891 # fail if string isn't ASCII.
1891 err = cdatasafe(err).decode('utf-8', 'replace')
1892 err = cdatasafe(err).decode('utf-8', 'replace')
1892 cd = doc.createCDATASection(err)
1893 cd = doc.createCDATASection(err)
1893 t.appendChild(cd)
1894 t.appendChild(cd)
1894 s.appendChild(t)
1895 s.appendChild(t)
1895 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
1896 xuf.write(doc.toprettyxml(indent=' ', encoding='utf-8'))
1896
1897
1897 if self._runner.options.json:
1898 if self._runner.options.json:
1898 jsonpath = os.path.join(self._runner._testdir, b'report.json')
1899 jsonpath = os.path.join(self._runner._testdir, b'report.json')
1899 with open(jsonpath, 'w') as fp:
1900 with open(jsonpath, 'w') as fp:
1900 timesd = {}
1901 timesd = {}
1901 for tdata in result.times:
1902 for tdata in result.times:
1902 test = tdata[0]
1903 test = tdata[0]
1903 timesd[test] = tdata[1:]
1904 timesd[test] = tdata[1:]
1904
1905
1905 outcome = {}
1906 outcome = {}
1906 groups = [('success', ((tc, None)
1907 groups = [('success', ((tc, None)
1907 for tc in result.successes)),
1908 for tc in result.successes)),
1908 ('failure', result.failures),
1909 ('failure', result.failures),
1909 ('skip', result.skipped)]
1910 ('skip', result.skipped)]
1910 for res, testcases in groups:
1911 for res, testcases in groups:
1911 for tc, __ in testcases:
1912 for tc, __ in testcases:
1912 if tc.name in timesd:
1913 if tc.name in timesd:
1913 diff = result.faildata.get(tc.name, b'')
1914 diff = result.faildata.get(tc.name, b'')
1914 tres = {'result': res,
1915 tres = {'result': res,
1915 'time': ('%0.3f' % timesd[tc.name][2]),
1916 'time': ('%0.3f' % timesd[tc.name][2]),
1916 'cuser': ('%0.3f' % timesd[tc.name][0]),
1917 'cuser': ('%0.3f' % timesd[tc.name][0]),
1917 'csys': ('%0.3f' % timesd[tc.name][1]),
1918 'csys': ('%0.3f' % timesd[tc.name][1]),
1918 'start': ('%0.3f' % timesd[tc.name][3]),
1919 'start': ('%0.3f' % timesd[tc.name][3]),
1919 'end': ('%0.3f' % timesd[tc.name][4]),
1920 'end': ('%0.3f' % timesd[tc.name][4]),
1920 'diff': diff.decode('unicode_escape'),
1921 'diff': diff.decode('unicode_escape'),
1921 }
1922 }
1922 else:
1923 else:
1923 # blacklisted test
1924 # blacklisted test
1924 tres = {'result': res}
1925 tres = {'result': res}
1925
1926
1926 outcome[tc.name] = tres
1927 outcome[tc.name] = tres
1927 jsonout = json.dumps(outcome, sort_keys=True, indent=4,
1928 jsonout = json.dumps(outcome, sort_keys=True, indent=4,
1928 separators=(',', ': '))
1929 separators=(',', ': '))
1929 fp.writelines(("testreport =", jsonout))
1930 fp.writelines(("testreport =", jsonout))
1930
1931
1931 self._runner._checkhglib('Tested')
1932 self._runner._checkhglib('Tested')
1932
1933
1933 savetimes(self._runner._testdir, result)
1934 savetimes(self._runner._testdir, result)
1934
1935
1935 if failed and self._runner.options.known_good_rev:
1936 if failed and self._runner.options.known_good_rev:
1936 def nooutput(args):
1937 def nooutput(args):
1937 p = subprocess.Popen(args, stderr=subprocess.STDOUT,
1938 p = subprocess.Popen(args, stderr=subprocess.STDOUT,
1938 stdout=subprocess.PIPE)
1939 stdout=subprocess.PIPE)
1939 p.stdout.read()
1940 p.stdout.read()
1940 p.wait()
1941 p.wait()
1941 for test, msg in result.failures:
1942 for test, msg in result.failures:
1942 nooutput(['hg', 'bisect', '--reset']),
1943 nooutput(['hg', 'bisect', '--reset']),
1943 nooutput(['hg', 'bisect', '--bad', '.'])
1944 nooutput(['hg', 'bisect', '--bad', '.'])
1944 nooutput(['hg', 'bisect', '--good',
1945 nooutput(['hg', 'bisect', '--good',
1945 self._runner.options.known_good_rev])
1946 self._runner.options.known_good_rev])
1946 # TODO: we probably need to forward some options
1947 # TODO: we probably need to forward some options
1947 # that alter hg's behavior inside the tests.
1948 # that alter hg's behavior inside the tests.
1948 rtc = '%s %s %s' % (sys.executable, sys.argv[0], test)
1949 rtc = '%s %s %s' % (sys.executable, sys.argv[0], test)
1949 sub = subprocess.Popen(['hg', 'bisect', '--command', rtc],
1950 sub = subprocess.Popen(['hg', 'bisect', '--command', rtc],
1950 stderr=subprocess.STDOUT,
1951 stderr=subprocess.STDOUT,
1951 stdout=subprocess.PIPE)
1952 stdout=subprocess.PIPE)
1952 data = sub.stdout.read()
1953 data = sub.stdout.read()
1953 sub.wait()
1954 sub.wait()
1954 m = re.search(
1955 m = re.search(
1955 (r'\nThe first (?P<goodbad>bad|good) revision '
1956 (r'\nThe first (?P<goodbad>bad|good) revision '
1956 r'is:\nchangeset: +\d+:(?P<node>[a-f0-9]+)\n.*\n'
1957 r'is:\nchangeset: +\d+:(?P<node>[a-f0-9]+)\n.*\n'
1957 r'summary: +(?P<summary>[^\n]+)\n'),
1958 r'summary: +(?P<summary>[^\n]+)\n'),
1958 data, (re.MULTILINE | re.DOTALL))
1959 data, (re.MULTILINE | re.DOTALL))
1959 if m is None:
1960 if m is None:
1960 self.stream.writeln(
1961 self.stream.writeln(
1961 'Failed to identify failure point for %s' % test)
1962 'Failed to identify failure point for %s' % test)
1962 continue
1963 continue
1963 dat = m.groupdict()
1964 dat = m.groupdict()
1964 verb = 'broken' if dat['goodbad'] == 'bad' else 'fixed'
1965 verb = 'broken' if dat['goodbad'] == 'bad' else 'fixed'
1965 self.stream.writeln(
1966 self.stream.writeln(
1966 '%s %s by %s (%s)' % (
1967 '%s %s by %s (%s)' % (
1967 test, verb, dat['node'], dat['summary']))
1968 test, verb, dat['node'], dat['summary']))
1968 self.stream.writeln(
1969 self.stream.writeln(
1969 '# Ran %d tests, %d skipped, %d warned, %d failed.'
1970 '# Ran %d tests, %d skipped, %d warned, %d failed.'
1970 % (result.testsRun,
1971 % (result.testsRun,
1971 skipped + ignored, warned, failed))
1972 skipped + ignored, warned, failed))
1972 if failed:
1973 if failed:
1973 self.stream.writeln('python hash seed: %s' %
1974 self.stream.writeln('python hash seed: %s' %
1974 os.environ['PYTHONHASHSEED'])
1975 os.environ['PYTHONHASHSEED'])
1975 if self._runner.options.time:
1976 if self._runner.options.time:
1976 self.printtimes(result.times)
1977 self.printtimes(result.times)
1977
1978
1978 return result
1979 return result
1979
1980
1980 def printtimes(self, times):
1981 def printtimes(self, times):
1981 # iolock held by run
1982 # iolock held by run
1982 self.stream.writeln('# Producing time report')
1983 self.stream.writeln('# Producing time report')
1983 times.sort(key=lambda t: (t[3]))
1984 times.sort(key=lambda t: (t[3]))
1984 cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
1985 cols = '%7.3f %7.3f %7.3f %7.3f %7.3f %s'
1985 self.stream.writeln('%-7s %-7s %-7s %-7s %-7s %s' %
1986 self.stream.writeln('%-7s %-7s %-7s %-7s %-7s %s' %
1986 ('start', 'end', 'cuser', 'csys', 'real', 'Test'))
1987 ('start', 'end', 'cuser', 'csys', 'real', 'Test'))
1987 for tdata in times:
1988 for tdata in times:
1988 test = tdata[0]
1989 test = tdata[0]
1989 cuser, csys, real, start, end = tdata[1:6]
1990 cuser, csys, real, start, end = tdata[1:6]
1990 self.stream.writeln(cols % (start, end, cuser, csys, real, test))
1991 self.stream.writeln(cols % (start, end, cuser, csys, real, test))
1991
1992
1992 class TestRunner(object):
1993 class TestRunner(object):
1993 """Holds context for executing tests.
1994 """Holds context for executing tests.
1994
1995
1995 Tests rely on a lot of state. This object holds it for them.
1996 Tests rely on a lot of state. This object holds it for them.
1996 """
1997 """
1997
1998
1998 # Programs required to run tests.
1999 # Programs required to run tests.
1999 REQUIREDTOOLS = [
2000 REQUIREDTOOLS = [
2000 os.path.basename(_bytespath(sys.executable)),
2001 os.path.basename(_bytespath(sys.executable)),
2001 b'diff',
2002 b'diff',
2002 b'grep',
2003 b'grep',
2003 b'unzip',
2004 b'unzip',
2004 b'gunzip',
2005 b'gunzip',
2005 b'bunzip2',
2006 b'bunzip2',
2006 b'sed',
2007 b'sed',
2007 ]
2008 ]
2008
2009
2009 # Maps file extensions to test class.
2010 # Maps file extensions to test class.
2010 TESTTYPES = [
2011 TESTTYPES = [
2011 (b'.py', PythonTest),
2012 (b'.py', PythonTest),
2012 (b'.t', TTest),
2013 (b'.t', TTest),
2013 ]
2014 ]
2014
2015
2015 def __init__(self):
2016 def __init__(self):
2016 self.options = None
2017 self.options = None
2017 self._hgroot = None
2018 self._hgroot = None
2018 self._testdir = None
2019 self._testdir = None
2019 self._hgtmp = None
2020 self._hgtmp = None
2020 self._installdir = None
2021 self._installdir = None
2021 self._bindir = None
2022 self._bindir = None
2022 self._tmpbinddir = None
2023 self._tmpbinddir = None
2023 self._pythondir = None
2024 self._pythondir = None
2024 self._coveragefile = None
2025 self._coveragefile = None
2025 self._createdfiles = []
2026 self._createdfiles = []
2026 self._hgcommand = None
2027 self._hgcommand = None
2027 self._hgpath = None
2028 self._hgpath = None
2028 self._portoffset = 0
2029 self._portoffset = 0
2029 self._ports = {}
2030 self._ports = {}
2030
2031
2031 def run(self, args, parser=None):
2032 def run(self, args, parser=None):
2032 """Run the test suite."""
2033 """Run the test suite."""
2033 oldmask = os.umask(0o22)
2034 oldmask = os.umask(0o22)
2034 try:
2035 try:
2035 parser = parser or getparser()
2036 parser = parser or getparser()
2036 options, args = parseargs(args, parser)
2037 options, args = parseargs(args, parser)
2037 # positional arguments are paths to test files to run, so
2038 # positional arguments are paths to test files to run, so
2038 # we make sure they're all bytestrings
2039 # we make sure they're all bytestrings
2039 args = [_bytespath(a) for a in args]
2040 args = [_bytespath(a) for a in args]
2040 self.options = options
2041 self.options = options
2041
2042
2042 self._checktools()
2043 self._checktools()
2043 tests = self.findtests(args)
2044 tests = self.findtests(args)
2044 if options.profile_runner:
2045 if options.profile_runner:
2045 import statprof
2046 import statprof
2046 statprof.start()
2047 statprof.start()
2047 result = self._run(tests)
2048 result = self._run(tests)
2048 if options.profile_runner:
2049 if options.profile_runner:
2049 statprof.stop()
2050 statprof.stop()
2050 statprof.display()
2051 statprof.display()
2051 return result
2052 return result
2052
2053
2053 finally:
2054 finally:
2054 os.umask(oldmask)
2055 os.umask(oldmask)
2055
2056
2056 def _run(self, tests):
2057 def _run(self, tests):
2057 if self.options.random:
2058 if self.options.random:
2058 random.shuffle(tests)
2059 random.shuffle(tests)
2059 else:
2060 else:
2060 # keywords for slow tests
2061 # keywords for slow tests
2061 slow = {b'svn': 10,
2062 slow = {b'svn': 10,
2062 b'cvs': 10,
2063 b'cvs': 10,
2063 b'hghave': 10,
2064 b'hghave': 10,
2064 b'largefiles-update': 10,
2065 b'largefiles-update': 10,
2065 b'run-tests': 10,
2066 b'run-tests': 10,
2066 b'corruption': 10,
2067 b'corruption': 10,
2067 b'race': 10,
2068 b'race': 10,
2068 b'i18n': 10,
2069 b'i18n': 10,
2069 b'check': 100,
2070 b'check': 100,
2070 b'gendoc': 100,
2071 b'gendoc': 100,
2071 b'contrib-perf': 200,
2072 b'contrib-perf': 200,
2072 }
2073 }
2073 perf = {}
2074 perf = {}
2074 def sortkey(f):
2075 def sortkey(f):
2075 # run largest tests first, as they tend to take the longest
2076 # run largest tests first, as they tend to take the longest
2076 try:
2077 try:
2077 return perf[f]
2078 return perf[f]
2078 except KeyError:
2079 except KeyError:
2079 try:
2080 try:
2080 val = -os.stat(f).st_size
2081 val = -os.stat(f).st_size
2081 except OSError as e:
2082 except OSError as e:
2082 if e.errno != errno.ENOENT:
2083 if e.errno != errno.ENOENT:
2083 raise
2084 raise
2084 perf[f] = -1e9 # file does not exist, tell early
2085 perf[f] = -1e9 # file does not exist, tell early
2085 return -1e9
2086 return -1e9
2086 for kw, mul in slow.items():
2087 for kw, mul in slow.items():
2087 if kw in f:
2088 if kw in f:
2088 val *= mul
2089 val *= mul
2089 if f.endswith(b'.py'):
2090 if f.endswith(b'.py'):
2090 val /= 10.0
2091 val /= 10.0
2091 perf[f] = val / 1000.0
2092 perf[f] = val / 1000.0
2092 return perf[f]
2093 return perf[f]
2093 tests.sort(key=sortkey)
2094 tests.sort(key=sortkey)
2094
2095
2095 self._testdir = osenvironb[b'TESTDIR'] = getattr(
2096 self._testdir = osenvironb[b'TESTDIR'] = getattr(
2096 os, 'getcwdb', os.getcwd)()
2097 os, 'getcwdb', os.getcwd)()
2097
2098
2098 if 'PYTHONHASHSEED' not in os.environ:
2099 if 'PYTHONHASHSEED' not in os.environ:
2099 # use a random python hash seed all the time
2100 # use a random python hash seed all the time
2100 # we do the randomness ourself to know what seed is used
2101 # we do the randomness ourself to know what seed is used
2101 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
2102 os.environ['PYTHONHASHSEED'] = str(random.getrandbits(32))
2102
2103
2103 if self.options.tmpdir:
2104 if self.options.tmpdir:
2104 self.options.keep_tmpdir = True
2105 self.options.keep_tmpdir = True
2105 tmpdir = _bytespath(self.options.tmpdir)
2106 tmpdir = _bytespath(self.options.tmpdir)
2106 if os.path.exists(tmpdir):
2107 if os.path.exists(tmpdir):
2107 # Meaning of tmpdir has changed since 1.3: we used to create
2108 # Meaning of tmpdir has changed since 1.3: we used to create
2108 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
2109 # HGTMP inside tmpdir; now HGTMP is tmpdir. So fail if
2109 # tmpdir already exists.
2110 # tmpdir already exists.
2110 print("error: temp dir %r already exists" % tmpdir)
2111 print("error: temp dir %r already exists" % tmpdir)
2111 return 1
2112 return 1
2112
2113
2113 # Automatically removing tmpdir sounds convenient, but could
2114 # Automatically removing tmpdir sounds convenient, but could
2114 # really annoy anyone in the habit of using "--tmpdir=/tmp"
2115 # really annoy anyone in the habit of using "--tmpdir=/tmp"
2115 # or "--tmpdir=$HOME".
2116 # or "--tmpdir=$HOME".
2116 #vlog("# Removing temp dir", tmpdir)
2117 #vlog("# Removing temp dir", tmpdir)
2117 #shutil.rmtree(tmpdir)
2118 #shutil.rmtree(tmpdir)
2118 os.makedirs(tmpdir)
2119 os.makedirs(tmpdir)
2119 else:
2120 else:
2120 d = None
2121 d = None
2121 if os.name == 'nt':
2122 if os.name == 'nt':
2122 # without this, we get the default temp dir location, but
2123 # without this, we get the default temp dir location, but
2123 # in all lowercase, which causes troubles with paths (issue3490)
2124 # in all lowercase, which causes troubles with paths (issue3490)
2124 d = osenvironb.get(b'TMP', None)
2125 d = osenvironb.get(b'TMP', None)
2125 tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
2126 tmpdir = tempfile.mkdtemp(b'', b'hgtests.', d)
2126
2127
2127 self._hgtmp = osenvironb[b'HGTMP'] = (
2128 self._hgtmp = osenvironb[b'HGTMP'] = (
2128 os.path.realpath(tmpdir))
2129 os.path.realpath(tmpdir))
2129
2130
2130 if self.options.with_hg:
2131 if self.options.with_hg:
2131 self._installdir = None
2132 self._installdir = None
2132 whg = self.options.with_hg
2133 whg = self.options.with_hg
2133 self._bindir = os.path.dirname(os.path.realpath(whg))
2134 self._bindir = os.path.dirname(os.path.realpath(whg))
2134 assert isinstance(self._bindir, bytes)
2135 assert isinstance(self._bindir, bytes)
2135 self._hgcommand = os.path.basename(whg)
2136 self._hgcommand = os.path.basename(whg)
2136 self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
2137 self._tmpbindir = os.path.join(self._hgtmp, b'install', b'bin')
2137 os.makedirs(self._tmpbindir)
2138 os.makedirs(self._tmpbindir)
2138
2139
2139 # This looks redundant with how Python initializes sys.path from
2140 # This looks redundant with how Python initializes sys.path from
2140 # the location of the script being executed. Needed because the
2141 # the location of the script being executed. Needed because the
2141 # "hg" specified by --with-hg is not the only Python script
2142 # "hg" specified by --with-hg is not the only Python script
2142 # executed in the test suite that needs to import 'mercurial'
2143 # executed in the test suite that needs to import 'mercurial'
2143 # ... which means it's not really redundant at all.
2144 # ... which means it's not really redundant at all.
2144 self._pythondir = self._bindir
2145 self._pythondir = self._bindir
2145 else:
2146 else:
2146 self._installdir = os.path.join(self._hgtmp, b"install")
2147 self._installdir = os.path.join(self._hgtmp, b"install")
2147 self._bindir = os.path.join(self._installdir, b"bin")
2148 self._bindir = os.path.join(self._installdir, b"bin")
2148 self._hgcommand = b'hg'
2149 self._hgcommand = b'hg'
2149 self._tmpbindir = self._bindir
2150 self._tmpbindir = self._bindir
2150 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
2151 self._pythondir = os.path.join(self._installdir, b"lib", b"python")
2151
2152
2152 # set CHGHG, then replace "hg" command by "chg"
2153 # set CHGHG, then replace "hg" command by "chg"
2153 chgbindir = self._bindir
2154 chgbindir = self._bindir
2154 if self.options.chg or self.options.with_chg:
2155 if self.options.chg or self.options.with_chg:
2155 osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand)
2156 osenvironb[b'CHGHG'] = os.path.join(self._bindir, self._hgcommand)
2156 else:
2157 else:
2157 osenvironb.pop(b'CHGHG', None) # drop flag for hghave
2158 osenvironb.pop(b'CHGHG', None) # drop flag for hghave
2158 if self.options.chg:
2159 if self.options.chg:
2159 self._hgcommand = b'chg'
2160 self._hgcommand = b'chg'
2160 elif self.options.with_chg:
2161 elif self.options.with_chg:
2161 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
2162 chgbindir = os.path.dirname(os.path.realpath(self.options.with_chg))
2162 self._hgcommand = os.path.basename(self.options.with_chg)
2163 self._hgcommand = os.path.basename(self.options.with_chg)
2163
2164
2164 osenvironb[b"BINDIR"] = self._bindir
2165 osenvironb[b"BINDIR"] = self._bindir
2165 osenvironb[b"PYTHON"] = PYTHON
2166 osenvironb[b"PYTHON"] = PYTHON
2166
2167
2167 if self.options.with_python3:
2168 if self.options.with_python3:
2168 osenvironb[b'PYTHON3'] = self.options.with_python3
2169 osenvironb[b'PYTHON3'] = self.options.with_python3
2169
2170
2170 fileb = _bytespath(__file__)
2171 fileb = _bytespath(__file__)
2171 runtestdir = os.path.abspath(os.path.dirname(fileb))
2172 runtestdir = os.path.abspath(os.path.dirname(fileb))
2172 osenvironb[b'RUNTESTDIR'] = runtestdir
2173 osenvironb[b'RUNTESTDIR'] = runtestdir
2173 if PYTHON3:
2174 if PYTHON3:
2174 sepb = _bytespath(os.pathsep)
2175 sepb = _bytespath(os.pathsep)
2175 else:
2176 else:
2176 sepb = os.pathsep
2177 sepb = os.pathsep
2177 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
2178 path = [self._bindir, runtestdir] + osenvironb[b"PATH"].split(sepb)
2178 if os.path.islink(__file__):
2179 if os.path.islink(__file__):
2179 # test helper will likely be at the end of the symlink
2180 # test helper will likely be at the end of the symlink
2180 realfile = os.path.realpath(fileb)
2181 realfile = os.path.realpath(fileb)
2181 realdir = os.path.abspath(os.path.dirname(realfile))
2182 realdir = os.path.abspath(os.path.dirname(realfile))
2182 path.insert(2, realdir)
2183 path.insert(2, realdir)
2183 if chgbindir != self._bindir:
2184 if chgbindir != self._bindir:
2184 path.insert(1, chgbindir)
2185 path.insert(1, chgbindir)
2185 if self._testdir != runtestdir:
2186 if self._testdir != runtestdir:
2186 path = [self._testdir] + path
2187 path = [self._testdir] + path
2187 if self._tmpbindir != self._bindir:
2188 if self._tmpbindir != self._bindir:
2188 path = [self._tmpbindir] + path
2189 path = [self._tmpbindir] + path
2189 osenvironb[b"PATH"] = sepb.join(path)
2190 osenvironb[b"PATH"] = sepb.join(path)
2190
2191
2191 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
2192 # Include TESTDIR in PYTHONPATH so that out-of-tree extensions
2192 # can run .../tests/run-tests.py test-foo where test-foo
2193 # can run .../tests/run-tests.py test-foo where test-foo
2193 # adds an extension to HGRC. Also include run-test.py directory to
2194 # adds an extension to HGRC. Also include run-test.py directory to
2194 # import modules like heredoctest.
2195 # import modules like heredoctest.
2195 pypath = [self._pythondir, self._testdir, runtestdir]
2196 pypath = [self._pythondir, self._testdir, runtestdir]
2196 # We have to augment PYTHONPATH, rather than simply replacing
2197 # We have to augment PYTHONPATH, rather than simply replacing
2197 # it, in case external libraries are only available via current
2198 # it, in case external libraries are only available via current
2198 # PYTHONPATH. (In particular, the Subversion bindings on OS X
2199 # PYTHONPATH. (In particular, the Subversion bindings on OS X
2199 # are in /opt/subversion.)
2200 # are in /opt/subversion.)
2200 oldpypath = osenvironb.get(IMPL_PATH)
2201 oldpypath = osenvironb.get(IMPL_PATH)
2201 if oldpypath:
2202 if oldpypath:
2202 pypath.append(oldpypath)
2203 pypath.append(oldpypath)
2203 osenvironb[IMPL_PATH] = sepb.join(pypath)
2204 osenvironb[IMPL_PATH] = sepb.join(pypath)
2204
2205
2205 if self.options.pure:
2206 if self.options.pure:
2206 os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
2207 os.environ["HGTEST_RUN_TESTS_PURE"] = "--pure"
2207 os.environ["HGMODULEPOLICY"] = "py"
2208 os.environ["HGMODULEPOLICY"] = "py"
2208
2209
2209 if self.options.allow_slow_tests:
2210 if self.options.allow_slow_tests:
2210 os.environ["HGTEST_SLOW"] = "slow"
2211 os.environ["HGTEST_SLOW"] = "slow"
2211 elif 'HGTEST_SLOW' in os.environ:
2212 elif 'HGTEST_SLOW' in os.environ:
2212 del os.environ['HGTEST_SLOW']
2213 del os.environ['HGTEST_SLOW']
2213
2214
2214 self._coveragefile = os.path.join(self._testdir, b'.coverage')
2215 self._coveragefile = os.path.join(self._testdir, b'.coverage')
2215
2216
2216 vlog("# Using TESTDIR", self._testdir)
2217 vlog("# Using TESTDIR", self._testdir)
2217 vlog("# Using RUNTESTDIR", osenvironb[b'RUNTESTDIR'])
2218 vlog("# Using RUNTESTDIR", osenvironb[b'RUNTESTDIR'])
2218 vlog("# Using HGTMP", self._hgtmp)
2219 vlog("# Using HGTMP", self._hgtmp)
2219 vlog("# Using PATH", os.environ["PATH"])
2220 vlog("# Using PATH", os.environ["PATH"])
2220 vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
2221 vlog("# Using", IMPL_PATH, osenvironb[IMPL_PATH])
2221
2222
2222 try:
2223 try:
2223 return self._runtests(tests) or 0
2224 return self._runtests(tests) or 0
2224 finally:
2225 finally:
2225 time.sleep(.1)
2226 time.sleep(.1)
2226 self._cleanup()
2227 self._cleanup()
2227
2228
2228 def findtests(self, args):
2229 def findtests(self, args):
2229 """Finds possible test files from arguments.
2230 """Finds possible test files from arguments.
2230
2231
2231 If you wish to inject custom tests into the test harness, this would
2232 If you wish to inject custom tests into the test harness, this would
2232 be a good function to monkeypatch or override in a derived class.
2233 be a good function to monkeypatch or override in a derived class.
2233 """
2234 """
2234 if not args:
2235 if not args:
2235 if self.options.changed:
2236 if self.options.changed:
2236 proc = Popen4('hg st --rev "%s" -man0 .' %
2237 proc = Popen4('hg st --rev "%s" -man0 .' %
2237 self.options.changed, None, 0)
2238 self.options.changed, None, 0)
2238 stdout, stderr = proc.communicate()
2239 stdout, stderr = proc.communicate()
2239 args = stdout.strip(b'\0').split(b'\0')
2240 args = stdout.strip(b'\0').split(b'\0')
2240 else:
2241 else:
2241 args = os.listdir(b'.')
2242 args = os.listdir(b'.')
2242
2243
2243 return [t for t in args
2244 return [t for t in args
2244 if os.path.basename(t).startswith(b'test-')
2245 if os.path.basename(t).startswith(b'test-')
2245 and (t.endswith(b'.py') or t.endswith(b'.t'))]
2246 and (t.endswith(b'.py') or t.endswith(b'.t'))]
2246
2247
2247 def _runtests(self, tests):
2248 def _runtests(self, tests):
2248 try:
2249 try:
2249 if self._installdir:
2250 if self._installdir:
2250 self._installhg()
2251 self._installhg()
2251 self._checkhglib("Testing")
2252 self._checkhglib("Testing")
2252 else:
2253 else:
2253 self._usecorrectpython()
2254 self._usecorrectpython()
2254 if self.options.chg:
2255 if self.options.chg:
2255 assert self._installdir
2256 assert self._installdir
2256 self._installchg()
2257 self._installchg()
2257
2258
2258 if self.options.restart:
2259 if self.options.restart:
2259 orig = list(tests)
2260 orig = list(tests)
2260 while tests:
2261 while tests:
2261 if os.path.exists(tests[0] + ".err"):
2262 if os.path.exists(tests[0] + ".err"):
2262 break
2263 break
2263 tests.pop(0)
2264 tests.pop(0)
2264 if not tests:
2265 if not tests:
2265 print("running all tests")
2266 print("running all tests")
2266 tests = orig
2267 tests = orig
2267
2268
2268 tests = [self._gettest(t, i) for i, t in enumerate(tests)]
2269 tests = [self._gettest(t, i) for i, t in enumerate(tests)]
2269
2270
2270 failed = False
2271 failed = False
2271 warned = False
2272 warned = False
2272 kws = self.options.keywords
2273 kws = self.options.keywords
2273 if kws is not None and PYTHON3:
2274 if kws is not None and PYTHON3:
2274 kws = kws.encode('utf-8')
2275 kws = kws.encode('utf-8')
2275
2276
2276 suite = TestSuite(self._testdir,
2277 suite = TestSuite(self._testdir,
2277 jobs=self.options.jobs,
2278 jobs=self.options.jobs,
2278 whitelist=self.options.whitelisted,
2279 whitelist=self.options.whitelisted,
2279 blacklist=self.options.blacklist,
2280 blacklist=self.options.blacklist,
2280 retest=self.options.retest,
2281 retest=self.options.retest,
2281 keywords=kws,
2282 keywords=kws,
2282 loop=self.options.loop,
2283 loop=self.options.loop,
2283 runs_per_test=self.options.runs_per_test,
2284 runs_per_test=self.options.runs_per_test,
2284 showchannels=self.options.showchannels,
2285 showchannels=self.options.showchannels,
2285 tests=tests, loadtest=self._gettest)
2286 tests=tests, loadtest=self._gettest)
2286 verbosity = 1
2287 verbosity = 1
2287 if self.options.verbose:
2288 if self.options.verbose:
2288 verbosity = 2
2289 verbosity = 2
2289 runner = TextTestRunner(self, verbosity=verbosity)
2290 runner = TextTestRunner(self, verbosity=verbosity)
2290 result = runner.run(suite)
2291 result = runner.run(suite)
2291
2292
2292 if result.failures:
2293 if result.failures:
2293 failed = True
2294 failed = True
2294 if result.warned:
2295 if result.warned:
2295 warned = True
2296 warned = True
2296
2297
2297 if self.options.anycoverage:
2298 if self.options.anycoverage:
2298 self._outputcoverage()
2299 self._outputcoverage()
2299 except KeyboardInterrupt:
2300 except KeyboardInterrupt:
2300 failed = True
2301 failed = True
2301 print("\ninterrupted!")
2302 print("\ninterrupted!")
2302
2303
2303 if failed:
2304 if failed:
2304 return 1
2305 return 1
2305 if warned:
2306 if warned:
2306 return 80
2307 return 80
2307
2308
2308 def _getport(self, count):
2309 def _getport(self, count):
2309 port = self._ports.get(count) # do we have a cached entry?
2310 port = self._ports.get(count) # do we have a cached entry?
2310 if port is None:
2311 if port is None:
2311 portneeded = 3
2312 portneeded = 3
2312 # above 100 tries we just give up and let test reports failure
2313 # above 100 tries we just give up and let test reports failure
2313 for tries in xrange(100):
2314 for tries in xrange(100):
2314 allfree = True
2315 allfree = True
2315 port = self.options.port + self._portoffset
2316 port = self.options.port + self._portoffset
2316 for idx in xrange(portneeded):
2317 for idx in xrange(portneeded):
2317 if not checkportisavailable(port + idx):
2318 if not checkportisavailable(port + idx):
2318 allfree = False
2319 allfree = False
2319 break
2320 break
2320 self._portoffset += portneeded
2321 self._portoffset += portneeded
2321 if allfree:
2322 if allfree:
2322 break
2323 break
2323 self._ports[count] = port
2324 self._ports[count] = port
2324 return port
2325 return port
2325
2326
2326 def _gettest(self, test, count):
2327 def _gettest(self, test, count):
2327 """Obtain a Test by looking at its filename.
2328 """Obtain a Test by looking at its filename.
2328
2329
2329 Returns a Test instance. The Test may not be runnable if it doesn't
2330 Returns a Test instance. The Test may not be runnable if it doesn't
2330 map to a known type.
2331 map to a known type.
2331 """
2332 """
2332 lctest = test.lower()
2333 lctest = test.lower()
2333 testcls = Test
2334 testcls = Test
2334
2335
2335 for ext, cls in self.TESTTYPES:
2336 for ext, cls in self.TESTTYPES:
2336 if lctest.endswith(ext):
2337 if lctest.endswith(ext):
2337 testcls = cls
2338 testcls = cls
2338 break
2339 break
2339
2340
2340 refpath = os.path.join(self._testdir, test)
2341 refpath = os.path.join(self._testdir, test)
2341 tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
2342 tmpdir = os.path.join(self._hgtmp, b'child%d' % count)
2342
2343
2343 t = testcls(refpath, tmpdir,
2344 t = testcls(refpath, tmpdir,
2344 keeptmpdir=self.options.keep_tmpdir,
2345 keeptmpdir=self.options.keep_tmpdir,
2345 debug=self.options.debug,
2346 debug=self.options.debug,
2346 timeout=self.options.timeout,
2347 timeout=self.options.timeout,
2347 startport=self._getport(count),
2348 startport=self._getport(count),
2348 extraconfigopts=self.options.extra_config_opt,
2349 extraconfigopts=self.options.extra_config_opt,
2349 py3kwarnings=self.options.py3k_warnings,
2350 py3kwarnings=self.options.py3k_warnings,
2350 shell=self.options.shell,
2351 shell=self.options.shell,
2351 hgcommand=self._hgcommand,
2352 hgcommand=self._hgcommand,
2352 usechg=bool(self.options.with_chg or self.options.chg),
2353 usechg=bool(self.options.with_chg or self.options.chg),
2353 useipv6=useipv6)
2354 useipv6=useipv6)
2354 t.should_reload = True
2355 t.should_reload = True
2355 return t
2356 return t
2356
2357
2357 def _cleanup(self):
2358 def _cleanup(self):
2358 """Clean up state from this test invocation."""
2359 """Clean up state from this test invocation."""
2359 if self.options.keep_tmpdir:
2360 if self.options.keep_tmpdir:
2360 return
2361 return
2361
2362
2362 vlog("# Cleaning up HGTMP", self._hgtmp)
2363 vlog("# Cleaning up HGTMP", self._hgtmp)
2363 shutil.rmtree(self._hgtmp, True)
2364 shutil.rmtree(self._hgtmp, True)
2364 for f in self._createdfiles:
2365 for f in self._createdfiles:
2365 try:
2366 try:
2366 os.remove(f)
2367 os.remove(f)
2367 except OSError:
2368 except OSError:
2368 pass
2369 pass
2369
2370
2370 def _usecorrectpython(self):
2371 def _usecorrectpython(self):
2371 """Configure the environment to use the appropriate Python in tests."""
2372 """Configure the environment to use the appropriate Python in tests."""
2372 # Tests must use the same interpreter as us or bad things will happen.
2373 # Tests must use the same interpreter as us or bad things will happen.
2373 pyexename = sys.platform == 'win32' and b'python.exe' or b'python'
2374 pyexename = sys.platform == 'win32' and b'python.exe' or b'python'
2374 if getattr(os, 'symlink', None):
2375 if getattr(os, 'symlink', None):
2375 vlog("# Making python executable in test path a symlink to '%s'" %
2376 vlog("# Making python executable in test path a symlink to '%s'" %
2376 sys.executable)
2377 sys.executable)
2377 mypython = os.path.join(self._tmpbindir, pyexename)
2378 mypython = os.path.join(self._tmpbindir, pyexename)
2378 try:
2379 try:
2379 if os.readlink(mypython) == sys.executable:
2380 if os.readlink(mypython) == sys.executable:
2380 return
2381 return
2381 os.unlink(mypython)
2382 os.unlink(mypython)
2382 except OSError as err:
2383 except OSError as err:
2383 if err.errno != errno.ENOENT:
2384 if err.errno != errno.ENOENT:
2384 raise
2385 raise
2385 if self._findprogram(pyexename) != sys.executable:
2386 if self._findprogram(pyexename) != sys.executable:
2386 try:
2387 try:
2387 os.symlink(sys.executable, mypython)
2388 os.symlink(sys.executable, mypython)
2388 self._createdfiles.append(mypython)
2389 self._createdfiles.append(mypython)
2389 except OSError as err:
2390 except OSError as err:
2390 # child processes may race, which is harmless
2391 # child processes may race, which is harmless
2391 if err.errno != errno.EEXIST:
2392 if err.errno != errno.EEXIST:
2392 raise
2393 raise
2393 else:
2394 else:
2394 exedir, exename = os.path.split(sys.executable)
2395 exedir, exename = os.path.split(sys.executable)
2395 vlog("# Modifying search path to find %s as %s in '%s'" %
2396 vlog("# Modifying search path to find %s as %s in '%s'" %
2396 (exename, pyexename, exedir))
2397 (exename, pyexename, exedir))
2397 path = os.environ['PATH'].split(os.pathsep)
2398 path = os.environ['PATH'].split(os.pathsep)
2398 while exedir in path:
2399 while exedir in path:
2399 path.remove(exedir)
2400 path.remove(exedir)
2400 os.environ['PATH'] = os.pathsep.join([exedir] + path)
2401 os.environ['PATH'] = os.pathsep.join([exedir] + path)
2401 if not self._findprogram(pyexename):
2402 if not self._findprogram(pyexename):
2402 print("WARNING: Cannot find %s in search path" % pyexename)
2403 print("WARNING: Cannot find %s in search path" % pyexename)
2403
2404
2404 def _installhg(self):
2405 def _installhg(self):
2405 """Install hg into the test environment.
2406 """Install hg into the test environment.
2406
2407
2407 This will also configure hg with the appropriate testing settings.
2408 This will also configure hg with the appropriate testing settings.
2408 """
2409 """
2409 vlog("# Performing temporary installation of HG")
2410 vlog("# Performing temporary installation of HG")
2410 installerrs = os.path.join(self._hgtmp, b"install.err")
2411 installerrs = os.path.join(self._hgtmp, b"install.err")
2411 compiler = ''
2412 compiler = ''
2412 if self.options.compiler:
2413 if self.options.compiler:
2413 compiler = '--compiler ' + self.options.compiler
2414 compiler = '--compiler ' + self.options.compiler
2414 if self.options.pure:
2415 if self.options.pure:
2415 pure = b"--pure"
2416 pure = b"--pure"
2416 else:
2417 else:
2417 pure = b""
2418 pure = b""
2418
2419
2419 # Run installer in hg root
2420 # Run installer in hg root
2420 script = os.path.realpath(sys.argv[0])
2421 script = os.path.realpath(sys.argv[0])
2421 exe = sys.executable
2422 exe = sys.executable
2422 if PYTHON3:
2423 if PYTHON3:
2423 compiler = _bytespath(compiler)
2424 compiler = _bytespath(compiler)
2424 script = _bytespath(script)
2425 script = _bytespath(script)
2425 exe = _bytespath(exe)
2426 exe = _bytespath(exe)
2426 hgroot = os.path.dirname(os.path.dirname(script))
2427 hgroot = os.path.dirname(os.path.dirname(script))
2427 self._hgroot = hgroot
2428 self._hgroot = hgroot
2428 os.chdir(hgroot)
2429 os.chdir(hgroot)
2429 nohome = b'--home=""'
2430 nohome = b'--home=""'
2430 if os.name == 'nt':
2431 if os.name == 'nt':
2431 # The --home="" trick works only on OS where os.sep == '/'
2432 # The --home="" trick works only on OS where os.sep == '/'
2432 # because of a distutils convert_path() fast-path. Avoid it at
2433 # because of a distutils convert_path() fast-path. Avoid it at
2433 # least on Windows for now, deal with .pydistutils.cfg bugs
2434 # least on Windows for now, deal with .pydistutils.cfg bugs
2434 # when they happen.
2435 # when they happen.
2435 nohome = b''
2436 nohome = b''
2436 cmd = (b'%(exe)s setup.py %(pure)s clean --all'
2437 cmd = (b'%(exe)s setup.py %(pure)s clean --all'
2437 b' build %(compiler)s --build-base="%(base)s"'
2438 b' build %(compiler)s --build-base="%(base)s"'
2438 b' install --force --prefix="%(prefix)s"'
2439 b' install --force --prefix="%(prefix)s"'
2439 b' --install-lib="%(libdir)s"'
2440 b' --install-lib="%(libdir)s"'
2440 b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
2441 b' --install-scripts="%(bindir)s" %(nohome)s >%(logfile)s 2>&1'
2441 % {b'exe': exe, b'pure': pure,
2442 % {b'exe': exe, b'pure': pure,
2442 b'compiler': compiler,
2443 b'compiler': compiler,
2443 b'base': os.path.join(self._hgtmp, b"build"),
2444 b'base': os.path.join(self._hgtmp, b"build"),
2444 b'prefix': self._installdir, b'libdir': self._pythondir,
2445 b'prefix': self._installdir, b'libdir': self._pythondir,
2445 b'bindir': self._bindir,
2446 b'bindir': self._bindir,
2446 b'nohome': nohome, b'logfile': installerrs})
2447 b'nohome': nohome, b'logfile': installerrs})
2447
2448
2448 # setuptools requires install directories to exist.
2449 # setuptools requires install directories to exist.
2449 def makedirs(p):
2450 def makedirs(p):
2450 try:
2451 try:
2451 os.makedirs(p)
2452 os.makedirs(p)
2452 except OSError as e:
2453 except OSError as e:
2453 if e.errno != errno.EEXIST:
2454 if e.errno != errno.EEXIST:
2454 raise
2455 raise
2455 makedirs(self._pythondir)
2456 makedirs(self._pythondir)
2456 makedirs(self._bindir)
2457 makedirs(self._bindir)
2457
2458
2458 vlog("# Running", cmd)
2459 vlog("# Running", cmd)
2459 if os.system(cmd) == 0:
2460 if os.system(cmd) == 0:
2460 if not self.options.verbose:
2461 if not self.options.verbose:
2461 try:
2462 try:
2462 os.remove(installerrs)
2463 os.remove(installerrs)
2463 except OSError as e:
2464 except OSError as e:
2464 if e.errno != errno.ENOENT:
2465 if e.errno != errno.ENOENT:
2465 raise
2466 raise
2466 else:
2467 else:
2467 f = open(installerrs, 'rb')
2468 f = open(installerrs, 'rb')
2468 for line in f:
2469 for line in f:
2469 if PYTHON3:
2470 if PYTHON3:
2470 sys.stdout.buffer.write(line)
2471 sys.stdout.buffer.write(line)
2471 else:
2472 else:
2472 sys.stdout.write(line)
2473 sys.stdout.write(line)
2473 f.close()
2474 f.close()
2474 sys.exit(1)
2475 sys.exit(1)
2475 os.chdir(self._testdir)
2476 os.chdir(self._testdir)
2476
2477
2477 self._usecorrectpython()
2478 self._usecorrectpython()
2478
2479
2479 if self.options.py3k_warnings and not self.options.anycoverage:
2480 if self.options.py3k_warnings and not self.options.anycoverage:
2480 vlog("# Updating hg command to enable Py3k Warnings switch")
2481 vlog("# Updating hg command to enable Py3k Warnings switch")
2481 f = open(os.path.join(self._bindir, 'hg'), 'rb')
2482 f = open(os.path.join(self._bindir, 'hg'), 'rb')
2482 lines = [line.rstrip() for line in f]
2483 lines = [line.rstrip() for line in f]
2483 lines[0] += ' -3'
2484 lines[0] += ' -3'
2484 f.close()
2485 f.close()
2485 f = open(os.path.join(self._bindir, 'hg'), 'wb')
2486 f = open(os.path.join(self._bindir, 'hg'), 'wb')
2486 for line in lines:
2487 for line in lines:
2487 f.write(line + '\n')
2488 f.write(line + '\n')
2488 f.close()
2489 f.close()
2489
2490
2490 hgbat = os.path.join(self._bindir, b'hg.bat')
2491 hgbat = os.path.join(self._bindir, b'hg.bat')
2491 if os.path.isfile(hgbat):
2492 if os.path.isfile(hgbat):
2492 # hg.bat expects to be put in bin/scripts while run-tests.py
2493 # hg.bat expects to be put in bin/scripts while run-tests.py
2493 # installation layout put it in bin/ directly. Fix it
2494 # installation layout put it in bin/ directly. Fix it
2494 f = open(hgbat, 'rb')
2495 f = open(hgbat, 'rb')
2495 data = f.read()
2496 data = f.read()
2496 f.close()
2497 f.close()
2497 if b'"%~dp0..\python" "%~dp0hg" %*' in data:
2498 if b'"%~dp0..\python" "%~dp0hg" %*' in data:
2498 data = data.replace(b'"%~dp0..\python" "%~dp0hg" %*',
2499 data = data.replace(b'"%~dp0..\python" "%~dp0hg" %*',
2499 b'"%~dp0python" "%~dp0hg" %*')
2500 b'"%~dp0python" "%~dp0hg" %*')
2500 f = open(hgbat, 'wb')
2501 f = open(hgbat, 'wb')
2501 f.write(data)
2502 f.write(data)
2502 f.close()
2503 f.close()
2503 else:
2504 else:
2504 print('WARNING: cannot fix hg.bat reference to python.exe')
2505 print('WARNING: cannot fix hg.bat reference to python.exe')
2505
2506
2506 if self.options.anycoverage:
2507 if self.options.anycoverage:
2507 custom = os.path.join(self._testdir, 'sitecustomize.py')
2508 custom = os.path.join(self._testdir, 'sitecustomize.py')
2508 target = os.path.join(self._pythondir, 'sitecustomize.py')
2509 target = os.path.join(self._pythondir, 'sitecustomize.py')
2509 vlog('# Installing coverage trigger to %s' % target)
2510 vlog('# Installing coverage trigger to %s' % target)
2510 shutil.copyfile(custom, target)
2511 shutil.copyfile(custom, target)
2511 rc = os.path.join(self._testdir, '.coveragerc')
2512 rc = os.path.join(self._testdir, '.coveragerc')
2512 vlog('# Installing coverage rc to %s' % rc)
2513 vlog('# Installing coverage rc to %s' % rc)
2513 os.environ['COVERAGE_PROCESS_START'] = rc
2514 os.environ['COVERAGE_PROCESS_START'] = rc
2514 covdir = os.path.join(self._installdir, '..', 'coverage')
2515 covdir = os.path.join(self._installdir, '..', 'coverage')
2515 try:
2516 try:
2516 os.mkdir(covdir)
2517 os.mkdir(covdir)
2517 except OSError as e:
2518 except OSError as e:
2518 if e.errno != errno.EEXIST:
2519 if e.errno != errno.EEXIST:
2519 raise
2520 raise
2520
2521
2521 os.environ['COVERAGE_DIR'] = covdir
2522 os.environ['COVERAGE_DIR'] = covdir
2522
2523
2523 def _checkhglib(self, verb):
2524 def _checkhglib(self, verb):
2524 """Ensure that the 'mercurial' package imported by python is
2525 """Ensure that the 'mercurial' package imported by python is
2525 the one we expect it to be. If not, print a warning to stderr."""
2526 the one we expect it to be. If not, print a warning to stderr."""
2526 if ((self._bindir == self._pythondir) and
2527 if ((self._bindir == self._pythondir) and
2527 (self._bindir != self._tmpbindir)):
2528 (self._bindir != self._tmpbindir)):
2528 # The pythondir has been inferred from --with-hg flag.
2529 # The pythondir has been inferred from --with-hg flag.
2529 # We cannot expect anything sensible here.
2530 # We cannot expect anything sensible here.
2530 return
2531 return
2531 expecthg = os.path.join(self._pythondir, b'mercurial')
2532 expecthg = os.path.join(self._pythondir, b'mercurial')
2532 actualhg = self._gethgpath()
2533 actualhg = self._gethgpath()
2533 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
2534 if os.path.abspath(actualhg) != os.path.abspath(expecthg):
2534 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
2535 sys.stderr.write('warning: %s with unexpected mercurial lib: %s\n'
2535 ' (expected %s)\n'
2536 ' (expected %s)\n'
2536 % (verb, actualhg, expecthg))
2537 % (verb, actualhg, expecthg))
2537 def _gethgpath(self):
2538 def _gethgpath(self):
2538 """Return the path to the mercurial package that is actually found by
2539 """Return the path to the mercurial package that is actually found by
2539 the current Python interpreter."""
2540 the current Python interpreter."""
2540 if self._hgpath is not None:
2541 if self._hgpath is not None:
2541 return self._hgpath
2542 return self._hgpath
2542
2543
2543 cmd = b'%s -c "import mercurial; print (mercurial.__path__[0])"'
2544 cmd = b'%s -c "import mercurial; print (mercurial.__path__[0])"'
2544 cmd = cmd % PYTHON
2545 cmd = cmd % PYTHON
2545 if PYTHON3:
2546 if PYTHON3:
2546 cmd = _strpath(cmd)
2547 cmd = _strpath(cmd)
2547 pipe = os.popen(cmd)
2548 pipe = os.popen(cmd)
2548 try:
2549 try:
2549 self._hgpath = _bytespath(pipe.read().strip())
2550 self._hgpath = _bytespath(pipe.read().strip())
2550 finally:
2551 finally:
2551 pipe.close()
2552 pipe.close()
2552
2553
2553 return self._hgpath
2554 return self._hgpath
2554
2555
2555 def _installchg(self):
2556 def _installchg(self):
2556 """Install chg into the test environment"""
2557 """Install chg into the test environment"""
2557 vlog('# Performing temporary installation of CHG')
2558 vlog('# Performing temporary installation of CHG')
2558 assert os.path.dirname(self._bindir) == self._installdir
2559 assert os.path.dirname(self._bindir) == self._installdir
2559 assert self._hgroot, 'must be called after _installhg()'
2560 assert self._hgroot, 'must be called after _installhg()'
2560 cmd = (b'"%(make)s" clean install PREFIX="%(prefix)s"'
2561 cmd = (b'"%(make)s" clean install PREFIX="%(prefix)s"'
2561 % {b'make': 'make', # TODO: switch by option or environment?
2562 % {b'make': 'make', # TODO: switch by option or environment?
2562 b'prefix': self._installdir})
2563 b'prefix': self._installdir})
2563 cwd = os.path.join(self._hgroot, b'contrib', b'chg')
2564 cwd = os.path.join(self._hgroot, b'contrib', b'chg')
2564 vlog("# Running", cmd)
2565 vlog("# Running", cmd)
2565 proc = subprocess.Popen(cmd, shell=True, cwd=cwd,
2566 proc = subprocess.Popen(cmd, shell=True, cwd=cwd,
2566 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2567 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2567 stderr=subprocess.STDOUT)
2568 stderr=subprocess.STDOUT)
2568 out, _err = proc.communicate()
2569 out, _err = proc.communicate()
2569 if proc.returncode != 0:
2570 if proc.returncode != 0:
2570 if PYTHON3:
2571 if PYTHON3:
2571 sys.stdout.buffer.write(out)
2572 sys.stdout.buffer.write(out)
2572 else:
2573 else:
2573 sys.stdout.write(out)
2574 sys.stdout.write(out)
2574 sys.exit(1)
2575 sys.exit(1)
2575
2576
2576 def _outputcoverage(self):
2577 def _outputcoverage(self):
2577 """Produce code coverage output."""
2578 """Produce code coverage output."""
2578 import coverage
2579 import coverage
2579 coverage = coverage.coverage
2580 coverage = coverage.coverage
2580
2581
2581 vlog('# Producing coverage report')
2582 vlog('# Producing coverage report')
2582 # chdir is the easiest way to get short, relative paths in the
2583 # chdir is the easiest way to get short, relative paths in the
2583 # output.
2584 # output.
2584 os.chdir(self._hgroot)
2585 os.chdir(self._hgroot)
2585 covdir = os.path.join(self._installdir, '..', 'coverage')
2586 covdir = os.path.join(self._installdir, '..', 'coverage')
2586 cov = coverage(data_file=os.path.join(covdir, 'cov'))
2587 cov = coverage(data_file=os.path.join(covdir, 'cov'))
2587
2588
2588 # Map install directory paths back to source directory.
2589 # Map install directory paths back to source directory.
2589 cov.config.paths['srcdir'] = ['.', self._pythondir]
2590 cov.config.paths['srcdir'] = ['.', self._pythondir]
2590
2591
2591 cov.combine()
2592 cov.combine()
2592
2593
2593 omit = [os.path.join(x, '*') for x in [self._bindir, self._testdir]]
2594 omit = [os.path.join(x, '*') for x in [self._bindir, self._testdir]]
2594 cov.report(ignore_errors=True, omit=omit)
2595 cov.report(ignore_errors=True, omit=omit)
2595
2596
2596 if self.options.htmlcov:
2597 if self.options.htmlcov:
2597 htmldir = os.path.join(self._testdir, 'htmlcov')
2598 htmldir = os.path.join(self._testdir, 'htmlcov')
2598 cov.html_report(directory=htmldir, omit=omit)
2599 cov.html_report(directory=htmldir, omit=omit)
2599 if self.options.annotate:
2600 if self.options.annotate:
2600 adir = os.path.join(self._testdir, 'annotated')
2601 adir = os.path.join(self._testdir, 'annotated')
2601 if not os.path.isdir(adir):
2602 if not os.path.isdir(adir):
2602 os.mkdir(adir)
2603 os.mkdir(adir)
2603 cov.annotate(directory=adir, omit=omit)
2604 cov.annotate(directory=adir, omit=omit)
2604
2605
2605 def _findprogram(self, program):
2606 def _findprogram(self, program):
2606 """Search PATH for a executable program"""
2607 """Search PATH for a executable program"""
2607 dpb = _bytespath(os.defpath)
2608 dpb = _bytespath(os.defpath)
2608 sepb = _bytespath(os.pathsep)
2609 sepb = _bytespath(os.pathsep)
2609 for p in osenvironb.get(b'PATH', dpb).split(sepb):
2610 for p in osenvironb.get(b'PATH', dpb).split(sepb):
2610 name = os.path.join(p, program)
2611 name = os.path.join(p, program)
2611 if os.name == 'nt' or os.access(name, os.X_OK):
2612 if os.name == 'nt' or os.access(name, os.X_OK):
2612 return name
2613 return name
2613 return None
2614 return None
2614
2615
2615 def _checktools(self):
2616 def _checktools(self):
2616 """Ensure tools required to run tests are present."""
2617 """Ensure tools required to run tests are present."""
2617 for p in self.REQUIREDTOOLS:
2618 for p in self.REQUIREDTOOLS:
2618 if os.name == 'nt' and not p.endswith('.exe'):
2619 if os.name == 'nt' and not p.endswith('.exe'):
2619 p += '.exe'
2620 p += '.exe'
2620 found = self._findprogram(p)
2621 found = self._findprogram(p)
2621 if found:
2622 if found:
2622 vlog("# Found prerequisite", p, "at", found)
2623 vlog("# Found prerequisite", p, "at", found)
2623 else:
2624 else:
2624 print("WARNING: Did not find prerequisite tool: %s " %
2625 print("WARNING: Did not find prerequisite tool: %s " %
2625 p.decode("utf-8"))
2626 p.decode("utf-8"))
2626
2627
2627 if __name__ == '__main__':
2628 if __name__ == '__main__':
2628 runner = TestRunner()
2629 runner = TestRunner()
2629
2630
2630 try:
2631 try:
2631 import msvcrt
2632 import msvcrt
2632 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
2633 msvcrt.setmode(sys.stdin.fileno(), os.O_BINARY)
2633 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
2634 msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
2634 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
2635 msvcrt.setmode(sys.stderr.fileno(), os.O_BINARY)
2635 except ImportError:
2636 except ImportError:
2636 pass
2637 pass
2637
2638
2638 sys.exit(runner.run(sys.argv[1:]))
2639 sys.exit(runner.run(sys.argv[1:]))
@@ -1,853 +1,853 b''
1
1
2 $ cat << EOF >> $HGRCPATH
2 $ cat << EOF >> $HGRCPATH
3 > [format]
3 > [format]
4 > usegeneraldelta=yes
4 > usegeneraldelta=yes
5 > EOF
5 > EOF
6
6
7 Setting up test
7 Setting up test
8
8
9 $ hg init test
9 $ hg init test
10 $ cd test
10 $ cd test
11 $ echo 0 > afile
11 $ echo 0 > afile
12 $ hg add afile
12 $ hg add afile
13 $ hg commit -m "0.0"
13 $ hg commit -m "0.0"
14 $ echo 1 >> afile
14 $ echo 1 >> afile
15 $ hg commit -m "0.1"
15 $ hg commit -m "0.1"
16 $ echo 2 >> afile
16 $ echo 2 >> afile
17 $ hg commit -m "0.2"
17 $ hg commit -m "0.2"
18 $ echo 3 >> afile
18 $ echo 3 >> afile
19 $ hg commit -m "0.3"
19 $ hg commit -m "0.3"
20 $ hg update -C 0
20 $ hg update -C 0
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ echo 1 >> afile
22 $ echo 1 >> afile
23 $ hg commit -m "1.1"
23 $ hg commit -m "1.1"
24 created new head
24 created new head
25 $ echo 2 >> afile
25 $ echo 2 >> afile
26 $ hg commit -m "1.2"
26 $ hg commit -m "1.2"
27 $ echo "a line" > fred
27 $ echo "a line" > fred
28 $ echo 3 >> afile
28 $ echo 3 >> afile
29 $ hg add fred
29 $ hg add fred
30 $ hg commit -m "1.3"
30 $ hg commit -m "1.3"
31 $ hg mv afile adifferentfile
31 $ hg mv afile adifferentfile
32 $ hg commit -m "1.3m"
32 $ hg commit -m "1.3m"
33 $ hg update -C 3
33 $ hg update -C 3
34 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
34 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
35 $ hg mv afile anotherfile
35 $ hg mv afile anotherfile
36 $ hg commit -m "0.3m"
36 $ hg commit -m "0.3m"
37 $ hg verify
37 $ hg verify
38 checking changesets
38 checking changesets
39 checking manifests
39 checking manifests
40 crosschecking files in changesets and manifests
40 crosschecking files in changesets and manifests
41 checking files
41 checking files
42 4 files, 9 changesets, 7 total revisions
42 4 files, 9 changesets, 7 total revisions
43 $ cd ..
43 $ cd ..
44 $ hg init empty
44 $ hg init empty
45
45
46 Bundle and phase
46 Bundle and phase
47
47
48 $ hg -R test phase --force --secret 0
48 $ hg -R test phase --force --secret 0
49 $ hg -R test bundle phase.hg empty
49 $ hg -R test bundle phase.hg empty
50 searching for changes
50 searching for changes
51 no changes found (ignored 9 secret changesets)
51 no changes found (ignored 9 secret changesets)
52 [1]
52 [1]
53 $ hg -R test phase --draft -r 'head()'
53 $ hg -R test phase --draft -r 'head()'
54
54
55 Bundle --all
55 Bundle --all
56
56
57 $ hg -R test bundle --all all.hg
57 $ hg -R test bundle --all all.hg
58 9 changesets found
58 9 changesets found
59
59
60 Bundle test to full.hg
60 Bundle test to full.hg
61
61
62 $ hg -R test bundle full.hg empty
62 $ hg -R test bundle full.hg empty
63 searching for changes
63 searching for changes
64 9 changesets found
64 9 changesets found
65
65
66 Unbundle full.hg in test
66 Unbundle full.hg in test
67
67
68 $ hg -R test unbundle full.hg
68 $ hg -R test unbundle full.hg
69 adding changesets
69 adding changesets
70 adding manifests
70 adding manifests
71 adding file changes
71 adding file changes
72 added 0 changesets with 0 changes to 4 files
72 added 0 changesets with 0 changes to 4 files
73 (run 'hg update' to get a working copy)
73 (run 'hg update' to get a working copy)
74
74
75 Verify empty
75 Verify empty
76
76
77 $ hg -R empty heads
77 $ hg -R empty heads
78 [1]
78 [1]
79 $ hg -R empty verify
79 $ hg -R empty verify
80 checking changesets
80 checking changesets
81 checking manifests
81 checking manifests
82 crosschecking files in changesets and manifests
82 crosschecking files in changesets and manifests
83 checking files
83 checking files
84 0 files, 0 changesets, 0 total revisions
84 0 files, 0 changesets, 0 total revisions
85
85
86 Pull full.hg into test (using --cwd)
86 Pull full.hg into test (using --cwd)
87
87
88 $ hg --cwd test pull ../full.hg
88 $ hg --cwd test pull ../full.hg
89 pulling from ../full.hg
89 pulling from ../full.hg
90 searching for changes
90 searching for changes
91 no changes found
91 no changes found
92
92
93 Verify that there are no leaked temporary files after pull (issue2797)
93 Verify that there are no leaked temporary files after pull (issue2797)
94
94
95 $ ls test/.hg | grep .hg10un
95 $ ls test/.hg | grep .hg10un
96 [1]
96 [1]
97
97
98 Pull full.hg into empty (using --cwd)
98 Pull full.hg into empty (using --cwd)
99
99
100 $ hg --cwd empty pull ../full.hg
100 $ hg --cwd empty pull ../full.hg
101 pulling from ../full.hg
101 pulling from ../full.hg
102 requesting all changes
102 requesting all changes
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 9 changesets with 7 changes to 4 files (+1 heads)
106 added 9 changesets with 7 changes to 4 files (+1 heads)
107 (run 'hg heads' to see heads, 'hg merge' to merge)
107 (run 'hg heads' to see heads, 'hg merge' to merge)
108
108
109 Rollback empty
109 Rollback empty
110
110
111 $ hg -R empty rollback
111 $ hg -R empty rollback
112 repository tip rolled back to revision -1 (undo pull)
112 repository tip rolled back to revision -1 (undo pull)
113
113
114 Pull full.hg into empty again (using --cwd)
114 Pull full.hg into empty again (using --cwd)
115
115
116 $ hg --cwd empty pull ../full.hg
116 $ hg --cwd empty pull ../full.hg
117 pulling from ../full.hg
117 pulling from ../full.hg
118 requesting all changes
118 requesting all changes
119 adding changesets
119 adding changesets
120 adding manifests
120 adding manifests
121 adding file changes
121 adding file changes
122 added 9 changesets with 7 changes to 4 files (+1 heads)
122 added 9 changesets with 7 changes to 4 files (+1 heads)
123 (run 'hg heads' to see heads, 'hg merge' to merge)
123 (run 'hg heads' to see heads, 'hg merge' to merge)
124
124
125 Pull full.hg into test (using -R)
125 Pull full.hg into test (using -R)
126
126
127 $ hg -R test pull full.hg
127 $ hg -R test pull full.hg
128 pulling from full.hg
128 pulling from full.hg
129 searching for changes
129 searching for changes
130 no changes found
130 no changes found
131
131
132 Pull full.hg into empty (using -R)
132 Pull full.hg into empty (using -R)
133
133
134 $ hg -R empty pull full.hg
134 $ hg -R empty pull full.hg
135 pulling from full.hg
135 pulling from full.hg
136 searching for changes
136 searching for changes
137 no changes found
137 no changes found
138
138
139 Rollback empty
139 Rollback empty
140
140
141 $ hg -R empty rollback
141 $ hg -R empty rollback
142 repository tip rolled back to revision -1 (undo pull)
142 repository tip rolled back to revision -1 (undo pull)
143
143
144 Pull full.hg into empty again (using -R)
144 Pull full.hg into empty again (using -R)
145
145
146 $ hg -R empty pull full.hg
146 $ hg -R empty pull full.hg
147 pulling from full.hg
147 pulling from full.hg
148 requesting all changes
148 requesting all changes
149 adding changesets
149 adding changesets
150 adding manifests
150 adding manifests
151 adding file changes
151 adding file changes
152 added 9 changesets with 7 changes to 4 files (+1 heads)
152 added 9 changesets with 7 changes to 4 files (+1 heads)
153 (run 'hg heads' to see heads, 'hg merge' to merge)
153 (run 'hg heads' to see heads, 'hg merge' to merge)
154
154
155 Log -R full.hg in fresh empty
155 Log -R full.hg in fresh empty
156
156
157 $ rm -r empty
157 $ rm -r empty
158 $ hg init empty
158 $ hg init empty
159 $ cd empty
159 $ cd empty
160 $ hg -R bundle://../full.hg log
160 $ hg -R bundle://../full.hg log
161 changeset: 8:aa35859c02ea
161 changeset: 8:aa35859c02ea
162 tag: tip
162 tag: tip
163 parent: 3:eebf5a27f8ca
163 parent: 3:eebf5a27f8ca
164 user: test
164 user: test
165 date: Thu Jan 01 00:00:00 1970 +0000
165 date: Thu Jan 01 00:00:00 1970 +0000
166 summary: 0.3m
166 summary: 0.3m
167
167
168 changeset: 7:a6a34bfa0076
168 changeset: 7:a6a34bfa0076
169 user: test
169 user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: 1.3m
171 summary: 1.3m
172
172
173 changeset: 6:7373c1169842
173 changeset: 6:7373c1169842
174 user: test
174 user: test
175 date: Thu Jan 01 00:00:00 1970 +0000
175 date: Thu Jan 01 00:00:00 1970 +0000
176 summary: 1.3
176 summary: 1.3
177
177
178 changeset: 5:1bb50a9436a7
178 changeset: 5:1bb50a9436a7
179 user: test
179 user: test
180 date: Thu Jan 01 00:00:00 1970 +0000
180 date: Thu Jan 01 00:00:00 1970 +0000
181 summary: 1.2
181 summary: 1.2
182
182
183 changeset: 4:095197eb4973
183 changeset: 4:095197eb4973
184 parent: 0:f9ee2f85a263
184 parent: 0:f9ee2f85a263
185 user: test
185 user: test
186 date: Thu Jan 01 00:00:00 1970 +0000
186 date: Thu Jan 01 00:00:00 1970 +0000
187 summary: 1.1
187 summary: 1.1
188
188
189 changeset: 3:eebf5a27f8ca
189 changeset: 3:eebf5a27f8ca
190 user: test
190 user: test
191 date: Thu Jan 01 00:00:00 1970 +0000
191 date: Thu Jan 01 00:00:00 1970 +0000
192 summary: 0.3
192 summary: 0.3
193
193
194 changeset: 2:e38ba6f5b7e0
194 changeset: 2:e38ba6f5b7e0
195 user: test
195 user: test
196 date: Thu Jan 01 00:00:00 1970 +0000
196 date: Thu Jan 01 00:00:00 1970 +0000
197 summary: 0.2
197 summary: 0.2
198
198
199 changeset: 1:34c2bf6b0626
199 changeset: 1:34c2bf6b0626
200 user: test
200 user: test
201 date: Thu Jan 01 00:00:00 1970 +0000
201 date: Thu Jan 01 00:00:00 1970 +0000
202 summary: 0.1
202 summary: 0.1
203
203
204 changeset: 0:f9ee2f85a263
204 changeset: 0:f9ee2f85a263
205 user: test
205 user: test
206 date: Thu Jan 01 00:00:00 1970 +0000
206 date: Thu Jan 01 00:00:00 1970 +0000
207 summary: 0.0
207 summary: 0.0
208
208
209 Make sure bundlerepo doesn't leak tempfiles (issue2491)
209 Make sure bundlerepo doesn't leak tempfiles (issue2491)
210
210
211 $ ls .hg
211 $ ls .hg
212 00changelog.i
212 00changelog.i
213 cache
213 cache
214 requires
214 requires
215 store
215 store
216
216
217 Pull ../full.hg into empty (with hook)
217 Pull ../full.hg into empty (with hook)
218
218
219 $ cat >> .hg/hgrc <<EOF
219 $ cat >> .hg/hgrc <<EOF
220 > [hooks]
220 > [hooks]
221 > changegroup = sh -c "printenv.py changegroup"
221 > changegroup = sh -c "printenv.py changegroup"
222 > EOF
222 > EOF
223
223
224 doesn't work (yet ?)
224 doesn't work (yet ?)
225
225
226 hg -R bundle://../full.hg verify
226 hg -R bundle://../full.hg verify
227
227
228 $ hg pull bundle://../full.hg
228 $ hg pull bundle://../full.hg
229 pulling from bundle:../full.hg
229 pulling from bundle:../full.hg
230 requesting all changes
230 requesting all changes
231 adding changesets
231 adding changesets
232 adding manifests
232 adding manifests
233 adding file changes
233 adding file changes
234 added 9 changesets with 7 changes to 4 files (+1 heads)
234 added 9 changesets with 7 changes to 4 files (+1 heads)
235 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=bundle?../full.hg (glob)
235 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=bundle:../full.hg
236 (run 'hg heads' to see heads, 'hg merge' to merge)
236 (run 'hg heads' to see heads, 'hg merge' to merge)
237
237
238 Rollback empty
238 Rollback empty
239
239
240 $ hg rollback
240 $ hg rollback
241 repository tip rolled back to revision -1 (undo pull)
241 repository tip rolled back to revision -1 (undo pull)
242 $ cd ..
242 $ cd ..
243
243
244 Log -R bundle:empty+full.hg
244 Log -R bundle:empty+full.hg
245
245
246 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
246 $ hg -R bundle:empty+full.hg log --template="{rev} "; echo ""
247 8 7 6 5 4 3 2 1 0
247 8 7 6 5 4 3 2 1 0
248
248
249 Pull full.hg into empty again (using -R; with hook)
249 Pull full.hg into empty again (using -R; with hook)
250
250
251 $ hg -R empty pull full.hg
251 $ hg -R empty pull full.hg
252 pulling from full.hg
252 pulling from full.hg
253 requesting all changes
253 requesting all changes
254 adding changesets
254 adding changesets
255 adding manifests
255 adding manifests
256 adding file changes
256 adding file changes
257 added 9 changesets with 7 changes to 4 files (+1 heads)
257 added 9 changesets with 7 changes to 4 files (+1 heads)
258 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=bundle:empty+full.hg (glob)
258 changegroup hook: HG_NODE=f9ee2f85a263049e9ae6d37a0e67e96194ffb735 HG_NODE_LAST=aa35859c02ea8bd48da5da68cd2740ac71afcbaf HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=bundle:empty+full.hg
259 (run 'hg heads' to see heads, 'hg merge' to merge)
259 (run 'hg heads' to see heads, 'hg merge' to merge)
260
260
261 Cannot produce streaming clone bundles with "hg bundle"
261 Cannot produce streaming clone bundles with "hg bundle"
262
262
263 $ hg -R test bundle -t packed1 packed.hg
263 $ hg -R test bundle -t packed1 packed.hg
264 abort: packed bundles cannot be produced by "hg bundle"
264 abort: packed bundles cannot be produced by "hg bundle"
265 (use 'hg debugcreatestreamclonebundle')
265 (use 'hg debugcreatestreamclonebundle')
266 [255]
266 [255]
267
267
268 packed1 is produced properly
268 packed1 is produced properly
269
269
270 $ hg -R test debugcreatestreamclonebundle packed.hg
270 $ hg -R test debugcreatestreamclonebundle packed.hg
271 writing 2664 bytes for 6 files
271 writing 2664 bytes for 6 files
272 bundle requirements: generaldelta, revlogv1
272 bundle requirements: generaldelta, revlogv1
273
273
274 $ f -B 64 --size --sha1 --hexdump packed.hg
274 $ f -B 64 --size --sha1 --hexdump packed.hg
275 packed.hg: size=2827, sha1=9d14cb90c66a21462d915ab33656f38b9deed686
275 packed.hg: size=2827, sha1=9d14cb90c66a21462d915ab33656f38b9deed686
276 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
276 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 06 00 00 |HGS1UN..........|
277 0010: 00 00 00 00 0a 68 00 16 67 65 6e 65 72 61 6c 64 |.....h..generald|
277 0010: 00 00 00 00 0a 68 00 16 67 65 6e 65 72 61 6c 64 |.....h..generald|
278 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 00 64 61 |elta,revlogv1.da|
278 0020: 65 6c 74 61 2c 72 65 76 6c 6f 67 76 31 00 64 61 |elta,revlogv1.da|
279 0030: 74 61 2f 61 64 69 66 66 65 72 65 6e 74 66 69 6c |ta/adifferentfil|
279 0030: 74 61 2f 61 64 69 66 66 65 72 65 6e 74 66 69 6c |ta/adifferentfil|
280
280
281 $ hg debugbundle --spec packed.hg
281 $ hg debugbundle --spec packed.hg
282 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1
282 none-packed1;requirements%3Dgeneraldelta%2Crevlogv1
283
283
284 generaldelta requirement is not listed in stream clone bundles unless used
284 generaldelta requirement is not listed in stream clone bundles unless used
285
285
286 $ hg --config format.usegeneraldelta=false init testnongd
286 $ hg --config format.usegeneraldelta=false init testnongd
287 $ cd testnongd
287 $ cd testnongd
288 $ touch foo
288 $ touch foo
289 $ hg -q commit -A -m initial
289 $ hg -q commit -A -m initial
290 $ cd ..
290 $ cd ..
291 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
291 $ hg -R testnongd debugcreatestreamclonebundle packednongd.hg
292 writing 301 bytes for 3 files
292 writing 301 bytes for 3 files
293 bundle requirements: revlogv1
293 bundle requirements: revlogv1
294
294
295 $ f -B 64 --size --sha1 --hexdump packednongd.hg
295 $ f -B 64 --size --sha1 --hexdump packednongd.hg
296 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
296 packednongd.hg: size=383, sha1=1d9c230238edd5d38907100b729ba72b1831fe6f
297 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
297 0000: 48 47 53 31 55 4e 00 00 00 00 00 00 00 03 00 00 |HGS1UN..........|
298 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
298 0010: 00 00 00 00 01 2d 00 09 72 65 76 6c 6f 67 76 31 |.....-..revlogv1|
299 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
299 0020: 00 64 61 74 61 2f 66 6f 6f 2e 69 00 36 34 0a 00 |.data/foo.i.64..|
300 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
300 0030: 01 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
301
301
302 $ hg debugbundle --spec packednongd.hg
302 $ hg debugbundle --spec packednongd.hg
303 none-packed1;requirements%3Drevlogv1
303 none-packed1;requirements%3Drevlogv1
304
304
305 Unpacking packed1 bundles with "hg unbundle" isn't allowed
305 Unpacking packed1 bundles with "hg unbundle" isn't allowed
306
306
307 $ hg init packed
307 $ hg init packed
308 $ hg -R packed unbundle packed.hg
308 $ hg -R packed unbundle packed.hg
309 abort: packed bundles cannot be applied with "hg unbundle"
309 abort: packed bundles cannot be applied with "hg unbundle"
310 (use "hg debugapplystreamclonebundle")
310 (use "hg debugapplystreamclonebundle")
311 [255]
311 [255]
312
312
313 packed1 can be consumed from debug command
313 packed1 can be consumed from debug command
314
314
315 (this also confirms that streamclone-ed changes are visible via
315 (this also confirms that streamclone-ed changes are visible via
316 @filecache properties to in-process procedures before closing
316 @filecache properties to in-process procedures before closing
317 transaction)
317 transaction)
318
318
319 $ cat > $TESTTMP/showtip.py <<EOF
319 $ cat > $TESTTMP/showtip.py <<EOF
320 > from __future__ import absolute_import
320 > from __future__ import absolute_import
321 >
321 >
322 > def showtip(ui, repo, hooktype, **kwargs):
322 > def showtip(ui, repo, hooktype, **kwargs):
323 > ui.warn('%s: %s\n' % (hooktype, repo['tip'].hex()[:12]))
323 > ui.warn('%s: %s\n' % (hooktype, repo['tip'].hex()[:12]))
324 >
324 >
325 > def reposetup(ui, repo):
325 > def reposetup(ui, repo):
326 > # this confirms (and ensures) that (empty) 00changelog.i
326 > # this confirms (and ensures) that (empty) 00changelog.i
327 > # before streamclone is already cached as repo.changelog
327 > # before streamclone is already cached as repo.changelog
328 > ui.setconfig('hooks', 'pretxnopen.showtip', showtip)
328 > ui.setconfig('hooks', 'pretxnopen.showtip', showtip)
329 >
329 >
330 > # this confirms that streamclone-ed changes are visible to
330 > # this confirms that streamclone-ed changes are visible to
331 > # in-process procedures before closing transaction
331 > # in-process procedures before closing transaction
332 > ui.setconfig('hooks', 'pretxnclose.showtip', showtip)
332 > ui.setconfig('hooks', 'pretxnclose.showtip', showtip)
333 >
333 >
334 > # this confirms that streamclone-ed changes are still visible
334 > # this confirms that streamclone-ed changes are still visible
335 > # after closing transaction
335 > # after closing transaction
336 > ui.setconfig('hooks', 'txnclose.showtip', showtip)
336 > ui.setconfig('hooks', 'txnclose.showtip', showtip)
337 > EOF
337 > EOF
338 $ cat >> $HGRCPATH <<EOF
338 $ cat >> $HGRCPATH <<EOF
339 > [extensions]
339 > [extensions]
340 > showtip = $TESTTMP/showtip.py
340 > showtip = $TESTTMP/showtip.py
341 > EOF
341 > EOF
342
342
343 $ hg -R packed debugapplystreamclonebundle packed.hg
343 $ hg -R packed debugapplystreamclonebundle packed.hg
344 6 files to transfer, 2.60 KB of data
344 6 files to transfer, 2.60 KB of data
345 pretxnopen: 000000000000
345 pretxnopen: 000000000000
346 pretxnclose: aa35859c02ea
346 pretxnclose: aa35859c02ea
347 transferred 2.60 KB in *.* seconds (* */sec) (glob)
347 transferred 2.60 KB in *.* seconds (* */sec) (glob)
348 txnclose: aa35859c02ea
348 txnclose: aa35859c02ea
349
349
350 (for safety, confirm visibility of streamclone-ed changes by another
350 (for safety, confirm visibility of streamclone-ed changes by another
351 process, too)
351 process, too)
352
352
353 $ hg -R packed tip -T "{node|short}\n"
353 $ hg -R packed tip -T "{node|short}\n"
354 aa35859c02ea
354 aa35859c02ea
355
355
356 $ cat >> $HGRCPATH <<EOF
356 $ cat >> $HGRCPATH <<EOF
357 > [extensions]
357 > [extensions]
358 > showtip = !
358 > showtip = !
359 > EOF
359 > EOF
360
360
361 Does not work on non-empty repo
361 Does not work on non-empty repo
362
362
363 $ hg -R packed debugapplystreamclonebundle packed.hg
363 $ hg -R packed debugapplystreamclonebundle packed.hg
364 abort: cannot apply stream clone bundle on non-empty repo
364 abort: cannot apply stream clone bundle on non-empty repo
365 [255]
365 [255]
366
366
367 Create partial clones
367 Create partial clones
368
368
369 $ rm -r empty
369 $ rm -r empty
370 $ hg init empty
370 $ hg init empty
371 $ hg clone -r 3 test partial
371 $ hg clone -r 3 test partial
372 adding changesets
372 adding changesets
373 adding manifests
373 adding manifests
374 adding file changes
374 adding file changes
375 added 4 changesets with 4 changes to 1 files
375 added 4 changesets with 4 changes to 1 files
376 updating to branch default
376 updating to branch default
377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 $ hg clone partial partial2
378 $ hg clone partial partial2
379 updating to branch default
379 updating to branch default
380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
381 $ cd partial
381 $ cd partial
382
382
383 Log -R full.hg in partial
383 Log -R full.hg in partial
384
384
385 $ hg -R bundle://../full.hg log -T phases
385 $ hg -R bundle://../full.hg log -T phases
386 changeset: 8:aa35859c02ea
386 changeset: 8:aa35859c02ea
387 tag: tip
387 tag: tip
388 phase: draft
388 phase: draft
389 parent: 3:eebf5a27f8ca
389 parent: 3:eebf5a27f8ca
390 user: test
390 user: test
391 date: Thu Jan 01 00:00:00 1970 +0000
391 date: Thu Jan 01 00:00:00 1970 +0000
392 summary: 0.3m
392 summary: 0.3m
393
393
394 changeset: 7:a6a34bfa0076
394 changeset: 7:a6a34bfa0076
395 phase: draft
395 phase: draft
396 user: test
396 user: test
397 date: Thu Jan 01 00:00:00 1970 +0000
397 date: Thu Jan 01 00:00:00 1970 +0000
398 summary: 1.3m
398 summary: 1.3m
399
399
400 changeset: 6:7373c1169842
400 changeset: 6:7373c1169842
401 phase: draft
401 phase: draft
402 user: test
402 user: test
403 date: Thu Jan 01 00:00:00 1970 +0000
403 date: Thu Jan 01 00:00:00 1970 +0000
404 summary: 1.3
404 summary: 1.3
405
405
406 changeset: 5:1bb50a9436a7
406 changeset: 5:1bb50a9436a7
407 phase: draft
407 phase: draft
408 user: test
408 user: test
409 date: Thu Jan 01 00:00:00 1970 +0000
409 date: Thu Jan 01 00:00:00 1970 +0000
410 summary: 1.2
410 summary: 1.2
411
411
412 changeset: 4:095197eb4973
412 changeset: 4:095197eb4973
413 phase: draft
413 phase: draft
414 parent: 0:f9ee2f85a263
414 parent: 0:f9ee2f85a263
415 user: test
415 user: test
416 date: Thu Jan 01 00:00:00 1970 +0000
416 date: Thu Jan 01 00:00:00 1970 +0000
417 summary: 1.1
417 summary: 1.1
418
418
419 changeset: 3:eebf5a27f8ca
419 changeset: 3:eebf5a27f8ca
420 phase: public
420 phase: public
421 user: test
421 user: test
422 date: Thu Jan 01 00:00:00 1970 +0000
422 date: Thu Jan 01 00:00:00 1970 +0000
423 summary: 0.3
423 summary: 0.3
424
424
425 changeset: 2:e38ba6f5b7e0
425 changeset: 2:e38ba6f5b7e0
426 phase: public
426 phase: public
427 user: test
427 user: test
428 date: Thu Jan 01 00:00:00 1970 +0000
428 date: Thu Jan 01 00:00:00 1970 +0000
429 summary: 0.2
429 summary: 0.2
430
430
431 changeset: 1:34c2bf6b0626
431 changeset: 1:34c2bf6b0626
432 phase: public
432 phase: public
433 user: test
433 user: test
434 date: Thu Jan 01 00:00:00 1970 +0000
434 date: Thu Jan 01 00:00:00 1970 +0000
435 summary: 0.1
435 summary: 0.1
436
436
437 changeset: 0:f9ee2f85a263
437 changeset: 0:f9ee2f85a263
438 phase: public
438 phase: public
439 user: test
439 user: test
440 date: Thu Jan 01 00:00:00 1970 +0000
440 date: Thu Jan 01 00:00:00 1970 +0000
441 summary: 0.0
441 summary: 0.0
442
442
443
443
444 Incoming full.hg in partial
444 Incoming full.hg in partial
445
445
446 $ hg incoming bundle://../full.hg
446 $ hg incoming bundle://../full.hg
447 comparing with bundle:../full.hg
447 comparing with bundle:../full.hg
448 searching for changes
448 searching for changes
449 changeset: 4:095197eb4973
449 changeset: 4:095197eb4973
450 parent: 0:f9ee2f85a263
450 parent: 0:f9ee2f85a263
451 user: test
451 user: test
452 date: Thu Jan 01 00:00:00 1970 +0000
452 date: Thu Jan 01 00:00:00 1970 +0000
453 summary: 1.1
453 summary: 1.1
454
454
455 changeset: 5:1bb50a9436a7
455 changeset: 5:1bb50a9436a7
456 user: test
456 user: test
457 date: Thu Jan 01 00:00:00 1970 +0000
457 date: Thu Jan 01 00:00:00 1970 +0000
458 summary: 1.2
458 summary: 1.2
459
459
460 changeset: 6:7373c1169842
460 changeset: 6:7373c1169842
461 user: test
461 user: test
462 date: Thu Jan 01 00:00:00 1970 +0000
462 date: Thu Jan 01 00:00:00 1970 +0000
463 summary: 1.3
463 summary: 1.3
464
464
465 changeset: 7:a6a34bfa0076
465 changeset: 7:a6a34bfa0076
466 user: test
466 user: test
467 date: Thu Jan 01 00:00:00 1970 +0000
467 date: Thu Jan 01 00:00:00 1970 +0000
468 summary: 1.3m
468 summary: 1.3m
469
469
470 changeset: 8:aa35859c02ea
470 changeset: 8:aa35859c02ea
471 tag: tip
471 tag: tip
472 parent: 3:eebf5a27f8ca
472 parent: 3:eebf5a27f8ca
473 user: test
473 user: test
474 date: Thu Jan 01 00:00:00 1970 +0000
474 date: Thu Jan 01 00:00:00 1970 +0000
475 summary: 0.3m
475 summary: 0.3m
476
476
477
477
478 Outgoing -R full.hg vs partial2 in partial
478 Outgoing -R full.hg vs partial2 in partial
479
479
480 $ hg -R bundle://../full.hg outgoing ../partial2
480 $ hg -R bundle://../full.hg outgoing ../partial2
481 comparing with ../partial2
481 comparing with ../partial2
482 searching for changes
482 searching for changes
483 changeset: 4:095197eb4973
483 changeset: 4:095197eb4973
484 parent: 0:f9ee2f85a263
484 parent: 0:f9ee2f85a263
485 user: test
485 user: test
486 date: Thu Jan 01 00:00:00 1970 +0000
486 date: Thu Jan 01 00:00:00 1970 +0000
487 summary: 1.1
487 summary: 1.1
488
488
489 changeset: 5:1bb50a9436a7
489 changeset: 5:1bb50a9436a7
490 user: test
490 user: test
491 date: Thu Jan 01 00:00:00 1970 +0000
491 date: Thu Jan 01 00:00:00 1970 +0000
492 summary: 1.2
492 summary: 1.2
493
493
494 changeset: 6:7373c1169842
494 changeset: 6:7373c1169842
495 user: test
495 user: test
496 date: Thu Jan 01 00:00:00 1970 +0000
496 date: Thu Jan 01 00:00:00 1970 +0000
497 summary: 1.3
497 summary: 1.3
498
498
499 changeset: 7:a6a34bfa0076
499 changeset: 7:a6a34bfa0076
500 user: test
500 user: test
501 date: Thu Jan 01 00:00:00 1970 +0000
501 date: Thu Jan 01 00:00:00 1970 +0000
502 summary: 1.3m
502 summary: 1.3m
503
503
504 changeset: 8:aa35859c02ea
504 changeset: 8:aa35859c02ea
505 tag: tip
505 tag: tip
506 parent: 3:eebf5a27f8ca
506 parent: 3:eebf5a27f8ca
507 user: test
507 user: test
508 date: Thu Jan 01 00:00:00 1970 +0000
508 date: Thu Jan 01 00:00:00 1970 +0000
509 summary: 0.3m
509 summary: 0.3m
510
510
511
511
512 Outgoing -R does-not-exist.hg vs partial2 in partial
512 Outgoing -R does-not-exist.hg vs partial2 in partial
513
513
514 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
514 $ hg -R bundle://../does-not-exist.hg outgoing ../partial2
515 abort: *../does-not-exist.hg* (glob)
515 abort: *../does-not-exist.hg* (glob)
516 [255]
516 [255]
517 $ cd ..
517 $ cd ..
518
518
519 hide outer repo
519 hide outer repo
520 $ hg init
520 $ hg init
521
521
522 Direct clone from bundle (all-history)
522 Direct clone from bundle (all-history)
523
523
524 $ hg clone full.hg full-clone
524 $ hg clone full.hg full-clone
525 requesting all changes
525 requesting all changes
526 adding changesets
526 adding changesets
527 adding manifests
527 adding manifests
528 adding file changes
528 adding file changes
529 added 9 changesets with 7 changes to 4 files (+1 heads)
529 added 9 changesets with 7 changes to 4 files (+1 heads)
530 updating to branch default
530 updating to branch default
531 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
532 $ hg -R full-clone heads
532 $ hg -R full-clone heads
533 changeset: 8:aa35859c02ea
533 changeset: 8:aa35859c02ea
534 tag: tip
534 tag: tip
535 parent: 3:eebf5a27f8ca
535 parent: 3:eebf5a27f8ca
536 user: test
536 user: test
537 date: Thu Jan 01 00:00:00 1970 +0000
537 date: Thu Jan 01 00:00:00 1970 +0000
538 summary: 0.3m
538 summary: 0.3m
539
539
540 changeset: 7:a6a34bfa0076
540 changeset: 7:a6a34bfa0076
541 user: test
541 user: test
542 date: Thu Jan 01 00:00:00 1970 +0000
542 date: Thu Jan 01 00:00:00 1970 +0000
543 summary: 1.3m
543 summary: 1.3m
544
544
545 $ rm -r full-clone
545 $ rm -r full-clone
546
546
547 When cloning from a non-copiable repository into '', do not
547 When cloning from a non-copiable repository into '', do not
548 recurse infinitely (issue2528)
548 recurse infinitely (issue2528)
549
549
550 $ hg clone full.hg ''
550 $ hg clone full.hg ''
551 abort: empty destination path is not valid
551 abort: empty destination path is not valid
552 [255]
552 [255]
553
553
554 test for https://bz.mercurial-scm.org/216
554 test for https://bz.mercurial-scm.org/216
555
555
556 Unbundle incremental bundles into fresh empty in one go
556 Unbundle incremental bundles into fresh empty in one go
557
557
558 $ rm -r empty
558 $ rm -r empty
559 $ hg init empty
559 $ hg init empty
560 $ hg -R test bundle --base null -r 0 ../0.hg
560 $ hg -R test bundle --base null -r 0 ../0.hg
561 1 changesets found
561 1 changesets found
562 $ hg -R test bundle --base 0 -r 1 ../1.hg
562 $ hg -R test bundle --base 0 -r 1 ../1.hg
563 1 changesets found
563 1 changesets found
564 $ hg -R empty unbundle -u ../0.hg ../1.hg
564 $ hg -R empty unbundle -u ../0.hg ../1.hg
565 adding changesets
565 adding changesets
566 adding manifests
566 adding manifests
567 adding file changes
567 adding file changes
568 added 1 changesets with 1 changes to 1 files
568 added 1 changesets with 1 changes to 1 files
569 adding changesets
569 adding changesets
570 adding manifests
570 adding manifests
571 adding file changes
571 adding file changes
572 added 1 changesets with 1 changes to 1 files
572 added 1 changesets with 1 changes to 1 files
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
573 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
574
574
575 View full contents of the bundle
575 View full contents of the bundle
576 $ hg -R test bundle --base null -r 3 ../partial.hg
576 $ hg -R test bundle --base null -r 3 ../partial.hg
577 4 changesets found
577 4 changesets found
578 $ cd test
578 $ cd test
579 $ hg -R ../../partial.hg log -r "bundle()"
579 $ hg -R ../../partial.hg log -r "bundle()"
580 changeset: 0:f9ee2f85a263
580 changeset: 0:f9ee2f85a263
581 user: test
581 user: test
582 date: Thu Jan 01 00:00:00 1970 +0000
582 date: Thu Jan 01 00:00:00 1970 +0000
583 summary: 0.0
583 summary: 0.0
584
584
585 changeset: 1:34c2bf6b0626
585 changeset: 1:34c2bf6b0626
586 user: test
586 user: test
587 date: Thu Jan 01 00:00:00 1970 +0000
587 date: Thu Jan 01 00:00:00 1970 +0000
588 summary: 0.1
588 summary: 0.1
589
589
590 changeset: 2:e38ba6f5b7e0
590 changeset: 2:e38ba6f5b7e0
591 user: test
591 user: test
592 date: Thu Jan 01 00:00:00 1970 +0000
592 date: Thu Jan 01 00:00:00 1970 +0000
593 summary: 0.2
593 summary: 0.2
594
594
595 changeset: 3:eebf5a27f8ca
595 changeset: 3:eebf5a27f8ca
596 user: test
596 user: test
597 date: Thu Jan 01 00:00:00 1970 +0000
597 date: Thu Jan 01 00:00:00 1970 +0000
598 summary: 0.3
598 summary: 0.3
599
599
600 $ cd ..
600 $ cd ..
601
601
602 test for 540d1059c802
602 test for 540d1059c802
603
603
604 test for 540d1059c802
604 test for 540d1059c802
605
605
606 $ hg init orig
606 $ hg init orig
607 $ cd orig
607 $ cd orig
608 $ echo foo > foo
608 $ echo foo > foo
609 $ hg add foo
609 $ hg add foo
610 $ hg ci -m 'add foo'
610 $ hg ci -m 'add foo'
611
611
612 $ hg clone . ../copy
612 $ hg clone . ../copy
613 updating to branch default
613 updating to branch default
614 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
614 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
615 $ hg tag foo
615 $ hg tag foo
616
616
617 $ cd ../copy
617 $ cd ../copy
618 $ echo >> foo
618 $ echo >> foo
619 $ hg ci -m 'change foo'
619 $ hg ci -m 'change foo'
620 $ hg bundle ../bundle.hg ../orig
620 $ hg bundle ../bundle.hg ../orig
621 searching for changes
621 searching for changes
622 1 changesets found
622 1 changesets found
623
623
624 $ cd ../orig
624 $ cd ../orig
625 $ hg incoming ../bundle.hg
625 $ hg incoming ../bundle.hg
626 comparing with ../bundle.hg
626 comparing with ../bundle.hg
627 searching for changes
627 searching for changes
628 changeset: 2:ed1b79f46b9a
628 changeset: 2:ed1b79f46b9a
629 tag: tip
629 tag: tip
630 parent: 0:bbd179dfa0a7
630 parent: 0:bbd179dfa0a7
631 user: test
631 user: test
632 date: Thu Jan 01 00:00:00 1970 +0000
632 date: Thu Jan 01 00:00:00 1970 +0000
633 summary: change foo
633 summary: change foo
634
634
635 $ cd ..
635 $ cd ..
636
636
637 test bundle with # in the filename (issue2154):
637 test bundle with # in the filename (issue2154):
638
638
639 $ cp bundle.hg 'test#bundle.hg'
639 $ cp bundle.hg 'test#bundle.hg'
640 $ cd orig
640 $ cd orig
641 $ hg incoming '../test#bundle.hg'
641 $ hg incoming '../test#bundle.hg'
642 comparing with ../test
642 comparing with ../test
643 abort: unknown revision 'bundle.hg'!
643 abort: unknown revision 'bundle.hg'!
644 [255]
644 [255]
645
645
646 note that percent encoding is not handled:
646 note that percent encoding is not handled:
647
647
648 $ hg incoming ../test%23bundle.hg
648 $ hg incoming ../test%23bundle.hg
649 abort: repository ../test%23bundle.hg not found!
649 abort: repository ../test%23bundle.hg not found!
650 [255]
650 [255]
651 $ cd ..
651 $ cd ..
652
652
653 test to bundle revisions on the newly created branch (issue3828):
653 test to bundle revisions on the newly created branch (issue3828):
654
654
655 $ hg -q clone -U test test-clone
655 $ hg -q clone -U test test-clone
656 $ cd test
656 $ cd test
657
657
658 $ hg -q branch foo
658 $ hg -q branch foo
659 $ hg commit -m "create foo branch"
659 $ hg commit -m "create foo branch"
660 $ hg -q outgoing ../test-clone
660 $ hg -q outgoing ../test-clone
661 9:b4f5acb1ee27
661 9:b4f5acb1ee27
662 $ hg -q bundle --branch foo foo.hg ../test-clone
662 $ hg -q bundle --branch foo foo.hg ../test-clone
663 $ hg -R foo.hg -q log -r "bundle()"
663 $ hg -R foo.hg -q log -r "bundle()"
664 9:b4f5acb1ee27
664 9:b4f5acb1ee27
665
665
666 $ cd ..
666 $ cd ..
667
667
668 test for https://bz.mercurial-scm.org/1144
668 test for https://bz.mercurial-scm.org/1144
669
669
670 test that verify bundle does not traceback
670 test that verify bundle does not traceback
671
671
672 partial history bundle, fails w/ unknown parent
672 partial history bundle, fails w/ unknown parent
673
673
674 $ hg -R bundle.hg verify
674 $ hg -R bundle.hg verify
675 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
675 abort: 00changelog.i@bbd179dfa0a7: unknown parent!
676 [255]
676 [255]
677
677
678 full history bundle, refuses to verify non-local repo
678 full history bundle, refuses to verify non-local repo
679
679
680 $ hg -R all.hg verify
680 $ hg -R all.hg verify
681 abort: cannot verify bundle or remote repos
681 abort: cannot verify bundle or remote repos
682 [255]
682 [255]
683
683
684 but, regular verify must continue to work
684 but, regular verify must continue to work
685
685
686 $ hg -R orig verify
686 $ hg -R orig verify
687 checking changesets
687 checking changesets
688 checking manifests
688 checking manifests
689 crosschecking files in changesets and manifests
689 crosschecking files in changesets and manifests
690 checking files
690 checking files
691 2 files, 2 changesets, 2 total revisions
691 2 files, 2 changesets, 2 total revisions
692
692
693 diff against bundle
693 diff against bundle
694
694
695 $ hg init b
695 $ hg init b
696 $ cd b
696 $ cd b
697 $ hg -R ../all.hg diff -r tip
697 $ hg -R ../all.hg diff -r tip
698 diff -r aa35859c02ea anotherfile
698 diff -r aa35859c02ea anotherfile
699 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
699 --- a/anotherfile Thu Jan 01 00:00:00 1970 +0000
700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
701 @@ -1,4 +0,0 @@
701 @@ -1,4 +0,0 @@
702 -0
702 -0
703 -1
703 -1
704 -2
704 -2
705 -3
705 -3
706 $ cd ..
706 $ cd ..
707
707
708 bundle single branch
708 bundle single branch
709
709
710 $ hg init branchy
710 $ hg init branchy
711 $ cd branchy
711 $ cd branchy
712 $ echo a >a
712 $ echo a >a
713 $ echo x >x
713 $ echo x >x
714 $ hg ci -Ama
714 $ hg ci -Ama
715 adding a
715 adding a
716 adding x
716 adding x
717 $ echo c >c
717 $ echo c >c
718 $ echo xx >x
718 $ echo xx >x
719 $ hg ci -Amc
719 $ hg ci -Amc
720 adding c
720 adding c
721 $ echo c1 >c1
721 $ echo c1 >c1
722 $ hg ci -Amc1
722 $ hg ci -Amc1
723 adding c1
723 adding c1
724 $ hg up 0
724 $ hg up 0
725 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
725 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
726 $ echo b >b
726 $ echo b >b
727 $ hg ci -Amb
727 $ hg ci -Amb
728 adding b
728 adding b
729 created new head
729 created new head
730 $ echo b1 >b1
730 $ echo b1 >b1
731 $ echo xx >x
731 $ echo xx >x
732 $ hg ci -Amb1
732 $ hg ci -Amb1
733 adding b1
733 adding b1
734 $ hg clone -q -r2 . part
734 $ hg clone -q -r2 . part
735
735
736 == bundling via incoming
736 == bundling via incoming
737
737
738 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
738 $ hg in -R part --bundle incoming.hg --template "{node}\n" .
739 comparing with .
739 comparing with .
740 searching for changes
740 searching for changes
741 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
741 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
742 057f4db07f61970e1c11e83be79e9d08adc4dc31
742 057f4db07f61970e1c11e83be79e9d08adc4dc31
743
743
744 == bundling
744 == bundling
745
745
746 $ hg bundle bundle.hg part --debug --config progress.debug=true
746 $ hg bundle bundle.hg part --debug --config progress.debug=true
747 query 1; heads
747 query 1; heads
748 searching for changes
748 searching for changes
749 all remote heads known locally
749 all remote heads known locally
750 2 changesets found
750 2 changesets found
751 list of changesets:
751 list of changesets:
752 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
752 1a38c1b849e8b70c756d2d80b0b9a3ac0b7ea11a
753 057f4db07f61970e1c11e83be79e9d08adc4dc31
753 057f4db07f61970e1c11e83be79e9d08adc4dc31
754 bundle2-output-bundle: "HG20", (1 params) 1 parts total
754 bundle2-output-bundle: "HG20", (1 params) 1 parts total
755 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
755 bundle2-output-part: "changegroup" (params: 1 mandatory 1 advisory) streamed payload
756 bundling: 1/2 changesets (50.00%)
756 bundling: 1/2 changesets (50.00%)
757 bundling: 2/2 changesets (100.00%)
757 bundling: 2/2 changesets (100.00%)
758 bundling: 1/2 manifests (50.00%)
758 bundling: 1/2 manifests (50.00%)
759 bundling: 2/2 manifests (100.00%)
759 bundling: 2/2 manifests (100.00%)
760 bundling: b 1/3 files (33.33%)
760 bundling: b 1/3 files (33.33%)
761 bundling: b1 2/3 files (66.67%)
761 bundling: b1 2/3 files (66.67%)
762 bundling: x 3/3 files (100.00%)
762 bundling: x 3/3 files (100.00%)
763
763
764 == Test for issue3441
764 == Test for issue3441
765
765
766 $ hg clone -q -r0 . part2
766 $ hg clone -q -r0 . part2
767 $ hg -q -R part2 pull bundle.hg
767 $ hg -q -R part2 pull bundle.hg
768 $ hg -R part2 verify
768 $ hg -R part2 verify
769 checking changesets
769 checking changesets
770 checking manifests
770 checking manifests
771 crosschecking files in changesets and manifests
771 crosschecking files in changesets and manifests
772 checking files
772 checking files
773 4 files, 3 changesets, 5 total revisions
773 4 files, 3 changesets, 5 total revisions
774
774
775 == Test bundling no commits
775 == Test bundling no commits
776
776
777 $ hg bundle -r 'public()' no-output.hg
777 $ hg bundle -r 'public()' no-output.hg
778 abort: no commits to bundle
778 abort: no commits to bundle
779 [255]
779 [255]
780
780
781 $ cd ..
781 $ cd ..
782
782
783 When user merges to the revision existing only in the bundle,
783 When user merges to the revision existing only in the bundle,
784 it should show warning that second parent of the working
784 it should show warning that second parent of the working
785 directory does not exist
785 directory does not exist
786
786
787 $ hg init update2bundled
787 $ hg init update2bundled
788 $ cd update2bundled
788 $ cd update2bundled
789 $ cat <<EOF >> .hg/hgrc
789 $ cat <<EOF >> .hg/hgrc
790 > [extensions]
790 > [extensions]
791 > strip =
791 > strip =
792 > EOF
792 > EOF
793 $ echo "aaa" >> a
793 $ echo "aaa" >> a
794 $ hg commit -A -m 0
794 $ hg commit -A -m 0
795 adding a
795 adding a
796 $ echo "bbb" >> b
796 $ echo "bbb" >> b
797 $ hg commit -A -m 1
797 $ hg commit -A -m 1
798 adding b
798 adding b
799 $ echo "ccc" >> c
799 $ echo "ccc" >> c
800 $ hg commit -A -m 2
800 $ hg commit -A -m 2
801 adding c
801 adding c
802 $ hg update -r 1
802 $ hg update -r 1
803 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
803 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
804 $ echo "ddd" >> d
804 $ echo "ddd" >> d
805 $ hg commit -A -m 3
805 $ hg commit -A -m 3
806 adding d
806 adding d
807 created new head
807 created new head
808 $ hg update -r 2
808 $ hg update -r 2
809 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
809 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
810 $ hg log -G
810 $ hg log -G
811 o changeset: 3:8bd3e1f196af
811 o changeset: 3:8bd3e1f196af
812 | tag: tip
812 | tag: tip
813 | parent: 1:a01eca7af26d
813 | parent: 1:a01eca7af26d
814 | user: test
814 | user: test
815 | date: Thu Jan 01 00:00:00 1970 +0000
815 | date: Thu Jan 01 00:00:00 1970 +0000
816 | summary: 3
816 | summary: 3
817 |
817 |
818 | @ changeset: 2:4652c276ac4f
818 | @ changeset: 2:4652c276ac4f
819 |/ user: test
819 |/ user: test
820 | date: Thu Jan 01 00:00:00 1970 +0000
820 | date: Thu Jan 01 00:00:00 1970 +0000
821 | summary: 2
821 | summary: 2
822 |
822 |
823 o changeset: 1:a01eca7af26d
823 o changeset: 1:a01eca7af26d
824 | user: test
824 | user: test
825 | date: Thu Jan 01 00:00:00 1970 +0000
825 | date: Thu Jan 01 00:00:00 1970 +0000
826 | summary: 1
826 | summary: 1
827 |
827 |
828 o changeset: 0:4fe08cd4693e
828 o changeset: 0:4fe08cd4693e
829 user: test
829 user: test
830 date: Thu Jan 01 00:00:00 1970 +0000
830 date: Thu Jan 01 00:00:00 1970 +0000
831 summary: 0
831 summary: 0
832
832
833 $ hg bundle --base 1 -r 3 ../update2bundled.hg
833 $ hg bundle --base 1 -r 3 ../update2bundled.hg
834 1 changesets found
834 1 changesets found
835 $ hg strip -r 3
835 $ hg strip -r 3
836 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg (glob)
836 saved backup bundle to $TESTTMP/update2bundled/.hg/strip-backup/8bd3e1f196af-017e56d8-backup.hg (glob)
837 $ hg merge -R ../update2bundled.hg -r 3
837 $ hg merge -R ../update2bundled.hg -r 3
838 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
838 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
839 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
840 (branch merge, don't forget to commit)
840 (branch merge, don't forget to commit)
841
841
842 When user updates to the revision existing only in the bundle,
842 When user updates to the revision existing only in the bundle,
843 it should show warning
843 it should show warning
844
844
845 $ hg update -R ../update2bundled.hg --clean -r 3
845 $ hg update -R ../update2bundled.hg --clean -r 3
846 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
846 setting parent to node 8bd3e1f196af289b2b121be08031e76d7ae92098 that only exists in the bundle
847 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
847 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
848
848
849 When user updates to the revision existing in the local repository
849 When user updates to the revision existing in the local repository
850 the warning shouldn't be emitted
850 the warning shouldn't be emitted
851
851
852 $ hg update -R ../update2bundled.hg -r 0
852 $ hg update -R ../update2bundled.hg -r 0
853 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
853 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
@@ -1,1136 +1,1136 b''
1 Test exchange of common information using bundle2
1 Test exchange of common information using bundle2
2
2
3
3
4 $ getmainid() {
4 $ getmainid() {
5 > hg -R main log --template '{node}\n' --rev "$1"
5 > hg -R main log --template '{node}\n' --rev "$1"
6 > }
6 > }
7
7
8 enable obsolescence
8 enable obsolescence
9
9
10 $ cp $HGRCPATH $TESTTMP/hgrc.orig
10 $ cp $HGRCPATH $TESTTMP/hgrc.orig
11 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
11 $ cat > $TESTTMP/bundle2-pushkey-hook.sh << EOF
12 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
12 > echo pushkey: lock state after \"\$HG_NAMESPACE\"
13 > hg debuglock
13 > hg debuglock
14 > EOF
14 > EOF
15
15
16 $ cat >> $HGRCPATH << EOF
16 $ cat >> $HGRCPATH << EOF
17 > [experimental]
17 > [experimental]
18 > evolution=createmarkers,exchange
18 > evolution=createmarkers,exchange
19 > bundle2-output-capture=True
19 > bundle2-output-capture=True
20 > [ui]
20 > [ui]
21 > ssh=python "$TESTDIR/dummyssh"
21 > ssh=python "$TESTDIR/dummyssh"
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
22 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
23 > [web]
23 > [web]
24 > push_ssl = false
24 > push_ssl = false
25 > allow_push = *
25 > allow_push = *
26 > [phases]
26 > [phases]
27 > publish=False
27 > publish=False
28 > [hooks]
28 > [hooks]
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
29 > pretxnclose.tip = hg log -r tip -T "pre-close-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
30 > txnclose.tip = hg log -r tip -T "postclose-tip:{node|short} {phase} {bookmarks}\n"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
31 > txnclose.env = sh -c "HG_LOCAL= printenv.py txnclose"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
32 > pushkey= sh "$TESTTMP/bundle2-pushkey-hook.sh"
33 > EOF
33 > EOF
34
34
35 The extension requires a repo (currently unused)
35 The extension requires a repo (currently unused)
36
36
37 $ hg init main
37 $ hg init main
38 $ cd main
38 $ cd main
39 $ touch a
39 $ touch a
40 $ hg add a
40 $ hg add a
41 $ hg commit -m 'a'
41 $ hg commit -m 'a'
42 pre-close-tip:3903775176ed draft
42 pre-close-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
43 postclose-tip:3903775176ed draft
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
44 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
45
45
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
46 $ hg unbundle $TESTDIR/bundles/rebase.hg
47 adding changesets
47 adding changesets
48 adding manifests
48 adding manifests
49 adding file changes
49 adding file changes
50 added 8 changesets with 7 changes to 7 files (+3 heads)
50 added 8 changesets with 7 changes to 7 files (+3 heads)
51 pre-close-tip:02de42196ebe draft
51 pre-close-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
52 postclose-tip:02de42196ebe draft
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:* HG_TXNNAME=unbundle (glob)
53 txnclose hook: HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=unbundle HG_TXNID=TXN:$ID$ HG_TXNNAME=unbundle
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
54 bundle:*/tests/bundles/rebase.hg HG_URL=bundle:*/tests/bundles/rebase.hg (glob)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
55 (run 'hg heads' to see heads, 'hg merge' to merge)
56
56
57 $ cd ..
57 $ cd ..
58
58
59 Real world exchange
59 Real world exchange
60 =====================
60 =====================
61
61
62 Add more obsolescence information
62 Add more obsolescence information
63
63
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
64 $ hg -R main debugobsolete -d '0 0' 1111111111111111111111111111111111111111 `getmainid 9520eea781bc`
65 pre-close-tip:02de42196ebe draft
65 pre-close-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
66 postclose-tip:02de42196ebe draft
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
67 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
68 $ hg -R main debugobsolete -d '0 0' 2222222222222222222222222222222222222222 `getmainid 24b6387c8c8c`
69 pre-close-tip:02de42196ebe draft
69 pre-close-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
70 postclose-tip:02de42196ebe draft
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
71 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
72
72
73 clone --pull
73 clone --pull
74
74
75 $ hg -R main phase --public cd010b8cd998
75 $ hg -R main phase --public cd010b8cd998
76 pre-close-tip:02de42196ebe draft
76 pre-close-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
77 postclose-tip:02de42196ebe draft
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
78 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
79 $ hg clone main other --pull --rev 9520eea781bc
79 $ hg clone main other --pull --rev 9520eea781bc
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 2 changesets with 2 changes to 2 files
83 added 2 changesets with 2 changes to 2 files
84 1 new obsolescence markers
84 1 new obsolescence markers
85 pre-close-tip:9520eea781bc draft
85 pre-close-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
86 postclose-tip:9520eea781bc draft
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
87 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=cd010b8cd998f3981a5a8115f94f8da4ab506089 HG_NODE_LAST=9520eea781bcca16c1e15acc0ba14335a0e8e5ba HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
88 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
89 updating to branch default
89 updating to branch default
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 $ hg -R other log -G
91 $ hg -R other log -G
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
92 @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
93 |
93 |
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
94 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
95
95
96 $ hg -R other debugobsolete
96 $ hg -R other debugobsolete
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
97 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
98
98
99 pull
99 pull
100
100
101 $ hg -R main phase --public 9520eea781bc
101 $ hg -R main phase --public 9520eea781bc
102 pre-close-tip:02de42196ebe draft
102 pre-close-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
103 postclose-tip:02de42196ebe draft
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
104 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
105 $ hg -R other pull -r 24b6387c8c8c
105 $ hg -R other pull -r 24b6387c8c8c
106 pulling from $TESTTMP/main (glob)
106 pulling from $TESTTMP/main (glob)
107 searching for changes
107 searching for changes
108 adding changesets
108 adding changesets
109 adding manifests
109 adding manifests
110 adding file changes
110 adding file changes
111 added 1 changesets with 1 changes to 1 files (+1 heads)
111 added 1 changesets with 1 changes to 1 files (+1 heads)
112 1 new obsolescence markers
112 1 new obsolescence markers
113 pre-close-tip:24b6387c8c8c draft
113 pre-close-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
114 postclose-tip:24b6387c8c8c draft
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
115 txnclose hook: HG_NEW_OBSMARKERS=1 HG_NODE=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_NODE_LAST=24b6387c8c8cae37178880f3fa95ded3cb1cf785 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
116 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
117 (run 'hg heads' to see heads, 'hg merge' to merge)
118 $ hg -R other log -G
118 $ hg -R other log -G
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
119 o 2:24b6387c8c8c draft Nicolas Dumazet <nicdumz.commits@gmail.com> F
120 |
120 |
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
121 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
122 |/
122 |/
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
123 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
124
124
125 $ hg -R other debugobsolete
125 $ hg -R other debugobsolete
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
126 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
127 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
128
128
129 pull empty (with phase movement)
129 pull empty (with phase movement)
130
130
131 $ hg -R main phase --public 24b6387c8c8c
131 $ hg -R main phase --public 24b6387c8c8c
132 pre-close-tip:02de42196ebe draft
132 pre-close-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
133 postclose-tip:02de42196ebe draft
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
134 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
135 $ hg -R other pull -r 24b6387c8c8c
135 $ hg -R other pull -r 24b6387c8c8c
136 pulling from $TESTTMP/main (glob)
136 pulling from $TESTTMP/main (glob)
137 no changes found
137 no changes found
138 pre-close-tip:24b6387c8c8c public
138 pre-close-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
139 postclose-tip:24b6387c8c8c public
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
140 txnclose hook: HG_NEW_OBSMARKERS=0 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
141 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
142 $ hg -R other log -G
142 $ hg -R other log -G
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
143 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
144 |
144 |
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
145 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
146 |/
146 |/
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
147 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
148
148
149 $ hg -R other debugobsolete
149 $ hg -R other debugobsolete
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
150 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
151 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
152
152
153 pull empty
153 pull empty
154
154
155 $ hg -R other pull -r 24b6387c8c8c
155 $ hg -R other pull -r 24b6387c8c8c
156 pulling from $TESTTMP/main (glob)
156 pulling from $TESTTMP/main (glob)
157 no changes found
157 no changes found
158 pre-close-tip:24b6387c8c8c public
158 pre-close-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
159 postclose-tip:24b6387c8c8c public
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
160 txnclose hook: HG_NEW_OBSMARKERS=0 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
161 file:/*/$TESTTMP/main HG_URL=file:$TESTTMP/main (glob)
162 $ hg -R other log -G
162 $ hg -R other log -G
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
163 o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
164 |
164 |
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
165 | @ 1:9520eea781bc draft Nicolas Dumazet <nicdumz.commits@gmail.com> E
166 |/
166 |/
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
167 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
168
168
169 $ hg -R other debugobsolete
169 $ hg -R other debugobsolete
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
170 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
171 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
172
172
173 add extra data to test their exchange during push
173 add extra data to test their exchange during push
174
174
175 $ hg -R main bookmark --rev eea13746799a book_eea1
175 $ hg -R main bookmark --rev eea13746799a book_eea1
176 pre-close-tip:02de42196ebe draft
176 pre-close-tip:02de42196ebe draft
177 postclose-tip:02de42196ebe draft
177 postclose-tip:02de42196ebe draft
178 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
178 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
179 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
179 $ hg -R main debugobsolete -d '0 0' 3333333333333333333333333333333333333333 `getmainid eea13746799a`
180 pre-close-tip:02de42196ebe draft
180 pre-close-tip:02de42196ebe draft
181 postclose-tip:02de42196ebe draft
181 postclose-tip:02de42196ebe draft
182 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
182 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
183 $ hg -R main bookmark --rev 02de42196ebe book_02de
183 $ hg -R main bookmark --rev 02de42196ebe book_02de
184 pre-close-tip:02de42196ebe draft book_02de
184 pre-close-tip:02de42196ebe draft book_02de
185 postclose-tip:02de42196ebe draft book_02de
185 postclose-tip:02de42196ebe draft book_02de
186 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
186 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
187 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
187 $ hg -R main debugobsolete -d '0 0' 4444444444444444444444444444444444444444 `getmainid 02de42196ebe`
188 pre-close-tip:02de42196ebe draft book_02de
188 pre-close-tip:02de42196ebe draft book_02de
189 postclose-tip:02de42196ebe draft book_02de
189 postclose-tip:02de42196ebe draft book_02de
190 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
190 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
191 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
191 $ hg -R main bookmark --rev 42ccdea3bb16 book_42cc
192 pre-close-tip:02de42196ebe draft book_02de
192 pre-close-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
193 postclose-tip:02de42196ebe draft book_02de
194 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
194 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
195 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
195 $ hg -R main debugobsolete -d '0 0' 5555555555555555555555555555555555555555 `getmainid 42ccdea3bb16`
196 pre-close-tip:02de42196ebe draft book_02de
196 pre-close-tip:02de42196ebe draft book_02de
197 postclose-tip:02de42196ebe draft book_02de
197 postclose-tip:02de42196ebe draft book_02de
198 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
198 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
199 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
199 $ hg -R main bookmark --rev 5fddd98957c8 book_5fdd
200 pre-close-tip:02de42196ebe draft book_02de
200 pre-close-tip:02de42196ebe draft book_02de
201 postclose-tip:02de42196ebe draft book_02de
201 postclose-tip:02de42196ebe draft book_02de
202 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
202 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
203 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
203 $ hg -R main debugobsolete -d '0 0' 6666666666666666666666666666666666666666 `getmainid 5fddd98957c8`
204 pre-close-tip:02de42196ebe draft book_02de
204 pre-close-tip:02de42196ebe draft book_02de
205 postclose-tip:02de42196ebe draft book_02de
205 postclose-tip:02de42196ebe draft book_02de
206 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
206 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
207 $ hg -R main bookmark --rev 32af7686d403 book_32af
207 $ hg -R main bookmark --rev 32af7686d403 book_32af
208 pre-close-tip:02de42196ebe draft book_02de
208 pre-close-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
209 postclose-tip:02de42196ebe draft book_02de
210 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
210 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
211 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
211 $ hg -R main debugobsolete -d '0 0' 7777777777777777777777777777777777777777 `getmainid 32af7686d403`
212 pre-close-tip:02de42196ebe draft book_02de
212 pre-close-tip:02de42196ebe draft book_02de
213 postclose-tip:02de42196ebe draft book_02de
213 postclose-tip:02de42196ebe draft book_02de
214 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:* HG_TXNNAME=debugobsolete (glob)
214 txnclose hook: HG_NEW_OBSMARKERS=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=debugobsolete
215
215
216 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
216 $ hg -R other bookmark --rev cd010b8cd998 book_eea1
217 pre-close-tip:24b6387c8c8c public
217 pre-close-tip:24b6387c8c8c public
218 postclose-tip:24b6387c8c8c public
218 postclose-tip:24b6387c8c8c public
219 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
219 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
220 $ hg -R other bookmark --rev cd010b8cd998 book_02de
220 $ hg -R other bookmark --rev cd010b8cd998 book_02de
221 pre-close-tip:24b6387c8c8c public
221 pre-close-tip:24b6387c8c8c public
222 postclose-tip:24b6387c8c8c public
222 postclose-tip:24b6387c8c8c public
223 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
223 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
224 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
224 $ hg -R other bookmark --rev cd010b8cd998 book_42cc
225 pre-close-tip:24b6387c8c8c public
225 pre-close-tip:24b6387c8c8c public
226 postclose-tip:24b6387c8c8c public
226 postclose-tip:24b6387c8c8c public
227 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
227 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
228 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
228 $ hg -R other bookmark --rev cd010b8cd998 book_5fdd
229 pre-close-tip:24b6387c8c8c public
229 pre-close-tip:24b6387c8c8c public
230 postclose-tip:24b6387c8c8c public
230 postclose-tip:24b6387c8c8c public
231 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
231 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
232 $ hg -R other bookmark --rev cd010b8cd998 book_32af
232 $ hg -R other bookmark --rev cd010b8cd998 book_32af
233 pre-close-tip:24b6387c8c8c public
233 pre-close-tip:24b6387c8c8c public
234 postclose-tip:24b6387c8c8c public
234 postclose-tip:24b6387c8c8c public
235 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
235 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
236
236
237 $ hg -R main phase --public eea13746799a
237 $ hg -R main phase --public eea13746799a
238 pre-close-tip:02de42196ebe draft book_02de
238 pre-close-tip:02de42196ebe draft book_02de
239 postclose-tip:02de42196ebe draft book_02de
239 postclose-tip:02de42196ebe draft book_02de
240 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
240 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
241
241
242 push
242 push
243 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
243 $ hg -R main push other --rev eea13746799a --bookmark book_eea1
244 pushing to other
244 pushing to other
245 searching for changes
245 searching for changes
246 remote: adding changesets
246 remote: adding changesets
247 remote: adding manifests
247 remote: adding manifests
248 remote: adding file changes
248 remote: adding file changes
249 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
249 remote: added 1 changesets with 0 changes to 0 files (-1 heads)
250 remote: 1 new obsolescence markers
250 remote: 1 new obsolescence markers
251 remote: pre-close-tip:eea13746799a public book_eea1
251 remote: pre-close-tip:eea13746799a public book_eea1
252 remote: pushkey: lock state after "phases"
252 remote: pushkey: lock state after "phases"
253 remote: lock: free
253 remote: lock: free
254 remote: wlock: free
254 remote: wlock: free
255 remote: pushkey: lock state after "bookmarks"
255 remote: pushkey: lock state after "bookmarks"
256 remote: lock: free
256 remote: lock: free
257 remote: wlock: free
257 remote: wlock: free
258 remote: postclose-tip:eea13746799a public book_eea1
258 remote: postclose-tip:eea13746799a public book_eea1
259 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=file:$TESTTMP/other (glob)
259 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_NODE_LAST=eea13746799a9e0bfd88f29d3c2e9dc9389f524f HG_PHASES_MOVED=1 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/other
260 updating bookmark book_eea1
260 updating bookmark book_eea1
261 pre-close-tip:02de42196ebe draft book_02de
261 pre-close-tip:02de42196ebe draft book_02de
262 postclose-tip:02de42196ebe draft book_02de
262 postclose-tip:02de42196ebe draft book_02de
263 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
263 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
264 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
264 file:/*/$TESTTMP/other HG_URL=file:$TESTTMP/other (glob)
265 $ hg -R other log -G
265 $ hg -R other log -G
266 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
266 o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
267 |\
267 |\
268 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
268 | o 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
269 | |
269 | |
270 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
270 @ | 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
271 |/
271 |/
272 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
272 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de book_32af book_42cc book_5fdd A
273
273
274 $ hg -R other debugobsolete
274 $ hg -R other debugobsolete
275 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
275 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
276 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
276 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
277 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
277 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
278
278
279 pull over ssh
279 pull over ssh
280
280
281 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
281 $ hg -R other pull ssh://user@dummy/main -r 02de42196ebe --bookmark book_02de
282 pulling from ssh://user@dummy/main
282 pulling from ssh://user@dummy/main
283 searching for changes
283 searching for changes
284 adding changesets
284 adding changesets
285 adding manifests
285 adding manifests
286 adding file changes
286 adding file changes
287 added 1 changesets with 1 changes to 1 files (+1 heads)
287 added 1 changesets with 1 changes to 1 files (+1 heads)
288 1 new obsolescence markers
288 1 new obsolescence markers
289 updating bookmark book_02de
289 updating bookmark book_02de
290 pre-close-tip:02de42196ebe draft book_02de
290 pre-close-tip:02de42196ebe draft book_02de
291 postclose-tip:02de42196ebe draft book_02de
291 postclose-tip:02de42196ebe draft book_02de
292 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
292 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_NODE_LAST=02de42196ebee42ef284b6780a87cdc96e8eaab6 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
293 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
293 ssh://user@dummy/main HG_URL=ssh://user@dummy/main
294 (run 'hg heads' to see heads, 'hg merge' to merge)
294 (run 'hg heads' to see heads, 'hg merge' to merge)
295 $ hg -R other debugobsolete
295 $ hg -R other debugobsolete
296 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
296 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
297 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
297 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
298 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
298 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
299 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
299 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
300
300
301 pull over http
301 pull over http
302
302
303 $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log
303 $ hg serve -R main -p $HGPORT -d --pid-file=main.pid -E main-error.log
304 $ cat main.pid >> $DAEMON_PIDS
304 $ cat main.pid >> $DAEMON_PIDS
305
305
306 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
306 $ hg -R other pull http://localhost:$HGPORT/ -r 42ccdea3bb16 --bookmark book_42cc
307 pulling from http://localhost:$HGPORT/
307 pulling from http://localhost:$HGPORT/
308 searching for changes
308 searching for changes
309 adding changesets
309 adding changesets
310 adding manifests
310 adding manifests
311 adding file changes
311 adding file changes
312 added 1 changesets with 1 changes to 1 files (+1 heads)
312 added 1 changesets with 1 changes to 1 files (+1 heads)
313 1 new obsolescence markers
313 1 new obsolescence markers
314 updating bookmark book_42cc
314 updating bookmark book_42cc
315 pre-close-tip:42ccdea3bb16 draft book_42cc
315 pre-close-tip:42ccdea3bb16 draft book_42cc
316 postclose-tip:42ccdea3bb16 draft book_42cc
316 postclose-tip:42ccdea3bb16 draft book_42cc
317 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_TXNNAME=pull (glob)
317 txnclose hook: HG_BOOKMARK_MOVED=1 HG_NEW_OBSMARKERS=1 HG_NODE=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_NODE_LAST=42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_TXNNAME=pull
318 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
318 http://localhost:$HGPORT/ HG_URL=http://localhost:$HGPORT/
319 (run 'hg heads .' to see heads, 'hg merge' to merge)
319 (run 'hg heads .' to see heads, 'hg merge' to merge)
320 $ cat main-error.log
320 $ cat main-error.log
321 $ hg -R other debugobsolete
321 $ hg -R other debugobsolete
322 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
322 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
323 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
323 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
324 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
324 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
325 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
325 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
326 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
326 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
327
327
328 push over ssh
328 push over ssh
329
329
330 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
330 $ hg -R main push ssh://user@dummy/other -r 5fddd98957c8 --bookmark book_5fdd
331 pushing to ssh://user@dummy/other
331 pushing to ssh://user@dummy/other
332 searching for changes
332 searching for changes
333 remote: adding changesets
333 remote: adding changesets
334 remote: adding manifests
334 remote: adding manifests
335 remote: adding file changes
335 remote: adding file changes
336 remote: added 1 changesets with 1 changes to 1 files
336 remote: added 1 changesets with 1 changes to 1 files
337 remote: 1 new obsolescence markers
337 remote: 1 new obsolescence markers
338 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
338 remote: pre-close-tip:5fddd98957c8 draft book_5fdd
339 remote: pushkey: lock state after "bookmarks"
339 remote: pushkey: lock state after "bookmarks"
340 remote: lock: free
340 remote: lock: free
341 remote: wlock: free
341 remote: wlock: free
342 remote: postclose-tip:5fddd98957c8 draft book_5fdd
342 remote: postclose-tip:5fddd98957c8 draft book_5fdd
343 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:ssh:$LOCALIP (glob)
343 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_NODE_LAST=5fddd98957c8a54a4d436dfe1da9d87f21a1b97b HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:ssh:$LOCALIP
344 updating bookmark book_5fdd
344 updating bookmark book_5fdd
345 pre-close-tip:02de42196ebe draft book_02de
345 pre-close-tip:02de42196ebe draft book_02de
346 postclose-tip:02de42196ebe draft book_02de
346 postclose-tip:02de42196ebe draft book_02de
347 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
347 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
348 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
348 ssh://user@dummy/other HG_URL=ssh://user@dummy/other
349 $ hg -R other log -G
349 $ hg -R other log -G
350 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
350 o 6:5fddd98957c8 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
351 |
351 |
352 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
352 o 5:42ccdea3bb16 draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
353 |
353 |
354 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
354 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
355 | |
355 | |
356 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
356 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
357 | |/|
357 | |/|
358 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
358 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
359 |/ /
359 |/ /
360 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
360 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
361 |/
361 |/
362 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
362 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af A
363
363
364 $ hg -R other debugobsolete
364 $ hg -R other debugobsolete
365 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
365 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
366 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
366 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
367 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
367 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
368 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
368 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
369 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
369 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
370 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
370 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
371
371
372 push over http
372 push over http
373
373
374 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
374 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
375 $ cat other.pid >> $DAEMON_PIDS
375 $ cat other.pid >> $DAEMON_PIDS
376
376
377 $ hg -R main phase --public 32af7686d403
377 $ hg -R main phase --public 32af7686d403
378 pre-close-tip:02de42196ebe draft book_02de
378 pre-close-tip:02de42196ebe draft book_02de
379 postclose-tip:02de42196ebe draft book_02de
379 postclose-tip:02de42196ebe draft book_02de
380 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=phase (glob)
380 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=phase
381 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
381 $ hg -R main push http://localhost:$HGPORT2/ -r 32af7686d403 --bookmark book_32af
382 pushing to http://localhost:$HGPORT2/
382 pushing to http://localhost:$HGPORT2/
383 searching for changes
383 searching for changes
384 remote: adding changesets
384 remote: adding changesets
385 remote: adding manifests
385 remote: adding manifests
386 remote: adding file changes
386 remote: adding file changes
387 remote: added 1 changesets with 1 changes to 1 files
387 remote: added 1 changesets with 1 changes to 1 files
388 remote: 1 new obsolescence markers
388 remote: 1 new obsolescence markers
389 remote: pre-close-tip:32af7686d403 public book_32af
389 remote: pre-close-tip:32af7686d403 public book_32af
390 remote: pushkey: lock state after "phases"
390 remote: pushkey: lock state after "phases"
391 remote: lock: free
391 remote: lock: free
392 remote: wlock: free
392 remote: wlock: free
393 remote: pushkey: lock state after "bookmarks"
393 remote: pushkey: lock state after "bookmarks"
394 remote: lock: free
394 remote: lock: free
395 remote: wlock: free
395 remote: wlock: free
396 remote: postclose-tip:32af7686d403 public book_32af
396 remote: postclose-tip:32af7686d403 public book_32af
397 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_TXNNAME=serve HG_URL=remote:http:*: (glob)
397 remote: txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_NEW_OBSMARKERS=1 HG_NODE=32af7686d403cf45b5d95f2d70cebea587ac806a HG_NODE_LAST=32af7686d403cf45b5d95f2d70cebea587ac806a HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_TXNNAME=serve HG_URL=remote:http:$LOCALIP:
398 updating bookmark book_32af
398 updating bookmark book_32af
399 pre-close-tip:02de42196ebe draft book_02de
399 pre-close-tip:02de42196ebe draft book_02de
400 postclose-tip:02de42196ebe draft book_02de
400 postclose-tip:02de42196ebe draft book_02de
401 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:* HG_TXNNAME=push-response (glob)
401 txnclose hook: HG_SOURCE=push-response HG_TXNID=TXN:$ID$ HG_TXNNAME=push-response
402 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
402 http://localhost:$HGPORT2/ HG_URL=http://localhost:$HGPORT2/
403 $ cat other-error.log
403 $ cat other-error.log
404
404
405 Check final content.
405 Check final content.
406
406
407 $ hg -R other log -G
407 $ hg -R other log -G
408 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
408 o 7:32af7686d403 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_32af D
409 |
409 |
410 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
410 o 6:5fddd98957c8 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_5fdd C
411 |
411 |
412 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
412 o 5:42ccdea3bb16 public Nicolas Dumazet <nicdumz.commits@gmail.com> book_42cc B
413 |
413 |
414 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
414 | o 4:02de42196ebe draft Nicolas Dumazet <nicdumz.commits@gmail.com> book_02de H
415 | |
415 | |
416 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
416 | | o 3:eea13746799a public Nicolas Dumazet <nicdumz.commits@gmail.com> book_eea1 G
417 | |/|
417 | |/|
418 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
418 | o | 2:24b6387c8c8c public Nicolas Dumazet <nicdumz.commits@gmail.com> F
419 |/ /
419 |/ /
420 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
420 | @ 1:9520eea781bc public Nicolas Dumazet <nicdumz.commits@gmail.com> E
421 |/
421 |/
422 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
422 o 0:cd010b8cd998 public Nicolas Dumazet <nicdumz.commits@gmail.com> A
423
423
424 $ hg -R other debugobsolete
424 $ hg -R other debugobsolete
425 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
425 1111111111111111111111111111111111111111 9520eea781bcca16c1e15acc0ba14335a0e8e5ba 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
426 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
426 2222222222222222222222222222222222222222 24b6387c8c8cae37178880f3fa95ded3cb1cf785 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
427 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
427 3333333333333333333333333333333333333333 eea13746799a9e0bfd88f29d3c2e9dc9389f524f 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
428 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
428 4444444444444444444444444444444444444444 02de42196ebee42ef284b6780a87cdc96e8eaab6 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
429 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
429 5555555555555555555555555555555555555555 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
430 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
430 6666666666666666666666666666666666666666 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
431 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
431 7777777777777777777777777777777777777777 32af7686d403cf45b5d95f2d70cebea587ac806a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
432
432
433 (check that no 'pending' files remain)
433 (check that no 'pending' files remain)
434
434
435 $ ls -1 other/.hg/bookmarks*
435 $ ls -1 other/.hg/bookmarks*
436 other/.hg/bookmarks
436 other/.hg/bookmarks
437 $ ls -1 other/.hg/store/phaseroots*
437 $ ls -1 other/.hg/store/phaseroots*
438 other/.hg/store/phaseroots
438 other/.hg/store/phaseroots
439 $ ls -1 other/.hg/store/00changelog.i*
439 $ ls -1 other/.hg/store/00changelog.i*
440 other/.hg/store/00changelog.i
440 other/.hg/store/00changelog.i
441
441
442 Error Handling
442 Error Handling
443 ==============
443 ==============
444
444
445 Check that errors are properly returned to the client during push.
445 Check that errors are properly returned to the client during push.
446
446
447 Setting up
447 Setting up
448
448
449 $ cat > failpush.py << EOF
449 $ cat > failpush.py << EOF
450 > """A small extension that makes push fails when using bundle2
450 > """A small extension that makes push fails when using bundle2
451 >
451 >
452 > used to test error handling in bundle2
452 > used to test error handling in bundle2
453 > """
453 > """
454 >
454 >
455 > from mercurial import error
455 > from mercurial import error
456 > from mercurial import bundle2
456 > from mercurial import bundle2
457 > from mercurial import exchange
457 > from mercurial import exchange
458 > from mercurial import extensions
458 > from mercurial import extensions
459 >
459 >
460 > def _pushbundle2failpart(pushop, bundler):
460 > def _pushbundle2failpart(pushop, bundler):
461 > reason = pushop.ui.config('failpush', 'reason', None)
461 > reason = pushop.ui.config('failpush', 'reason', None)
462 > part = None
462 > part = None
463 > if reason == 'abort':
463 > if reason == 'abort':
464 > bundler.newpart('test:abort')
464 > bundler.newpart('test:abort')
465 > if reason == 'unknown':
465 > if reason == 'unknown':
466 > bundler.newpart('test:unknown')
466 > bundler.newpart('test:unknown')
467 > if reason == 'race':
467 > if reason == 'race':
468 > # 20 Bytes of crap
468 > # 20 Bytes of crap
469 > bundler.newpart('check:heads', data='01234567890123456789')
469 > bundler.newpart('check:heads', data='01234567890123456789')
470 >
470 >
471 > @bundle2.parthandler("test:abort")
471 > @bundle2.parthandler("test:abort")
472 > def handleabort(op, part):
472 > def handleabort(op, part):
473 > raise error.Abort('Abandon ship!', hint="don't panic")
473 > raise error.Abort('Abandon ship!', hint="don't panic")
474 >
474 >
475 > def uisetup(ui):
475 > def uisetup(ui):
476 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
476 > exchange.b2partsgenmapping['failpart'] = _pushbundle2failpart
477 > exchange.b2partsgenorder.insert(0, 'failpart')
477 > exchange.b2partsgenorder.insert(0, 'failpart')
478 >
478 >
479 > EOF
479 > EOF
480
480
481 $ cd main
481 $ cd main
482 $ hg up tip
482 $ hg up tip
483 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
483 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
484 $ echo 'I' > I
484 $ echo 'I' > I
485 $ hg add I
485 $ hg add I
486 $ hg ci -m 'I'
486 $ hg ci -m 'I'
487 pre-close-tip:e7ec4e813ba6 draft
487 pre-close-tip:e7ec4e813ba6 draft
488 postclose-tip:e7ec4e813ba6 draft
488 postclose-tip:e7ec4e813ba6 draft
489 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
489 txnclose hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
490 $ hg id
490 $ hg id
491 e7ec4e813ba6 tip
491 e7ec4e813ba6 tip
492 $ cd ..
492 $ cd ..
493
493
494 $ cat << EOF >> $HGRCPATH
494 $ cat << EOF >> $HGRCPATH
495 > [extensions]
495 > [extensions]
496 > failpush=$TESTTMP/failpush.py
496 > failpush=$TESTTMP/failpush.py
497 > EOF
497 > EOF
498
498
499 $ killdaemons.py
499 $ killdaemons.py
500 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
500 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
501 $ cat other.pid >> $DAEMON_PIDS
501 $ cat other.pid >> $DAEMON_PIDS
502
502
503 Doing the actual push: Abort error
503 Doing the actual push: Abort error
504
504
505 $ cat << EOF >> $HGRCPATH
505 $ cat << EOF >> $HGRCPATH
506 > [failpush]
506 > [failpush]
507 > reason = abort
507 > reason = abort
508 > EOF
508 > EOF
509
509
510 $ hg -R main push other -r e7ec4e813ba6
510 $ hg -R main push other -r e7ec4e813ba6
511 pushing to other
511 pushing to other
512 searching for changes
512 searching for changes
513 abort: Abandon ship!
513 abort: Abandon ship!
514 (don't panic)
514 (don't panic)
515 [255]
515 [255]
516
516
517 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
517 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
518 pushing to ssh://user@dummy/other
518 pushing to ssh://user@dummy/other
519 searching for changes
519 searching for changes
520 remote: Abandon ship!
520 remote: Abandon ship!
521 remote: (don't panic)
521 remote: (don't panic)
522 abort: push failed on remote
522 abort: push failed on remote
523 [255]
523 [255]
524
524
525 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
525 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
526 pushing to http://localhost:$HGPORT2/
526 pushing to http://localhost:$HGPORT2/
527 searching for changes
527 searching for changes
528 remote: Abandon ship!
528 remote: Abandon ship!
529 remote: (don't panic)
529 remote: (don't panic)
530 abort: push failed on remote
530 abort: push failed on remote
531 [255]
531 [255]
532
532
533
533
534 Doing the actual push: unknown mandatory parts
534 Doing the actual push: unknown mandatory parts
535
535
536 $ cat << EOF >> $HGRCPATH
536 $ cat << EOF >> $HGRCPATH
537 > [failpush]
537 > [failpush]
538 > reason = unknown
538 > reason = unknown
539 > EOF
539 > EOF
540
540
541 $ hg -R main push other -r e7ec4e813ba6
541 $ hg -R main push other -r e7ec4e813ba6
542 pushing to other
542 pushing to other
543 searching for changes
543 searching for changes
544 abort: missing support for test:unknown
544 abort: missing support for test:unknown
545 [255]
545 [255]
546
546
547 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
547 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
548 pushing to ssh://user@dummy/other
548 pushing to ssh://user@dummy/other
549 searching for changes
549 searching for changes
550 abort: missing support for test:unknown
550 abort: missing support for test:unknown
551 [255]
551 [255]
552
552
553 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
553 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
554 pushing to http://localhost:$HGPORT2/
554 pushing to http://localhost:$HGPORT2/
555 searching for changes
555 searching for changes
556 abort: missing support for test:unknown
556 abort: missing support for test:unknown
557 [255]
557 [255]
558
558
559 Doing the actual push: race
559 Doing the actual push: race
560
560
561 $ cat << EOF >> $HGRCPATH
561 $ cat << EOF >> $HGRCPATH
562 > [failpush]
562 > [failpush]
563 > reason = race
563 > reason = race
564 > EOF
564 > EOF
565
565
566 $ hg -R main push other -r e7ec4e813ba6
566 $ hg -R main push other -r e7ec4e813ba6
567 pushing to other
567 pushing to other
568 searching for changes
568 searching for changes
569 abort: push failed:
569 abort: push failed:
570 'repository changed while pushing - please try again'
570 'repository changed while pushing - please try again'
571 [255]
571 [255]
572
572
573 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
573 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
574 pushing to ssh://user@dummy/other
574 pushing to ssh://user@dummy/other
575 searching for changes
575 searching for changes
576 abort: push failed:
576 abort: push failed:
577 'repository changed while pushing - please try again'
577 'repository changed while pushing - please try again'
578 [255]
578 [255]
579
579
580 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
580 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
581 pushing to http://localhost:$HGPORT2/
581 pushing to http://localhost:$HGPORT2/
582 searching for changes
582 searching for changes
583 abort: push failed:
583 abort: push failed:
584 'repository changed while pushing - please try again'
584 'repository changed while pushing - please try again'
585 [255]
585 [255]
586
586
587 Doing the actual push: hook abort
587 Doing the actual push: hook abort
588
588
589 $ cat << EOF >> $HGRCPATH
589 $ cat << EOF >> $HGRCPATH
590 > [failpush]
590 > [failpush]
591 > reason =
591 > reason =
592 > [hooks]
592 > [hooks]
593 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
593 > pretxnclose.failpush = sh -c "echo 'You shall not pass!'; false"
594 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
594 > txnabort.failpush = sh -c "echo 'Cleaning up the mess...'"
595 > EOF
595 > EOF
596
596
597 $ killdaemons.py
597 $ killdaemons.py
598 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
598 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
599 $ cat other.pid >> $DAEMON_PIDS
599 $ cat other.pid >> $DAEMON_PIDS
600
600
601 $ hg -R main push other -r e7ec4e813ba6
601 $ hg -R main push other -r e7ec4e813ba6
602 pushing to other
602 pushing to other
603 searching for changes
603 searching for changes
604 remote: adding changesets
604 remote: adding changesets
605 remote: adding manifests
605 remote: adding manifests
606 remote: adding file changes
606 remote: adding file changes
607 remote: added 1 changesets with 1 changes to 1 files
607 remote: added 1 changesets with 1 changes to 1 files
608 remote: pre-close-tip:e7ec4e813ba6 draft
608 remote: pre-close-tip:e7ec4e813ba6 draft
609 remote: You shall not pass!
609 remote: You shall not pass!
610 remote: transaction abort!
610 remote: transaction abort!
611 remote: Cleaning up the mess...
611 remote: Cleaning up the mess...
612 remote: rollback completed
612 remote: rollback completed
613 abort: pretxnclose.failpush hook exited with status 1
613 abort: pretxnclose.failpush hook exited with status 1
614 [255]
614 [255]
615
615
616 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
616 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
617 pushing to ssh://user@dummy/other
617 pushing to ssh://user@dummy/other
618 searching for changes
618 searching for changes
619 remote: adding changesets
619 remote: adding changesets
620 remote: adding manifests
620 remote: adding manifests
621 remote: adding file changes
621 remote: adding file changes
622 remote: added 1 changesets with 1 changes to 1 files
622 remote: added 1 changesets with 1 changes to 1 files
623 remote: pre-close-tip:e7ec4e813ba6 draft
623 remote: pre-close-tip:e7ec4e813ba6 draft
624 remote: You shall not pass!
624 remote: You shall not pass!
625 remote: transaction abort!
625 remote: transaction abort!
626 remote: Cleaning up the mess...
626 remote: Cleaning up the mess...
627 remote: rollback completed
627 remote: rollback completed
628 remote: pretxnclose.failpush hook exited with status 1
628 remote: pretxnclose.failpush hook exited with status 1
629 abort: push failed on remote
629 abort: push failed on remote
630 [255]
630 [255]
631
631
632 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
632 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
633 pushing to http://localhost:$HGPORT2/
633 pushing to http://localhost:$HGPORT2/
634 searching for changes
634 searching for changes
635 remote: adding changesets
635 remote: adding changesets
636 remote: adding manifests
636 remote: adding manifests
637 remote: adding file changes
637 remote: adding file changes
638 remote: added 1 changesets with 1 changes to 1 files
638 remote: added 1 changesets with 1 changes to 1 files
639 remote: pre-close-tip:e7ec4e813ba6 draft
639 remote: pre-close-tip:e7ec4e813ba6 draft
640 remote: You shall not pass!
640 remote: You shall not pass!
641 remote: transaction abort!
641 remote: transaction abort!
642 remote: Cleaning up the mess...
642 remote: Cleaning up the mess...
643 remote: rollback completed
643 remote: rollback completed
644 remote: pretxnclose.failpush hook exited with status 1
644 remote: pretxnclose.failpush hook exited with status 1
645 abort: push failed on remote
645 abort: push failed on remote
646 [255]
646 [255]
647
647
648 (check that no 'pending' files remain)
648 (check that no 'pending' files remain)
649
649
650 $ ls -1 other/.hg/bookmarks*
650 $ ls -1 other/.hg/bookmarks*
651 other/.hg/bookmarks
651 other/.hg/bookmarks
652 $ ls -1 other/.hg/store/phaseroots*
652 $ ls -1 other/.hg/store/phaseroots*
653 other/.hg/store/phaseroots
653 other/.hg/store/phaseroots
654 $ ls -1 other/.hg/store/00changelog.i*
654 $ ls -1 other/.hg/store/00changelog.i*
655 other/.hg/store/00changelog.i
655 other/.hg/store/00changelog.i
656
656
657 Check error from hook during the unbundling process itself
657 Check error from hook during the unbundling process itself
658
658
659 $ cat << EOF >> $HGRCPATH
659 $ cat << EOF >> $HGRCPATH
660 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
660 > pretxnchangegroup = sh -c "echo 'Fail early!'; false"
661 > EOF
661 > EOF
662 $ killdaemons.py # reload http config
662 $ killdaemons.py # reload http config
663 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
663 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
664 $ cat other.pid >> $DAEMON_PIDS
664 $ cat other.pid >> $DAEMON_PIDS
665
665
666 $ hg -R main push other -r e7ec4e813ba6
666 $ hg -R main push other -r e7ec4e813ba6
667 pushing to other
667 pushing to other
668 searching for changes
668 searching for changes
669 remote: adding changesets
669 remote: adding changesets
670 remote: adding manifests
670 remote: adding manifests
671 remote: adding file changes
671 remote: adding file changes
672 remote: added 1 changesets with 1 changes to 1 files
672 remote: added 1 changesets with 1 changes to 1 files
673 remote: Fail early!
673 remote: Fail early!
674 remote: transaction abort!
674 remote: transaction abort!
675 remote: Cleaning up the mess...
675 remote: Cleaning up the mess...
676 remote: rollback completed
676 remote: rollback completed
677 abort: pretxnchangegroup hook exited with status 1
677 abort: pretxnchangegroup hook exited with status 1
678 [255]
678 [255]
679 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
679 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
680 pushing to ssh://user@dummy/other
680 pushing to ssh://user@dummy/other
681 searching for changes
681 searching for changes
682 remote: adding changesets
682 remote: adding changesets
683 remote: adding manifests
683 remote: adding manifests
684 remote: adding file changes
684 remote: adding file changes
685 remote: added 1 changesets with 1 changes to 1 files
685 remote: added 1 changesets with 1 changes to 1 files
686 remote: Fail early!
686 remote: Fail early!
687 remote: transaction abort!
687 remote: transaction abort!
688 remote: Cleaning up the mess...
688 remote: Cleaning up the mess...
689 remote: rollback completed
689 remote: rollback completed
690 remote: pretxnchangegroup hook exited with status 1
690 remote: pretxnchangegroup hook exited with status 1
691 abort: push failed on remote
691 abort: push failed on remote
692 [255]
692 [255]
693 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
693 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
694 pushing to http://localhost:$HGPORT2/
694 pushing to http://localhost:$HGPORT2/
695 searching for changes
695 searching for changes
696 remote: adding changesets
696 remote: adding changesets
697 remote: adding manifests
697 remote: adding manifests
698 remote: adding file changes
698 remote: adding file changes
699 remote: added 1 changesets with 1 changes to 1 files
699 remote: added 1 changesets with 1 changes to 1 files
700 remote: Fail early!
700 remote: Fail early!
701 remote: transaction abort!
701 remote: transaction abort!
702 remote: Cleaning up the mess...
702 remote: Cleaning up the mess...
703 remote: rollback completed
703 remote: rollback completed
704 remote: pretxnchangegroup hook exited with status 1
704 remote: pretxnchangegroup hook exited with status 1
705 abort: push failed on remote
705 abort: push failed on remote
706 [255]
706 [255]
707
707
708 Check output capture control.
708 Check output capture control.
709
709
710 (should be still forced for http, disabled for local and ssh)
710 (should be still forced for http, disabled for local and ssh)
711
711
712 $ cat >> $HGRCPATH << EOF
712 $ cat >> $HGRCPATH << EOF
713 > [experimental]
713 > [experimental]
714 > bundle2-output-capture=False
714 > bundle2-output-capture=False
715 > EOF
715 > EOF
716
716
717 $ hg -R main push other -r e7ec4e813ba6
717 $ hg -R main push other -r e7ec4e813ba6
718 pushing to other
718 pushing to other
719 searching for changes
719 searching for changes
720 adding changesets
720 adding changesets
721 adding manifests
721 adding manifests
722 adding file changes
722 adding file changes
723 added 1 changesets with 1 changes to 1 files
723 added 1 changesets with 1 changes to 1 files
724 Fail early!
724 Fail early!
725 transaction abort!
725 transaction abort!
726 Cleaning up the mess...
726 Cleaning up the mess...
727 rollback completed
727 rollback completed
728 abort: pretxnchangegroup hook exited with status 1
728 abort: pretxnchangegroup hook exited with status 1
729 [255]
729 [255]
730 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
730 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
731 pushing to ssh://user@dummy/other
731 pushing to ssh://user@dummy/other
732 searching for changes
732 searching for changes
733 remote: adding changesets
733 remote: adding changesets
734 remote: adding manifests
734 remote: adding manifests
735 remote: adding file changes
735 remote: adding file changes
736 remote: added 1 changesets with 1 changes to 1 files
736 remote: added 1 changesets with 1 changes to 1 files
737 remote: Fail early!
737 remote: Fail early!
738 remote: transaction abort!
738 remote: transaction abort!
739 remote: Cleaning up the mess...
739 remote: Cleaning up the mess...
740 remote: rollback completed
740 remote: rollback completed
741 remote: pretxnchangegroup hook exited with status 1
741 remote: pretxnchangegroup hook exited with status 1
742 abort: push failed on remote
742 abort: push failed on remote
743 [255]
743 [255]
744 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
744 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
745 pushing to http://localhost:$HGPORT2/
745 pushing to http://localhost:$HGPORT2/
746 searching for changes
746 searching for changes
747 remote: adding changesets
747 remote: adding changesets
748 remote: adding manifests
748 remote: adding manifests
749 remote: adding file changes
749 remote: adding file changes
750 remote: added 1 changesets with 1 changes to 1 files
750 remote: added 1 changesets with 1 changes to 1 files
751 remote: Fail early!
751 remote: Fail early!
752 remote: transaction abort!
752 remote: transaction abort!
753 remote: Cleaning up the mess...
753 remote: Cleaning up the mess...
754 remote: rollback completed
754 remote: rollback completed
755 remote: pretxnchangegroup hook exited with status 1
755 remote: pretxnchangegroup hook exited with status 1
756 abort: push failed on remote
756 abort: push failed on remote
757 [255]
757 [255]
758
758
759 Check abort from mandatory pushkey
759 Check abort from mandatory pushkey
760
760
761 $ cat > mandatorypart.py << EOF
761 $ cat > mandatorypart.py << EOF
762 > from mercurial import exchange
762 > from mercurial import exchange
763 > from mercurial import pushkey
763 > from mercurial import pushkey
764 > from mercurial import node
764 > from mercurial import node
765 > from mercurial import error
765 > from mercurial import error
766 > @exchange.b2partsgenerator('failingpuskey')
766 > @exchange.b2partsgenerator('failingpuskey')
767 > def addfailingpushey(pushop, bundler):
767 > def addfailingpushey(pushop, bundler):
768 > enc = pushkey.encode
768 > enc = pushkey.encode
769 > part = bundler.newpart('pushkey')
769 > part = bundler.newpart('pushkey')
770 > part.addparam('namespace', enc('phases'))
770 > part.addparam('namespace', enc('phases'))
771 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
771 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
772 > part.addparam('old', enc(str(0))) # successful update
772 > part.addparam('old', enc(str(0))) # successful update
773 > part.addparam('new', enc(str(0)))
773 > part.addparam('new', enc(str(0)))
774 > def fail(pushop, exc):
774 > def fail(pushop, exc):
775 > raise error.Abort('Correct phase push failed (because hooks)')
775 > raise error.Abort('Correct phase push failed (because hooks)')
776 > pushop.pkfailcb[part.id] = fail
776 > pushop.pkfailcb[part.id] = fail
777 > EOF
777 > EOF
778 $ cat >> $HGRCPATH << EOF
778 $ cat >> $HGRCPATH << EOF
779 > [hooks]
779 > [hooks]
780 > pretxnchangegroup=
780 > pretxnchangegroup=
781 > pretxnclose.failpush=
781 > pretxnclose.failpush=
782 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
782 > prepushkey.failpush = sh -c "echo 'do not push the key !'; false"
783 > [extensions]
783 > [extensions]
784 > mandatorypart=$TESTTMP/mandatorypart.py
784 > mandatorypart=$TESTTMP/mandatorypart.py
785 > EOF
785 > EOF
786 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
786 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
787 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
787 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
788 $ cat other.pid >> $DAEMON_PIDS
788 $ cat other.pid >> $DAEMON_PIDS
789
789
790 (Failure from a hook)
790 (Failure from a hook)
791
791
792 $ hg -R main push other -r e7ec4e813ba6
792 $ hg -R main push other -r e7ec4e813ba6
793 pushing to other
793 pushing to other
794 searching for changes
794 searching for changes
795 adding changesets
795 adding changesets
796 adding manifests
796 adding manifests
797 adding file changes
797 adding file changes
798 added 1 changesets with 1 changes to 1 files
798 added 1 changesets with 1 changes to 1 files
799 do not push the key !
799 do not push the key !
800 pushkey-abort: prepushkey.failpush hook exited with status 1
800 pushkey-abort: prepushkey.failpush hook exited with status 1
801 transaction abort!
801 transaction abort!
802 Cleaning up the mess...
802 Cleaning up the mess...
803 rollback completed
803 rollback completed
804 abort: Correct phase push failed (because hooks)
804 abort: Correct phase push failed (because hooks)
805 [255]
805 [255]
806 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
806 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
807 pushing to ssh://user@dummy/other
807 pushing to ssh://user@dummy/other
808 searching for changes
808 searching for changes
809 remote: adding changesets
809 remote: adding changesets
810 remote: adding manifests
810 remote: adding manifests
811 remote: adding file changes
811 remote: adding file changes
812 remote: added 1 changesets with 1 changes to 1 files
812 remote: added 1 changesets with 1 changes to 1 files
813 remote: do not push the key !
813 remote: do not push the key !
814 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
814 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
815 remote: transaction abort!
815 remote: transaction abort!
816 remote: Cleaning up the mess...
816 remote: Cleaning up the mess...
817 remote: rollback completed
817 remote: rollback completed
818 abort: Correct phase push failed (because hooks)
818 abort: Correct phase push failed (because hooks)
819 [255]
819 [255]
820 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
820 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
821 pushing to http://localhost:$HGPORT2/
821 pushing to http://localhost:$HGPORT2/
822 searching for changes
822 searching for changes
823 remote: adding changesets
823 remote: adding changesets
824 remote: adding manifests
824 remote: adding manifests
825 remote: adding file changes
825 remote: adding file changes
826 remote: added 1 changesets with 1 changes to 1 files
826 remote: added 1 changesets with 1 changes to 1 files
827 remote: do not push the key !
827 remote: do not push the key !
828 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
828 remote: pushkey-abort: prepushkey.failpush hook exited with status 1
829 remote: transaction abort!
829 remote: transaction abort!
830 remote: Cleaning up the mess...
830 remote: Cleaning up the mess...
831 remote: rollback completed
831 remote: rollback completed
832 abort: Correct phase push failed (because hooks)
832 abort: Correct phase push failed (because hooks)
833 [255]
833 [255]
834
834
835 (Failure from a the pushkey)
835 (Failure from a the pushkey)
836
836
837 $ cat > mandatorypart.py << EOF
837 $ cat > mandatorypart.py << EOF
838 > from mercurial import exchange
838 > from mercurial import exchange
839 > from mercurial import pushkey
839 > from mercurial import pushkey
840 > from mercurial import node
840 > from mercurial import node
841 > from mercurial import error
841 > from mercurial import error
842 > @exchange.b2partsgenerator('failingpuskey')
842 > @exchange.b2partsgenerator('failingpuskey')
843 > def addfailingpushey(pushop, bundler):
843 > def addfailingpushey(pushop, bundler):
844 > enc = pushkey.encode
844 > enc = pushkey.encode
845 > part = bundler.newpart('pushkey')
845 > part = bundler.newpart('pushkey')
846 > part.addparam('namespace', enc('phases'))
846 > part.addparam('namespace', enc('phases'))
847 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
847 > part.addparam('key', enc(pushop.repo['cd010b8cd998'].hex()))
848 > part.addparam('old', enc(str(4))) # will fail
848 > part.addparam('old', enc(str(4))) # will fail
849 > part.addparam('new', enc(str(3)))
849 > part.addparam('new', enc(str(3)))
850 > def fail(pushop, exc):
850 > def fail(pushop, exc):
851 > raise error.Abort('Clown phase push failed')
851 > raise error.Abort('Clown phase push failed')
852 > pushop.pkfailcb[part.id] = fail
852 > pushop.pkfailcb[part.id] = fail
853 > EOF
853 > EOF
854 $ cat >> $HGRCPATH << EOF
854 $ cat >> $HGRCPATH << EOF
855 > [hooks]
855 > [hooks]
856 > prepushkey.failpush =
856 > prepushkey.failpush =
857 > EOF
857 > EOF
858 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
858 $ "$TESTDIR/killdaemons.py" $DAEMON_PIDS # reload http config
859 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
859 $ hg serve -R other -p $HGPORT2 -d --pid-file=other.pid -E other-error.log
860 $ cat other.pid >> $DAEMON_PIDS
860 $ cat other.pid >> $DAEMON_PIDS
861
861
862 $ hg -R main push other -r e7ec4e813ba6
862 $ hg -R main push other -r e7ec4e813ba6
863 pushing to other
863 pushing to other
864 searching for changes
864 searching for changes
865 adding changesets
865 adding changesets
866 adding manifests
866 adding manifests
867 adding file changes
867 adding file changes
868 added 1 changesets with 1 changes to 1 files
868 added 1 changesets with 1 changes to 1 files
869 transaction abort!
869 transaction abort!
870 Cleaning up the mess...
870 Cleaning up the mess...
871 rollback completed
871 rollback completed
872 pushkey: lock state after "phases"
872 pushkey: lock state after "phases"
873 lock: free
873 lock: free
874 wlock: free
874 wlock: free
875 abort: Clown phase push failed
875 abort: Clown phase push failed
876 [255]
876 [255]
877 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
877 $ hg -R main push ssh://user@dummy/other -r e7ec4e813ba6
878 pushing to ssh://user@dummy/other
878 pushing to ssh://user@dummy/other
879 searching for changes
879 searching for changes
880 remote: adding changesets
880 remote: adding changesets
881 remote: adding manifests
881 remote: adding manifests
882 remote: adding file changes
882 remote: adding file changes
883 remote: added 1 changesets with 1 changes to 1 files
883 remote: added 1 changesets with 1 changes to 1 files
884 remote: transaction abort!
884 remote: transaction abort!
885 remote: Cleaning up the mess...
885 remote: Cleaning up the mess...
886 remote: rollback completed
886 remote: rollback completed
887 remote: pushkey: lock state after "phases"
887 remote: pushkey: lock state after "phases"
888 remote: lock: free
888 remote: lock: free
889 remote: wlock: free
889 remote: wlock: free
890 abort: Clown phase push failed
890 abort: Clown phase push failed
891 [255]
891 [255]
892 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
892 $ hg -R main push http://localhost:$HGPORT2/ -r e7ec4e813ba6
893 pushing to http://localhost:$HGPORT2/
893 pushing to http://localhost:$HGPORT2/
894 searching for changes
894 searching for changes
895 remote: adding changesets
895 remote: adding changesets
896 remote: adding manifests
896 remote: adding manifests
897 remote: adding file changes
897 remote: adding file changes
898 remote: added 1 changesets with 1 changes to 1 files
898 remote: added 1 changesets with 1 changes to 1 files
899 remote: transaction abort!
899 remote: transaction abort!
900 remote: Cleaning up the mess...
900 remote: Cleaning up the mess...
901 remote: rollback completed
901 remote: rollback completed
902 remote: pushkey: lock state after "phases"
902 remote: pushkey: lock state after "phases"
903 remote: lock: free
903 remote: lock: free
904 remote: wlock: free
904 remote: wlock: free
905 abort: Clown phase push failed
905 abort: Clown phase push failed
906 [255]
906 [255]
907
907
908 Test lazily acquiring the lock during unbundle
908 Test lazily acquiring the lock during unbundle
909 $ cp $TESTTMP/hgrc.orig $HGRCPATH
909 $ cp $TESTTMP/hgrc.orig $HGRCPATH
910 $ cat >> $HGRCPATH <<EOF
910 $ cat >> $HGRCPATH <<EOF
911 > [ui]
911 > [ui]
912 > ssh=python "$TESTDIR/dummyssh"
912 > ssh=python "$TESTDIR/dummyssh"
913 > EOF
913 > EOF
914
914
915 $ cat >> $TESTTMP/locktester.py <<EOF
915 $ cat >> $TESTTMP/locktester.py <<EOF
916 > import os
916 > import os
917 > from mercurial import extensions, bundle2, util
917 > from mercurial import extensions, bundle2, util
918 > def checklock(orig, repo, *args, **kwargs):
918 > def checklock(orig, repo, *args, **kwargs):
919 > if repo.svfs.lexists("lock"):
919 > if repo.svfs.lexists("lock"):
920 > raise util.Abort("Lock should not be taken")
920 > raise util.Abort("Lock should not be taken")
921 > return orig(repo, *args, **kwargs)
921 > return orig(repo, *args, **kwargs)
922 > def extsetup(ui):
922 > def extsetup(ui):
923 > extensions.wrapfunction(bundle2, 'processbundle', checklock)
923 > extensions.wrapfunction(bundle2, 'processbundle', checklock)
924 > EOF
924 > EOF
925
925
926 $ hg init lazylock
926 $ hg init lazylock
927 $ cat >> lazylock/.hg/hgrc <<EOF
927 $ cat >> lazylock/.hg/hgrc <<EOF
928 > [extensions]
928 > [extensions]
929 > locktester=$TESTTMP/locktester.py
929 > locktester=$TESTTMP/locktester.py
930 > EOF
930 > EOF
931
931
932 $ hg clone -q ssh://user@dummy/lazylock lazylockclient
932 $ hg clone -q ssh://user@dummy/lazylock lazylockclient
933 $ cd lazylockclient
933 $ cd lazylockclient
934 $ touch a && hg ci -Aqm a
934 $ touch a && hg ci -Aqm a
935 $ hg push
935 $ hg push
936 pushing to ssh://user@dummy/lazylock
936 pushing to ssh://user@dummy/lazylock
937 searching for changes
937 searching for changes
938 remote: Lock should not be taken
938 remote: Lock should not be taken
939 abort: push failed on remote
939 abort: push failed on remote
940 [255]
940 [255]
941
941
942 $ cat >> ../lazylock/.hg/hgrc <<EOF
942 $ cat >> ../lazylock/.hg/hgrc <<EOF
943 > [experimental]
943 > [experimental]
944 > bundle2lazylocking=True
944 > bundle2lazylocking=True
945 > EOF
945 > EOF
946 $ hg push
946 $ hg push
947 pushing to ssh://user@dummy/lazylock
947 pushing to ssh://user@dummy/lazylock
948 searching for changes
948 searching for changes
949 remote: adding changesets
949 remote: adding changesets
950 remote: adding manifests
950 remote: adding manifests
951 remote: adding file changes
951 remote: adding file changes
952 remote: added 1 changesets with 1 changes to 1 files
952 remote: added 1 changesets with 1 changes to 1 files
953
953
954 $ cd ..
954 $ cd ..
955
955
956 Servers can disable bundle1 for clone/pull operations
956 Servers can disable bundle1 for clone/pull operations
957
957
958 $ killdaemons.py
958 $ killdaemons.py
959 $ hg init bundle2onlyserver
959 $ hg init bundle2onlyserver
960 $ cd bundle2onlyserver
960 $ cd bundle2onlyserver
961 $ cat > .hg/hgrc << EOF
961 $ cat > .hg/hgrc << EOF
962 > [server]
962 > [server]
963 > bundle1.pull = false
963 > bundle1.pull = false
964 > EOF
964 > EOF
965
965
966 $ touch foo
966 $ touch foo
967 $ hg -q commit -A -m initial
967 $ hg -q commit -A -m initial
968
968
969 $ hg serve -p $HGPORT -d --pid-file=hg.pid
969 $ hg serve -p $HGPORT -d --pid-file=hg.pid
970 $ cat hg.pid >> $DAEMON_PIDS
970 $ cat hg.pid >> $DAEMON_PIDS
971
971
972 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
972 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
973 requesting all changes
973 requesting all changes
974 abort: remote error:
974 abort: remote error:
975 incompatible Mercurial client; bundle2 required
975 incompatible Mercurial client; bundle2 required
976 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
976 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
977 [255]
977 [255]
978 $ killdaemons.py
978 $ killdaemons.py
979 $ cd ..
979 $ cd ..
980
980
981 bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled
981 bundle1 can still pull non-generaldelta repos when generaldelta bundle1 disabled
982
982
983 $ hg --config format.usegeneraldelta=false init notgdserver
983 $ hg --config format.usegeneraldelta=false init notgdserver
984 $ cd notgdserver
984 $ cd notgdserver
985 $ cat > .hg/hgrc << EOF
985 $ cat > .hg/hgrc << EOF
986 > [server]
986 > [server]
987 > bundle1gd.pull = false
987 > bundle1gd.pull = false
988 > EOF
988 > EOF
989
989
990 $ touch foo
990 $ touch foo
991 $ hg -q commit -A -m initial
991 $ hg -q commit -A -m initial
992 $ hg serve -p $HGPORT -d --pid-file=hg.pid
992 $ hg serve -p $HGPORT -d --pid-file=hg.pid
993 $ cat hg.pid >> $DAEMON_PIDS
993 $ cat hg.pid >> $DAEMON_PIDS
994
994
995 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1
995 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-1
996 requesting all changes
996 requesting all changes
997 adding changesets
997 adding changesets
998 adding manifests
998 adding manifests
999 adding file changes
999 adding file changes
1000 added 1 changesets with 1 changes to 1 files
1000 added 1 changesets with 1 changes to 1 files
1001 updating to branch default
1001 updating to branch default
1002 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1002 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1003
1003
1004 $ killdaemons.py
1004 $ killdaemons.py
1005 $ cd ../bundle2onlyserver
1005 $ cd ../bundle2onlyserver
1006
1006
1007 bundle1 pull can be disabled for generaldelta repos only
1007 bundle1 pull can be disabled for generaldelta repos only
1008
1008
1009 $ cat > .hg/hgrc << EOF
1009 $ cat > .hg/hgrc << EOF
1010 > [server]
1010 > [server]
1011 > bundle1gd.pull = false
1011 > bundle1gd.pull = false
1012 > EOF
1012 > EOF
1013
1013
1014 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1014 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1015 $ cat hg.pid >> $DAEMON_PIDS
1015 $ cat hg.pid >> $DAEMON_PIDS
1016 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1016 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1017 requesting all changes
1017 requesting all changes
1018 abort: remote error:
1018 abort: remote error:
1019 incompatible Mercurial client; bundle2 required
1019 incompatible Mercurial client; bundle2 required
1020 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1020 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1021 [255]
1021 [255]
1022
1022
1023 $ killdaemons.py
1023 $ killdaemons.py
1024
1024
1025 Verify the global server.bundle1 option works
1025 Verify the global server.bundle1 option works
1026
1026
1027 $ cd ..
1027 $ cd ..
1028 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1028 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1029 > [server]
1029 > [server]
1030 > bundle1 = false
1030 > bundle1 = false
1031 > EOF
1031 > EOF
1032 $ hg -R bundle2onlyserver serve -p $HGPORT -d --pid-file=hg.pid
1032 $ hg -R bundle2onlyserver serve -p $HGPORT -d --pid-file=hg.pid
1033 $ cat hg.pid >> $DAEMON_PIDS
1033 $ cat hg.pid >> $DAEMON_PIDS
1034 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2
1034 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT not-bundle2
1035 requesting all changes
1035 requesting all changes
1036 abort: remote error:
1036 abort: remote error:
1037 incompatible Mercurial client; bundle2 required
1037 incompatible Mercurial client; bundle2 required
1038 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1038 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1039 [255]
1039 [255]
1040 $ killdaemons.py
1040 $ killdaemons.py
1041
1041
1042 $ hg --config devel.legacy.exchange=bundle1 clone ssh://user@dummy/bundle2onlyserver not-bundle2-ssh
1042 $ hg --config devel.legacy.exchange=bundle1 clone ssh://user@dummy/bundle2onlyserver not-bundle2-ssh
1043 requesting all changes
1043 requesting all changes
1044 adding changesets
1044 adding changesets
1045 remote: abort: incompatible Mercurial client; bundle2 required
1045 remote: abort: incompatible Mercurial client; bundle2 required
1046 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1046 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1047 transaction abort!
1047 transaction abort!
1048 rollback completed
1048 rollback completed
1049 abort: stream ended unexpectedly (got 0 bytes, expected 4)
1049 abort: stream ended unexpectedly (got 0 bytes, expected 4)
1050 [255]
1050 [255]
1051
1051
1052 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1052 $ cat > bundle2onlyserver/.hg/hgrc << EOF
1053 > [server]
1053 > [server]
1054 > bundle1gd = false
1054 > bundle1gd = false
1055 > EOF
1055 > EOF
1056 $ hg -R bundle2onlyserver serve -p $HGPORT -d --pid-file=hg.pid
1056 $ hg -R bundle2onlyserver serve -p $HGPORT -d --pid-file=hg.pid
1057 $ cat hg.pid >> $DAEMON_PIDS
1057 $ cat hg.pid >> $DAEMON_PIDS
1058
1058
1059 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1059 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2
1060 requesting all changes
1060 requesting all changes
1061 abort: remote error:
1061 abort: remote error:
1062 incompatible Mercurial client; bundle2 required
1062 incompatible Mercurial client; bundle2 required
1063 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1063 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1064 [255]
1064 [255]
1065
1065
1066 $ killdaemons.py
1066 $ killdaemons.py
1067
1067
1068 $ cd notgdserver
1068 $ cd notgdserver
1069 $ cat > .hg/hgrc << EOF
1069 $ cat > .hg/hgrc << EOF
1070 > [server]
1070 > [server]
1071 > bundle1gd = false
1071 > bundle1gd = false
1072 > EOF
1072 > EOF
1073 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1073 $ hg serve -p $HGPORT -d --pid-file=hg.pid
1074 $ cat hg.pid >> $DAEMON_PIDS
1074 $ cat hg.pid >> $DAEMON_PIDS
1075
1075
1076 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2
1076 $ hg --config devel.legacy.exchange=bundle1 clone http://localhost:$HGPORT/ not-bundle2-2
1077 requesting all changes
1077 requesting all changes
1078 adding changesets
1078 adding changesets
1079 adding manifests
1079 adding manifests
1080 adding file changes
1080 adding file changes
1081 added 1 changesets with 1 changes to 1 files
1081 added 1 changesets with 1 changes to 1 files
1082 updating to branch default
1082 updating to branch default
1083 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1083 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1084
1084
1085 $ killdaemons.py
1085 $ killdaemons.py
1086 $ cd ../bundle2onlyserver
1086 $ cd ../bundle2onlyserver
1087
1087
1088 Verify bundle1 pushes can be disabled
1088 Verify bundle1 pushes can be disabled
1089
1089
1090 $ cat > .hg/hgrc << EOF
1090 $ cat > .hg/hgrc << EOF
1091 > [server]
1091 > [server]
1092 > bundle1.push = false
1092 > bundle1.push = false
1093 > [web]
1093 > [web]
1094 > allow_push = *
1094 > allow_push = *
1095 > push_ssl = false
1095 > push_ssl = false
1096 > EOF
1096 > EOF
1097
1097
1098 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log
1098 $ hg serve -p $HGPORT -d --pid-file=hg.pid -E error.log
1099 $ cat hg.pid >> $DAEMON_PIDS
1099 $ cat hg.pid >> $DAEMON_PIDS
1100 $ cd ..
1100 $ cd ..
1101
1101
1102 $ hg clone http://localhost:$HGPORT bundle2-only
1102 $ hg clone http://localhost:$HGPORT bundle2-only
1103 requesting all changes
1103 requesting all changes
1104 adding changesets
1104 adding changesets
1105 adding manifests
1105 adding manifests
1106 adding file changes
1106 adding file changes
1107 added 1 changesets with 1 changes to 1 files
1107 added 1 changesets with 1 changes to 1 files
1108 updating to branch default
1108 updating to branch default
1109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1109 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1110 $ cd bundle2-only
1110 $ cd bundle2-only
1111 $ echo commit > foo
1111 $ echo commit > foo
1112 $ hg commit -m commit
1112 $ hg commit -m commit
1113 $ hg --config devel.legacy.exchange=bundle1 push
1113 $ hg --config devel.legacy.exchange=bundle1 push
1114 pushing to http://localhost:$HGPORT/
1114 pushing to http://localhost:$HGPORT/
1115 searching for changes
1115 searching for changes
1116 abort: remote error:
1116 abort: remote error:
1117 incompatible Mercurial client; bundle2 required
1117 incompatible Mercurial client; bundle2 required
1118 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1118 (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1119 [255]
1119 [255]
1120
1120
1121 (also check with ssh)
1121 (also check with ssh)
1122
1122
1123 $ hg --config devel.legacy.exchange=bundle1 push ssh://user@dummy/bundle2onlyserver
1123 $ hg --config devel.legacy.exchange=bundle1 push ssh://user@dummy/bundle2onlyserver
1124 pushing to ssh://user@dummy/bundle2onlyserver
1124 pushing to ssh://user@dummy/bundle2onlyserver
1125 searching for changes
1125 searching for changes
1126 remote: abort: incompatible Mercurial client; bundle2 required
1126 remote: abort: incompatible Mercurial client; bundle2 required
1127 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1127 remote: (see https://www.mercurial-scm.org/wiki/IncompatibleClient)
1128 [1]
1128 [1]
1129
1129
1130 $ hg push
1130 $ hg push
1131 pushing to http://localhost:$HGPORT/
1131 pushing to http://localhost:$HGPORT/
1132 searching for changes
1132 searching for changes
1133 remote: adding changesets
1133 remote: adding changesets
1134 remote: adding manifests
1134 remote: adding manifests
1135 remote: adding file changes
1135 remote: adding file changes
1136 remote: added 1 changesets with 1 changes to 1 files
1136 remote: added 1 changesets with 1 changes to 1 files
@@ -1,260 +1,260 b''
1 Create an extension to test bundle2 with multiple changegroups
1 Create an extension to test bundle2 with multiple changegroups
2
2
3 $ cat > bundle2.py <<EOF
3 $ cat > bundle2.py <<EOF
4 > """
4 > """
5 > """
5 > """
6 > from mercurial import changegroup, discovery, exchange
6 > from mercurial import changegroup, discovery, exchange
7 >
7 >
8 > def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
8 > def _getbundlechangegrouppart(bundler, repo, source, bundlecaps=None,
9 > b2caps=None, heads=None, common=None,
9 > b2caps=None, heads=None, common=None,
10 > **kwargs):
10 > **kwargs):
11 > # Create two changegroups given the common changesets and heads for the
11 > # Create two changegroups given the common changesets and heads for the
12 > # changegroup part we are being requested. Use the parent of each head
12 > # changegroup part we are being requested. Use the parent of each head
13 > # in 'heads' as intermediate heads for the first changegroup.
13 > # in 'heads' as intermediate heads for the first changegroup.
14 > intermediates = [repo[r].p1().node() for r in heads]
14 > intermediates = [repo[r].p1().node() for r in heads]
15 > outgoing = discovery.outgoing(repo, common, intermediates)
15 > outgoing = discovery.outgoing(repo, common, intermediates)
16 > cg = changegroup.getchangegroup(repo, source, outgoing,
16 > cg = changegroup.getchangegroup(repo, source, outgoing,
17 > bundlecaps=bundlecaps)
17 > bundlecaps=bundlecaps)
18 > bundler.newpart('output', data='changegroup1')
18 > bundler.newpart('output', data='changegroup1')
19 > bundler.newpart('changegroup', data=cg.getchunks())
19 > bundler.newpart('changegroup', data=cg.getchunks())
20 > outgoing = discovery.outgoing(repo, common + intermediates, heads)
20 > outgoing = discovery.outgoing(repo, common + intermediates, heads)
21 > cg = changegroup.getchangegroup(repo, source, outgoing,
21 > cg = changegroup.getchangegroup(repo, source, outgoing,
22 > bundlecaps=bundlecaps)
22 > bundlecaps=bundlecaps)
23 > bundler.newpart('output', data='changegroup2')
23 > bundler.newpart('output', data='changegroup2')
24 > bundler.newpart('changegroup', data=cg.getchunks())
24 > bundler.newpart('changegroup', data=cg.getchunks())
25 >
25 >
26 > def _pull(repo, *args, **kwargs):
26 > def _pull(repo, *args, **kwargs):
27 > pullop = _orig_pull(repo, *args, **kwargs)
27 > pullop = _orig_pull(repo, *args, **kwargs)
28 > repo.ui.write('pullop.cgresult is %d\n' % pullop.cgresult)
28 > repo.ui.write('pullop.cgresult is %d\n' % pullop.cgresult)
29 > return pullop
29 > return pullop
30 >
30 >
31 > _orig_pull = exchange.pull
31 > _orig_pull = exchange.pull
32 > exchange.pull = _pull
32 > exchange.pull = _pull
33 > exchange.getbundle2partsmapping['changegroup'] = _getbundlechangegrouppart
33 > exchange.getbundle2partsmapping['changegroup'] = _getbundlechangegrouppart
34 > EOF
34 > EOF
35
35
36 $ cat >> $HGRCPATH << EOF
36 $ cat >> $HGRCPATH << EOF
37 > [ui]
37 > [ui]
38 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
38 > logtemplate={rev}:{node|short} {phase} {author} {bookmarks} {desc|firstline}
39 > EOF
39 > EOF
40
40
41 Start with a simple repository with a single commit
41 Start with a simple repository with a single commit
42
42
43 $ hg init repo
43 $ hg init repo
44 $ cd repo
44 $ cd repo
45 $ cat > .hg/hgrc << EOF
45 $ cat > .hg/hgrc << EOF
46 > [extensions]
46 > [extensions]
47 > bundle2=$TESTTMP/bundle2.py
47 > bundle2=$TESTTMP/bundle2.py
48 > EOF
48 > EOF
49
49
50 $ echo A > A
50 $ echo A > A
51 $ hg commit -A -m A -q
51 $ hg commit -A -m A -q
52 $ cd ..
52 $ cd ..
53
53
54 Clone
54 Clone
55
55
56 $ hg clone -q repo clone
56 $ hg clone -q repo clone
57
57
58 Add two linear commits
58 Add two linear commits
59
59
60 $ cd repo
60 $ cd repo
61 $ echo B > B
61 $ echo B > B
62 $ hg commit -A -m B -q
62 $ hg commit -A -m B -q
63 $ echo C > C
63 $ echo C > C
64 $ hg commit -A -m C -q
64 $ hg commit -A -m C -q
65
65
66 $ cd ../clone
66 $ cd ../clone
67 $ cat >> .hg/hgrc <<EOF
67 $ cat >> .hg/hgrc <<EOF
68 > [hooks]
68 > [hooks]
69 > pretxnchangegroup = sh -c "printenv.py pretxnchangegroup"
69 > pretxnchangegroup = sh -c "printenv.py pretxnchangegroup"
70 > changegroup = sh -c "printenv.py changegroup"
70 > changegroup = sh -c "printenv.py changegroup"
71 > incoming = sh -c "printenv.py incoming"
71 > incoming = sh -c "printenv.py incoming"
72 > EOF
72 > EOF
73
73
74 Pull the new commits in the clone
74 Pull the new commits in the clone
75
75
76 $ hg pull
76 $ hg pull
77 pulling from $TESTTMP/repo (glob)
77 pulling from $TESTTMP/repo (glob)
78 searching for changes
78 searching for changes
79 remote: changegroup1
79 remote: changegroup1
80 adding changesets
80 adding changesets
81 adding manifests
81 adding manifests
82 adding file changes
82 adding file changes
83 added 1 changesets with 1 changes to 1 files
83 added 1 changesets with 1 changes to 1 files
84 pretxnchangegroup hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
84 pretxnchangegroup hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
85 remote: changegroup2
85 remote: changegroup2
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 1 changesets with 1 changes to 1 files
89 added 1 changesets with 1 changes to 1 files
90 pretxnchangegroup hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
90 pretxnchangegroup hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
91 changegroup hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
91 changegroup hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_NODE_LAST=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
92 incoming hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
92 incoming hook: HG_NODE=27547f69f25460a52fff66ad004e58da7ad3fb56 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
93 changegroup hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
93 changegroup hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_NODE_LAST=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
94 incoming hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
94 incoming hook: HG_NODE=f838bfaca5c7226600ebcfd84f3c3c13a28d3757 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
95 pullop.cgresult is 1
95 pullop.cgresult is 1
96 (run 'hg update' to get a working copy)
96 (run 'hg update' to get a working copy)
97 $ hg update
97 $ hg update
98 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 $ hg log -G
99 $ hg log -G
100 @ 2:f838bfaca5c7 public test C
100 @ 2:f838bfaca5c7 public test C
101 |
101 |
102 o 1:27547f69f254 public test B
102 o 1:27547f69f254 public test B
103 |
103 |
104 o 0:4a2df7238c3b public test A
104 o 0:4a2df7238c3b public test A
105
105
106 Add more changesets with multiple heads to the original repository
106 Add more changesets with multiple heads to the original repository
107
107
108 $ cd ../repo
108 $ cd ../repo
109 $ echo D > D
109 $ echo D > D
110 $ hg commit -A -m D -q
110 $ hg commit -A -m D -q
111 $ hg up -r 1
111 $ hg up -r 1
112 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
112 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
113 $ echo E > E
113 $ echo E > E
114 $ hg commit -A -m E -q
114 $ hg commit -A -m E -q
115 $ echo F > F
115 $ echo F > F
116 $ hg commit -A -m F -q
116 $ hg commit -A -m F -q
117 $ hg up -r 1
117 $ hg up -r 1
118 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
118 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
119 $ echo G > G
119 $ echo G > G
120 $ hg commit -A -m G -q
120 $ hg commit -A -m G -q
121 $ hg up -r 3
121 $ hg up -r 3
122 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
122 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
123 $ echo H > H
123 $ echo H > H
124 $ hg commit -A -m H -q
124 $ hg commit -A -m H -q
125 $ hg log -G
125 $ hg log -G
126 @ 7:5cd59d311f65 draft test H
126 @ 7:5cd59d311f65 draft test H
127 |
127 |
128 | o 6:1d14c3ce6ac0 draft test G
128 | o 6:1d14c3ce6ac0 draft test G
129 | |
129 | |
130 | | o 5:7f219660301f draft test F
130 | | o 5:7f219660301f draft test F
131 | | |
131 | | |
132 | | o 4:8a5212ebc852 draft test E
132 | | o 4:8a5212ebc852 draft test E
133 | |/
133 | |/
134 o | 3:b3325c91a4d9 draft test D
134 o | 3:b3325c91a4d9 draft test D
135 | |
135 | |
136 o | 2:f838bfaca5c7 draft test C
136 o | 2:f838bfaca5c7 draft test C
137 |/
137 |/
138 o 1:27547f69f254 draft test B
138 o 1:27547f69f254 draft test B
139 |
139 |
140 o 0:4a2df7238c3b draft test A
140 o 0:4a2df7238c3b draft test A
141
141
142 New heads are reported during transfer and properly accounted for in
142 New heads are reported during transfer and properly accounted for in
143 pullop.cgresult
143 pullop.cgresult
144
144
145 $ cd ../clone
145 $ cd ../clone
146 $ hg pull
146 $ hg pull
147 pulling from $TESTTMP/repo (glob)
147 pulling from $TESTTMP/repo (glob)
148 searching for changes
148 searching for changes
149 remote: changegroup1
149 remote: changegroup1
150 adding changesets
150 adding changesets
151 adding manifests
151 adding manifests
152 adding file changes
152 adding file changes
153 added 2 changesets with 2 changes to 2 files (+1 heads)
153 added 2 changesets with 2 changes to 2 files (+1 heads)
154 pretxnchangegroup hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
154 pretxnchangegroup hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
155 remote: changegroup2
155 remote: changegroup2
156 adding changesets
156 adding changesets
157 adding manifests
157 adding manifests
158 adding file changes
158 adding file changes
159 added 3 changesets with 3 changes to 3 files (+1 heads)
159 added 3 changesets with 3 changes to 3 files (+1 heads)
160 pretxnchangegroup hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
160 pretxnchangegroup hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
161 changegroup hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
161 changegroup hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_NODE_LAST=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
162 incoming hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
162 incoming hook: HG_NODE=b3325c91a4d916bcc4cdc83ea3fe4ece46a42f6e HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
163 incoming hook: HG_NODE=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
163 incoming hook: HG_NODE=8a5212ebc8527f9fb821601504794e3eb11a1ed3 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
164 changegroup hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
164 changegroup hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_NODE_LAST=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
165 incoming hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
165 incoming hook: HG_NODE=7f219660301fe4c8a116f714df5e769695cc2b46 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
166 incoming hook: HG_NODE=1d14c3ce6ac0582d2809220d33e8cd7a696e0156 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
166 incoming hook: HG_NODE=1d14c3ce6ac0582d2809220d33e8cd7a696e0156 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
167 incoming hook: HG_NODE=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
167 incoming hook: HG_NODE=5cd59d311f6508b8e0ed28a266756c859419c9f1 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
168 pullop.cgresult is 3
168 pullop.cgresult is 3
169 (run 'hg heads' to see heads, 'hg merge' to merge)
169 (run 'hg heads' to see heads, 'hg merge' to merge)
170 $ hg log -G
170 $ hg log -G
171 o 7:5cd59d311f65 public test H
171 o 7:5cd59d311f65 public test H
172 |
172 |
173 | o 6:1d14c3ce6ac0 public test G
173 | o 6:1d14c3ce6ac0 public test G
174 | |
174 | |
175 | | o 5:7f219660301f public test F
175 | | o 5:7f219660301f public test F
176 | | |
176 | | |
177 | | o 4:8a5212ebc852 public test E
177 | | o 4:8a5212ebc852 public test E
178 | |/
178 | |/
179 o | 3:b3325c91a4d9 public test D
179 o | 3:b3325c91a4d9 public test D
180 | |
180 | |
181 @ | 2:f838bfaca5c7 public test C
181 @ | 2:f838bfaca5c7 public test C
182 |/
182 |/
183 o 1:27547f69f254 public test B
183 o 1:27547f69f254 public test B
184 |
184 |
185 o 0:4a2df7238c3b public test A
185 o 0:4a2df7238c3b public test A
186
186
187 Removing a head from the original repository by merging it
187 Removing a head from the original repository by merging it
188
188
189 $ cd ../repo
189 $ cd ../repo
190 $ hg merge -r 6 -q
190 $ hg merge -r 6 -q
191 $ hg commit -m Merge
191 $ hg commit -m Merge
192 $ echo I > I
192 $ echo I > I
193 $ hg commit -A -m H -q
193 $ hg commit -A -m H -q
194 $ hg log -G
194 $ hg log -G
195 @ 9:9d18e5bd9ab0 draft test H
195 @ 9:9d18e5bd9ab0 draft test H
196 |
196 |
197 o 8:71bd7b46de72 draft test Merge
197 o 8:71bd7b46de72 draft test Merge
198 |\
198 |\
199 | o 7:5cd59d311f65 draft test H
199 | o 7:5cd59d311f65 draft test H
200 | |
200 | |
201 o | 6:1d14c3ce6ac0 draft test G
201 o | 6:1d14c3ce6ac0 draft test G
202 | |
202 | |
203 | | o 5:7f219660301f draft test F
203 | | o 5:7f219660301f draft test F
204 | | |
204 | | |
205 +---o 4:8a5212ebc852 draft test E
205 +---o 4:8a5212ebc852 draft test E
206 | |
206 | |
207 | o 3:b3325c91a4d9 draft test D
207 | o 3:b3325c91a4d9 draft test D
208 | |
208 | |
209 | o 2:f838bfaca5c7 draft test C
209 | o 2:f838bfaca5c7 draft test C
210 |/
210 |/
211 o 1:27547f69f254 draft test B
211 o 1:27547f69f254 draft test B
212 |
212 |
213 o 0:4a2df7238c3b draft test A
213 o 0:4a2df7238c3b draft test A
214
214
215 Removed heads are reported during transfer and properly accounted for in
215 Removed heads are reported during transfer and properly accounted for in
216 pullop.cgresult
216 pullop.cgresult
217
217
218 $ cd ../clone
218 $ cd ../clone
219 $ hg pull
219 $ hg pull
220 pulling from $TESTTMP/repo (glob)
220 pulling from $TESTTMP/repo (glob)
221 searching for changes
221 searching for changes
222 remote: changegroup1
222 remote: changegroup1
223 adding changesets
223 adding changesets
224 adding manifests
224 adding manifests
225 adding file changes
225 adding file changes
226 added 1 changesets with 0 changes to 0 files (-1 heads)
226 added 1 changesets with 0 changes to 0 files (-1 heads)
227 pretxnchangegroup hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
227 pretxnchangegroup hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_PENDING=$TESTTMP/clone HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
228 remote: changegroup2
228 remote: changegroup2
229 adding changesets
229 adding changesets
230 adding manifests
230 adding manifests
231 adding file changes
231 adding file changes
232 added 1 changesets with 1 changes to 1 files
232 added 1 changesets with 1 changes to 1 files
233 pretxnchangegroup hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
233 pretxnchangegroup hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PENDING=$TESTTMP/clone HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
234 changegroup hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
234 changegroup hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_NODE_LAST=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
235 incoming hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
235 incoming hook: HG_NODE=71bd7b46de72e69a32455bf88d04757d542e6cf4 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
236 changegroup hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
236 changegroup hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_NODE_LAST=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
237 incoming hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/repo (glob)
237 incoming hook: HG_NODE=9d18e5bd9ab09337802595d49f1dad0c98df4d84 HG_PHASES_MOVED=1 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/repo
238 pullop.cgresult is -2
238 pullop.cgresult is -2
239 (run 'hg update' to get a working copy)
239 (run 'hg update' to get a working copy)
240 $ hg log -G
240 $ hg log -G
241 o 9:9d18e5bd9ab0 public test H
241 o 9:9d18e5bd9ab0 public test H
242 |
242 |
243 o 8:71bd7b46de72 public test Merge
243 o 8:71bd7b46de72 public test Merge
244 |\
244 |\
245 | o 7:5cd59d311f65 public test H
245 | o 7:5cd59d311f65 public test H
246 | |
246 | |
247 o | 6:1d14c3ce6ac0 public test G
247 o | 6:1d14c3ce6ac0 public test G
248 | |
248 | |
249 | | o 5:7f219660301f public test F
249 | | o 5:7f219660301f public test F
250 | | |
250 | | |
251 +---o 4:8a5212ebc852 public test E
251 +---o 4:8a5212ebc852 public test E
252 | |
252 | |
253 | o 3:b3325c91a4d9 public test D
253 | o 3:b3325c91a4d9 public test D
254 | |
254 | |
255 | @ 2:f838bfaca5c7 public test C
255 | @ 2:f838bfaca5c7 public test C
256 |/
256 |/
257 o 1:27547f69f254 public test B
257 o 1:27547f69f254 public test B
258 |
258 |
259 o 0:4a2df7238c3b public test A
259 o 0:4a2df7238c3b public test A
260
260
@@ -1,935 +1,935 b''
1 commit hooks can see env vars
1 commit hooks can see env vars
2 (and post-transaction one are run unlocked)
2 (and post-transaction one are run unlocked)
3
3
4
4
5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
5 $ cat > $TESTTMP/txnabort.checkargs.py <<EOF
6 > def showargs(ui, repo, hooktype, **kwargs):
6 > def showargs(ui, repo, hooktype, **kwargs):
7 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
7 > ui.write('%s python hook: %s\n' % (hooktype, ','.join(sorted(kwargs))))
8 > EOF
8 > EOF
9
9
10 $ hg init a
10 $ hg init a
11 $ cd a
11 $ cd a
12 $ cat > .hg/hgrc <<EOF
12 $ cat > .hg/hgrc <<EOF
13 > [hooks]
13 > [hooks]
14 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
14 > commit = sh -c "HG_LOCAL= HG_TAG= printenv.py commit"
15 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
15 > commit.b = sh -c "HG_LOCAL= HG_TAG= printenv.py commit.b"
16 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
16 > precommit = sh -c "HG_LOCAL= HG_NODE= HG_TAG= printenv.py precommit"
17 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
17 > pretxncommit = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxncommit"
18 > pretxncommit.tip = hg -q tip
18 > pretxncommit.tip = hg -q tip
19 > pre-identify = sh -c "printenv.py pre-identify 1"
19 > pre-identify = sh -c "printenv.py pre-identify 1"
20 > pre-cat = sh -c "printenv.py pre-cat"
20 > pre-cat = sh -c "printenv.py pre-cat"
21 > post-cat = sh -c "printenv.py post-cat"
21 > post-cat = sh -c "printenv.py post-cat"
22 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
22 > pretxnopen = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnopen"
23 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
23 > pretxnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py pretxnclose"
24 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
24 > txnclose = sh -c "HG_LOCAL= HG_TAG= printenv.py txnclose"
25 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
25 > txnabort.0 = python:$TESTTMP/txnabort.checkargs.py:showargs
26 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
26 > txnabort.1 = sh -c "HG_LOCAL= HG_TAG= printenv.py txnabort"
27 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
27 > txnclose.checklock = sh -c "hg debuglock > /dev/null"
28 > EOF
28 > EOF
29 $ echo a > a
29 $ echo a > a
30 $ hg add a
30 $ hg add a
31 $ hg commit -m a
31 $ hg commit -m a
32 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
32 precommit hook: HG_PARENT1=0000000000000000000000000000000000000000
33 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
33 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
34 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
34 pretxncommit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000 HG_PENDING=$TESTTMP/a
35 0:cb9a9f314b8b
35 0:cb9a9f314b8b
36 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
36 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
37 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
37 txnclose hook: HG_PHASES_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
38 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
38 commit hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
39 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
39 commit.b hook: HG_NODE=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PARENT1=0000000000000000000000000000000000000000
40
40
41 $ hg clone . ../b
41 $ hg clone . ../b
42 updating to branch default
42 updating to branch default
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
43 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 $ cd ../b
44 $ cd ../b
45
45
46 changegroup hooks can see env vars
46 changegroup hooks can see env vars
47
47
48 $ cat > .hg/hgrc <<EOF
48 $ cat > .hg/hgrc <<EOF
49 > [hooks]
49 > [hooks]
50 > prechangegroup = sh -c "printenv.py prechangegroup"
50 > prechangegroup = sh -c "printenv.py prechangegroup"
51 > changegroup = sh -c "printenv.py changegroup"
51 > changegroup = sh -c "printenv.py changegroup"
52 > incoming = sh -c "printenv.py incoming"
52 > incoming = sh -c "printenv.py incoming"
53 > EOF
53 > EOF
54
54
55 pretxncommit and commit hooks can see both parents of merge
55 pretxncommit and commit hooks can see both parents of merge
56
56
57 $ cd ../a
57 $ cd ../a
58 $ echo b >> a
58 $ echo b >> a
59 $ hg commit -m a1 -d "1 0"
59 $ hg commit -m a1 -d "1 0"
60 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
60 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
61 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
61 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
62 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
62 pretxncommit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
63 1:ab228980c14d
63 1:ab228980c14d
64 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
64 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
65 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
65 txnclose hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
66 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
66 commit hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
67 commit.b hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
68 $ hg update -C 0
68 $ hg update -C 0
69 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 $ echo b > b
70 $ echo b > b
71 $ hg add b
71 $ hg add b
72 $ hg commit -m b -d '1 0'
72 $ hg commit -m b -d '1 0'
73 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
73 precommit hook: HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
74 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
74 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
75 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
75 pretxncommit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b HG_PENDING=$TESTTMP/a
76 2:ee9deb46ab31
76 2:ee9deb46ab31
77 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
77 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
78 created new head
78 created new head
79 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
79 txnclose hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
80 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
80 commit hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
81 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
81 commit.b hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT1=cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b
82 $ hg merge 1
82 $ hg merge 1
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
83 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 (branch merge, don't forget to commit)
84 (branch merge, don't forget to commit)
85 $ hg commit -m merge -d '2 0'
85 $ hg commit -m merge -d '2 0'
86 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
86 precommit hook: HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
87 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
87 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
88 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
88 pretxncommit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd HG_PENDING=$TESTTMP/a
89 3:07f3376c1e65
89 3:07f3376c1e65
90 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
90 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
91 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
91 txnclose hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
92 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
92 commit hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
93 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
93 commit.b hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PARENT1=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_PARENT2=ab228980c14deea8b9555d91c9581127383e40fd
94
94
95 test generic hooks
95 test generic hooks
96
96
97 $ hg id
97 $ hg id
98 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
98 pre-identify hook: HG_ARGS=id HG_OPTS={'bookmarks': None, 'branch': None, 'id': None, 'insecure': None, 'num': None, 'remotecmd': '', 'rev': '', 'ssh': '', 'tags': None} HG_PATS=[]
99 abort: pre-identify hook exited with status 1
99 abort: pre-identify hook exited with status 1
100 [255]
100 [255]
101 $ hg cat b
101 $ hg cat b
102 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
102 pre-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b']
103 b
103 b
104 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
104 post-cat hook: HG_ARGS=cat b HG_OPTS={'decode': None, 'exclude': [], 'include': [], 'output': '', 'rev': ''} HG_PATS=['b'] HG_RESULT=0
105
105
106 $ cd ../b
106 $ cd ../b
107 $ hg pull ../a
107 $ hg pull ../a
108 pulling from ../a
108 pulling from ../a
109 searching for changes
109 searching for changes
110 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
110 prechangegroup hook: HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
111 adding changesets
111 adding changesets
112 adding manifests
112 adding manifests
113 adding file changes
113 adding file changes
114 added 3 changesets with 2 changes to 2 files
114 added 3 changesets with 2 changes to 2 files
115 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
115 changegroup hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_NODE_LAST=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
116 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
116 incoming hook: HG_NODE=ab228980c14deea8b9555d91c9581127383e40fd HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
117 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
117 incoming hook: HG_NODE=ee9deb46ab31e4cc3310f3cf0c3d668e4d8fffc2 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
118 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
118 incoming hook: HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
119 (run 'hg update' to get a working copy)
119 (run 'hg update' to get a working copy)
120
120
121 tag hooks can see env vars
121 tag hooks can see env vars
122
122
123 $ cd ../a
123 $ cd ../a
124 $ cat >> .hg/hgrc <<EOF
124 $ cat >> .hg/hgrc <<EOF
125 > pretag = sh -c "printenv.py pretag"
125 > pretag = sh -c "printenv.py pretag"
126 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
126 > tag = sh -c "HG_PARENT1= HG_PARENT2= printenv.py tag"
127 > EOF
127 > EOF
128 $ hg tag -d '3 0' a
128 $ hg tag -d '3 0' a
129 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
129 pretag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
130 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
130 precommit hook: HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
131 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
131 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
132 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
132 pretxncommit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2 HG_PENDING=$TESTTMP/a
133 4:539e4b31b6dc
133 4:539e4b31b6dc
134 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
134 pretxnclose hook: HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
135 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
135 tag hook: HG_LOCAL=0 HG_NODE=07f3376c1e655977439df2a814e3cc14b27abac2 HG_TAG=a
136 txnclose hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
136 txnclose hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
137 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
137 commit hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
138 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
138 commit.b hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PARENT1=07f3376c1e655977439df2a814e3cc14b27abac2
139 $ hg tag -l la
139 $ hg tag -l la
140 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
140 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
141 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
141 tag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=la
142
142
143 pretag hook can forbid tagging
143 pretag hook can forbid tagging
144
144
145 $ cat >> .hg/hgrc <<EOF
145 $ cat >> .hg/hgrc <<EOF
146 > pretag.forbid = sh -c "printenv.py pretag.forbid 1"
146 > pretag.forbid = sh -c "printenv.py pretag.forbid 1"
147 > EOF
147 > EOF
148 $ hg tag -d '4 0' fa
148 $ hg tag -d '4 0' fa
149 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
149 pretag hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
150 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
150 pretag.forbid hook: HG_LOCAL=0 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fa
151 abort: pretag.forbid hook exited with status 1
151 abort: pretag.forbid hook exited with status 1
152 [255]
152 [255]
153 $ hg tag -l fla
153 $ hg tag -l fla
154 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
154 pretag hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
155 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
155 pretag.forbid hook: HG_LOCAL=1 HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_TAG=fla
156 abort: pretag.forbid hook exited with status 1
156 abort: pretag.forbid hook exited with status 1
157 [255]
157 [255]
158
158
159 pretxncommit hook can see changeset, can roll back txn, changeset no
159 pretxncommit hook can see changeset, can roll back txn, changeset no
160 more there after
160 more there after
161
161
162 $ cat >> .hg/hgrc <<EOF
162 $ cat >> .hg/hgrc <<EOF
163 > pretxncommit.forbid0 = sh -c "hg tip -q"
163 > pretxncommit.forbid0 = sh -c "hg tip -q"
164 > pretxncommit.forbid1 = sh -c "printenv.py pretxncommit.forbid 1"
164 > pretxncommit.forbid1 = sh -c "printenv.py pretxncommit.forbid 1"
165 > EOF
165 > EOF
166 $ echo z > z
166 $ echo z > z
167 $ hg add z
167 $ hg add z
168 $ hg -q tip
168 $ hg -q tip
169 4:539e4b31b6dc
169 4:539e4b31b6dc
170 $ hg commit -m 'fail' -d '4 0'
170 $ hg commit -m 'fail' -d '4 0'
171 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
171 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
172 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
172 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
173 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
173 pretxncommit hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
174 5:6f611f8018c1
174 5:6f611f8018c1
175 5:6f611f8018c1
175 5:6f611f8018c1
176 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
176 pretxncommit.forbid hook: HG_NODE=6f611f8018c10e827fee6bd2bc807f937e761567 HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/a
177 transaction abort!
177 transaction abort!
178 txnabort python hook: txnid,txnname
178 txnabort python hook: txnid,txnname
179 txnabort hook: HG_TXNID=TXN:* HG_TXNNAME=commit (glob)
179 txnabort hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=commit
180 rollback completed
180 rollback completed
181 abort: pretxncommit.forbid1 hook exited with status 1
181 abort: pretxncommit.forbid1 hook exited with status 1
182 [255]
182 [255]
183 $ hg -q tip
183 $ hg -q tip
184 4:539e4b31b6dc
184 4:539e4b31b6dc
185
185
186 (Check that no 'changelog.i.a' file were left behind)
186 (Check that no 'changelog.i.a' file were left behind)
187
187
188 $ ls -1 .hg/store/
188 $ ls -1 .hg/store/
189 00changelog.i
189 00changelog.i
190 00manifest.i
190 00manifest.i
191 data
191 data
192 fncache
192 fncache
193 journal.phaseroots
193 journal.phaseroots
194 phaseroots
194 phaseroots
195 undo
195 undo
196 undo.backup.fncache
196 undo.backup.fncache
197 undo.backupfiles
197 undo.backupfiles
198 undo.phaseroots
198 undo.phaseroots
199
199
200
200
201 precommit hook can prevent commit
201 precommit hook can prevent commit
202
202
203 $ cat >> .hg/hgrc <<EOF
203 $ cat >> .hg/hgrc <<EOF
204 > precommit.forbid = sh -c "printenv.py precommit.forbid 1"
204 > precommit.forbid = sh -c "printenv.py precommit.forbid 1"
205 > EOF
205 > EOF
206 $ hg commit -m 'fail' -d '4 0'
206 $ hg commit -m 'fail' -d '4 0'
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
207 precommit hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
208 precommit.forbid hook: HG_PARENT1=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10
209 abort: precommit.forbid hook exited with status 1
209 abort: precommit.forbid hook exited with status 1
210 [255]
210 [255]
211 $ hg -q tip
211 $ hg -q tip
212 4:539e4b31b6dc
212 4:539e4b31b6dc
213
213
214 preupdate hook can prevent update
214 preupdate hook can prevent update
215
215
216 $ cat >> .hg/hgrc <<EOF
216 $ cat >> .hg/hgrc <<EOF
217 > preupdate = sh -c "printenv.py preupdate"
217 > preupdate = sh -c "printenv.py preupdate"
218 > EOF
218 > EOF
219 $ hg update 1
219 $ hg update 1
220 preupdate hook: HG_PARENT1=ab228980c14d
220 preupdate hook: HG_PARENT1=ab228980c14d
221 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
221 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
222
222
223 update hook
223 update hook
224
224
225 $ cat >> .hg/hgrc <<EOF
225 $ cat >> .hg/hgrc <<EOF
226 > update = sh -c "printenv.py update"
226 > update = sh -c "printenv.py update"
227 > EOF
227 > EOF
228 $ hg update
228 $ hg update
229 preupdate hook: HG_PARENT1=539e4b31b6dc
229 preupdate hook: HG_PARENT1=539e4b31b6dc
230 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
230 update hook: HG_ERROR=0 HG_PARENT1=539e4b31b6dc
231 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
232
232
233 pushkey hook
233 pushkey hook
234
234
235 $ cat >> .hg/hgrc <<EOF
235 $ cat >> .hg/hgrc <<EOF
236 > pushkey = sh -c "printenv.py pushkey"
236 > pushkey = sh -c "printenv.py pushkey"
237 > EOF
237 > EOF
238 $ cd ../b
238 $ cd ../b
239 $ hg bookmark -r null foo
239 $ hg bookmark -r null foo
240 $ hg push -B foo ../a
240 $ hg push -B foo ../a
241 pushing to ../a
241 pushing to ../a
242 searching for changes
242 searching for changes
243 no changes found
243 no changes found
244 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
244 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=push
245 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=file:$TESTTMP/a (glob)
245 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_PENDING=$TESTTMP/a HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/a
246 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
246 pushkey hook: HG_KEY=foo HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_RET=1
247 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:* HG_TXNNAME=push HG_URL=file:$TESTTMP/a (glob)
247 txnclose hook: HG_BOOKMARK_MOVED=1 HG_BUNDLE2=1 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_TXNNAME=push HG_URL=file:$TESTTMP/a
248 exporting bookmark foo
248 exporting bookmark foo
249 [1]
249 [1]
250 $ cd ../a
250 $ cd ../a
251
251
252 listkeys hook
252 listkeys hook
253
253
254 $ cat >> .hg/hgrc <<EOF
254 $ cat >> .hg/hgrc <<EOF
255 > listkeys = sh -c "printenv.py listkeys"
255 > listkeys = sh -c "printenv.py listkeys"
256 > EOF
256 > EOF
257 $ hg bookmark -r null bar
257 $ hg bookmark -r null bar
258 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
258 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
259 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
259 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
260 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
260 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
261 $ cd ../b
261 $ cd ../b
262 $ hg pull -B bar ../a
262 $ hg pull -B bar ../a
263 pulling from ../a
263 pulling from ../a
264 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
264 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
265 no changes found
265 no changes found
266 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
266 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
267 adding remote bookmark bar
267 adding remote bookmark bar
268 $ cd ../a
268 $ cd ../a
269
269
270 test that prepushkey can prevent incoming keys
270 test that prepushkey can prevent incoming keys
271
271
272 $ cat >> .hg/hgrc <<EOF
272 $ cat >> .hg/hgrc <<EOF
273 > prepushkey = sh -c "printenv.py prepushkey.forbid 1"
273 > prepushkey = sh -c "printenv.py prepushkey.forbid 1"
274 > EOF
274 > EOF
275 $ cd ../b
275 $ cd ../b
276 $ hg bookmark -r null baz
276 $ hg bookmark -r null baz
277 $ hg push -B baz ../a
277 $ hg push -B baz ../a
278 pushing to ../a
278 pushing to ../a
279 searching for changes
279 searching for changes
280 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
280 listkeys hook: HG_NAMESPACE=phases HG_VALUES={'cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b': '1', 'publishing': 'True'}
281 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
281 listkeys hook: HG_NAMESPACE=bookmarks HG_VALUES={'bar': '0000000000000000000000000000000000000000', 'foo': '0000000000000000000000000000000000000000'}
282 no changes found
282 no changes found
283 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=push (glob)
283 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=push
284 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
284 prepushkey.forbid hook: HG_BUNDLE2=1 HG_KEY=baz HG_NAMESPACE=bookmarks HG_NEW=0000000000000000000000000000000000000000 HG_SOURCE=push HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
285 pushkey-abort: prepushkey hook exited with status 1
285 pushkey-abort: prepushkey hook exited with status 1
286 abort: exporting bookmark baz failed!
286 abort: exporting bookmark baz failed!
287 [255]
287 [255]
288 $ cd ../a
288 $ cd ../a
289
289
290 test that prelistkeys can prevent listing keys
290 test that prelistkeys can prevent listing keys
291
291
292 $ cat >> .hg/hgrc <<EOF
292 $ cat >> .hg/hgrc <<EOF
293 > prelistkeys = sh -c "printenv.py prelistkeys.forbid 1"
293 > prelistkeys = sh -c "printenv.py prelistkeys.forbid 1"
294 > EOF
294 > EOF
295 $ hg bookmark -r null quux
295 $ hg bookmark -r null quux
296 pretxnopen hook: HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
296 pretxnopen hook: HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
297 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
297 pretxnclose hook: HG_BOOKMARK_MOVED=1 HG_PENDING=$TESTTMP/a HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
298 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:* HG_TXNNAME=bookmark (glob)
298 txnclose hook: HG_BOOKMARK_MOVED=1 HG_TXNID=TXN:$ID$ HG_TXNNAME=bookmark
299 $ cd ../b
299 $ cd ../b
300 $ hg pull -B quux ../a
300 $ hg pull -B quux ../a
301 pulling from ../a
301 pulling from ../a
302 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
302 prelistkeys.forbid hook: HG_NAMESPACE=bookmarks
303 abort: prelistkeys hook exited with status 1
303 abort: prelistkeys hook exited with status 1
304 [255]
304 [255]
305 $ cd ../a
305 $ cd ../a
306 $ rm .hg/hgrc
306 $ rm .hg/hgrc
307
307
308 prechangegroup hook can prevent incoming changes
308 prechangegroup hook can prevent incoming changes
309
309
310 $ cd ../b
310 $ cd ../b
311 $ hg -q tip
311 $ hg -q tip
312 3:07f3376c1e65
312 3:07f3376c1e65
313 $ cat > .hg/hgrc <<EOF
313 $ cat > .hg/hgrc <<EOF
314 > [hooks]
314 > [hooks]
315 > prechangegroup.forbid = sh -c "printenv.py prechangegroup.forbid 1"
315 > prechangegroup.forbid = sh -c "printenv.py prechangegroup.forbid 1"
316 > EOF
316 > EOF
317 $ hg pull ../a
317 $ hg pull ../a
318 pulling from ../a
318 pulling from ../a
319 searching for changes
319 searching for changes
320 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
320 prechangegroup.forbid hook: HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
321 abort: prechangegroup.forbid hook exited with status 1
321 abort: prechangegroup.forbid hook exited with status 1
322 [255]
322 [255]
323
323
324 pretxnchangegroup hook can see incoming changes, can roll back txn,
324 pretxnchangegroup hook can see incoming changes, can roll back txn,
325 incoming changes no longer there after
325 incoming changes no longer there after
326
326
327 $ cat > .hg/hgrc <<EOF
327 $ cat > .hg/hgrc <<EOF
328 > [hooks]
328 > [hooks]
329 > pretxnchangegroup.forbid0 = hg tip -q
329 > pretxnchangegroup.forbid0 = hg tip -q
330 > pretxnchangegroup.forbid1 = sh -c "printenv.py pretxnchangegroup.forbid 1"
330 > pretxnchangegroup.forbid1 = sh -c "printenv.py pretxnchangegroup.forbid 1"
331 > EOF
331 > EOF
332 $ hg pull ../a
332 $ hg pull ../a
333 pulling from ../a
333 pulling from ../a
334 searching for changes
334 searching for changes
335 adding changesets
335 adding changesets
336 adding manifests
336 adding manifests
337 adding file changes
337 adding file changes
338 added 1 changesets with 1 changes to 1 files
338 added 1 changesets with 1 changes to 1 files
339 4:539e4b31b6dc
339 4:539e4b31b6dc
340 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=file:$TESTTMP/a (glob)
340 pretxnchangegroup.forbid hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_NODE_LAST=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_PENDING=$TESTTMP/b HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=file:$TESTTMP/a
341 transaction abort!
341 transaction abort!
342 rollback completed
342 rollback completed
343 abort: pretxnchangegroup.forbid1 hook exited with status 1
343 abort: pretxnchangegroup.forbid1 hook exited with status 1
344 [255]
344 [255]
345 $ hg -q tip
345 $ hg -q tip
346 3:07f3376c1e65
346 3:07f3376c1e65
347
347
348 outgoing hooks can see env vars
348 outgoing hooks can see env vars
349
349
350 $ rm .hg/hgrc
350 $ rm .hg/hgrc
351 $ cat > ../a/.hg/hgrc <<EOF
351 $ cat > ../a/.hg/hgrc <<EOF
352 > [hooks]
352 > [hooks]
353 > preoutgoing = sh -c "printenv.py preoutgoing"
353 > preoutgoing = sh -c "printenv.py preoutgoing"
354 > outgoing = sh -c "printenv.py outgoing"
354 > outgoing = sh -c "printenv.py outgoing"
355 > EOF
355 > EOF
356 $ hg pull ../a
356 $ hg pull ../a
357 pulling from ../a
357 pulling from ../a
358 searching for changes
358 searching for changes
359 preoutgoing hook: HG_SOURCE=pull
359 preoutgoing hook: HG_SOURCE=pull
360 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
360 outgoing hook: HG_NODE=539e4b31b6dc99b3cfbaa6b53cbc1c1f9a1e3a10 HG_SOURCE=pull
361 adding changesets
361 adding changesets
362 adding manifests
362 adding manifests
363 adding file changes
363 adding file changes
364 added 1 changesets with 1 changes to 1 files
364 added 1 changesets with 1 changes to 1 files
365 adding remote bookmark quux
365 adding remote bookmark quux
366 (run 'hg update' to get a working copy)
366 (run 'hg update' to get a working copy)
367 $ hg rollback
367 $ hg rollback
368 repository tip rolled back to revision 3 (undo pull)
368 repository tip rolled back to revision 3 (undo pull)
369
369
370 preoutgoing hook can prevent outgoing changes
370 preoutgoing hook can prevent outgoing changes
371
371
372 $ cat >> ../a/.hg/hgrc <<EOF
372 $ cat >> ../a/.hg/hgrc <<EOF
373 > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
373 > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
374 > EOF
374 > EOF
375 $ hg pull ../a
375 $ hg pull ../a
376 pulling from ../a
376 pulling from ../a
377 searching for changes
377 searching for changes
378 preoutgoing hook: HG_SOURCE=pull
378 preoutgoing hook: HG_SOURCE=pull
379 preoutgoing.forbid hook: HG_SOURCE=pull
379 preoutgoing.forbid hook: HG_SOURCE=pull
380 abort: preoutgoing.forbid hook exited with status 1
380 abort: preoutgoing.forbid hook exited with status 1
381 [255]
381 [255]
382
382
383 outgoing hooks work for local clones
383 outgoing hooks work for local clones
384
384
385 $ cd ..
385 $ cd ..
386 $ cat > a/.hg/hgrc <<EOF
386 $ cat > a/.hg/hgrc <<EOF
387 > [hooks]
387 > [hooks]
388 > preoutgoing = sh -c "printenv.py preoutgoing"
388 > preoutgoing = sh -c "printenv.py preoutgoing"
389 > outgoing = sh -c "printenv.py outgoing"
389 > outgoing = sh -c "printenv.py outgoing"
390 > EOF
390 > EOF
391 $ hg clone a c
391 $ hg clone a c
392 preoutgoing hook: HG_SOURCE=clone
392 preoutgoing hook: HG_SOURCE=clone
393 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
393 outgoing hook: HG_NODE=0000000000000000000000000000000000000000 HG_SOURCE=clone
394 updating to branch default
394 updating to branch default
395 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
395 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
396 $ rm -rf c
396 $ rm -rf c
397
397
398 preoutgoing hook can prevent outgoing changes for local clones
398 preoutgoing hook can prevent outgoing changes for local clones
399
399
400 $ cat >> a/.hg/hgrc <<EOF
400 $ cat >> a/.hg/hgrc <<EOF
401 > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
401 > preoutgoing.forbid = sh -c "printenv.py preoutgoing.forbid 1"
402 > EOF
402 > EOF
403 $ hg clone a zzz
403 $ hg clone a zzz
404 preoutgoing hook: HG_SOURCE=clone
404 preoutgoing hook: HG_SOURCE=clone
405 preoutgoing.forbid hook: HG_SOURCE=clone
405 preoutgoing.forbid hook: HG_SOURCE=clone
406 abort: preoutgoing.forbid hook exited with status 1
406 abort: preoutgoing.forbid hook exited with status 1
407 [255]
407 [255]
408
408
409 $ cd "$TESTTMP/b"
409 $ cd "$TESTTMP/b"
410
410
411 $ cat > hooktests.py <<EOF
411 $ cat > hooktests.py <<EOF
412 > from mercurial import error
412 > from mercurial import error
413 >
413 >
414 > uncallable = 0
414 > uncallable = 0
415 >
415 >
416 > def printargs(args):
416 > def printargs(args):
417 > args.pop('ui', None)
417 > args.pop('ui', None)
418 > args.pop('repo', None)
418 > args.pop('repo', None)
419 > a = list(args.items())
419 > a = list(args.items())
420 > a.sort()
420 > a.sort()
421 > print 'hook args:'
421 > print 'hook args:'
422 > for k, v in a:
422 > for k, v in a:
423 > print ' ', k, v
423 > print ' ', k, v
424 >
424 >
425 > def passhook(**args):
425 > def passhook(**args):
426 > printargs(args)
426 > printargs(args)
427 >
427 >
428 > def failhook(**args):
428 > def failhook(**args):
429 > printargs(args)
429 > printargs(args)
430 > return True
430 > return True
431 >
431 >
432 > class LocalException(Exception):
432 > class LocalException(Exception):
433 > pass
433 > pass
434 >
434 >
435 > def raisehook(**args):
435 > def raisehook(**args):
436 > raise LocalException('exception from hook')
436 > raise LocalException('exception from hook')
437 >
437 >
438 > def aborthook(**args):
438 > def aborthook(**args):
439 > raise error.Abort('raise abort from hook')
439 > raise error.Abort('raise abort from hook')
440 >
440 >
441 > def brokenhook(**args):
441 > def brokenhook(**args):
442 > return 1 + {}
442 > return 1 + {}
443 >
443 >
444 > def verbosehook(ui, **args):
444 > def verbosehook(ui, **args):
445 > ui.note('verbose output from hook\n')
445 > ui.note('verbose output from hook\n')
446 >
446 >
447 > def printtags(ui, repo, **args):
447 > def printtags(ui, repo, **args):
448 > print sorted(repo.tags())
448 > print sorted(repo.tags())
449 >
449 >
450 > class container:
450 > class container:
451 > unreachable = 1
451 > unreachable = 1
452 > EOF
452 > EOF
453
453
454 $ cat > syntaxerror.py << EOF
454 $ cat > syntaxerror.py << EOF
455 > (foo
455 > (foo
456 > EOF
456 > EOF
457
457
458 test python hooks
458 test python hooks
459
459
460 #if windows
460 #if windows
461 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
461 $ PYTHONPATH="$TESTTMP/b;$PYTHONPATH"
462 #else
462 #else
463 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
463 $ PYTHONPATH="$TESTTMP/b:$PYTHONPATH"
464 #endif
464 #endif
465 $ export PYTHONPATH
465 $ export PYTHONPATH
466
466
467 $ echo '[hooks]' > ../a/.hg/hgrc
467 $ echo '[hooks]' > ../a/.hg/hgrc
468 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
468 $ echo 'preoutgoing.broken = python:hooktests.brokenhook' >> ../a/.hg/hgrc
469 $ hg pull ../a 2>&1 | grep 'raised an exception'
469 $ hg pull ../a 2>&1 | grep 'raised an exception'
470 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
470 error: preoutgoing.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
471
471
472 $ echo '[hooks]' > ../a/.hg/hgrc
472 $ echo '[hooks]' > ../a/.hg/hgrc
473 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
473 $ echo 'preoutgoing.raise = python:hooktests.raisehook' >> ../a/.hg/hgrc
474 $ hg pull ../a 2>&1 | grep 'raised an exception'
474 $ hg pull ../a 2>&1 | grep 'raised an exception'
475 error: preoutgoing.raise hook raised an exception: exception from hook
475 error: preoutgoing.raise hook raised an exception: exception from hook
476
476
477 $ echo '[hooks]' > ../a/.hg/hgrc
477 $ echo '[hooks]' > ../a/.hg/hgrc
478 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
478 $ echo 'preoutgoing.abort = python:hooktests.aborthook' >> ../a/.hg/hgrc
479 $ hg pull ../a
479 $ hg pull ../a
480 pulling from ../a
480 pulling from ../a
481 searching for changes
481 searching for changes
482 error: preoutgoing.abort hook failed: raise abort from hook
482 error: preoutgoing.abort hook failed: raise abort from hook
483 abort: raise abort from hook
483 abort: raise abort from hook
484 [255]
484 [255]
485
485
486 $ echo '[hooks]' > ../a/.hg/hgrc
486 $ echo '[hooks]' > ../a/.hg/hgrc
487 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
487 $ echo 'preoutgoing.fail = python:hooktests.failhook' >> ../a/.hg/hgrc
488 $ hg pull ../a
488 $ hg pull ../a
489 pulling from ../a
489 pulling from ../a
490 searching for changes
490 searching for changes
491 hook args:
491 hook args:
492 hooktype preoutgoing
492 hooktype preoutgoing
493 source pull
493 source pull
494 abort: preoutgoing.fail hook failed
494 abort: preoutgoing.fail hook failed
495 [255]
495 [255]
496
496
497 $ echo '[hooks]' > ../a/.hg/hgrc
497 $ echo '[hooks]' > ../a/.hg/hgrc
498 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
498 $ echo 'preoutgoing.uncallable = python:hooktests.uncallable' >> ../a/.hg/hgrc
499 $ hg pull ../a
499 $ hg pull ../a
500 pulling from ../a
500 pulling from ../a
501 searching for changes
501 searching for changes
502 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
502 abort: preoutgoing.uncallable hook is invalid: "hooktests.uncallable" is not callable
503 [255]
503 [255]
504
504
505 $ echo '[hooks]' > ../a/.hg/hgrc
505 $ echo '[hooks]' > ../a/.hg/hgrc
506 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
506 $ echo 'preoutgoing.nohook = python:hooktests.nohook' >> ../a/.hg/hgrc
507 $ hg pull ../a
507 $ hg pull ../a
508 pulling from ../a
508 pulling from ../a
509 searching for changes
509 searching for changes
510 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
510 abort: preoutgoing.nohook hook is invalid: "hooktests.nohook" is not defined
511 [255]
511 [255]
512
512
513 $ echo '[hooks]' > ../a/.hg/hgrc
513 $ echo '[hooks]' > ../a/.hg/hgrc
514 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
514 $ echo 'preoutgoing.nomodule = python:nomodule' >> ../a/.hg/hgrc
515 $ hg pull ../a
515 $ hg pull ../a
516 pulling from ../a
516 pulling from ../a
517 searching for changes
517 searching for changes
518 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
518 abort: preoutgoing.nomodule hook is invalid: "nomodule" not in a module
519 [255]
519 [255]
520
520
521 $ echo '[hooks]' > ../a/.hg/hgrc
521 $ echo '[hooks]' > ../a/.hg/hgrc
522 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
522 $ echo 'preoutgoing.badmodule = python:nomodule.nowhere' >> ../a/.hg/hgrc
523 $ hg pull ../a
523 $ hg pull ../a
524 pulling from ../a
524 pulling from ../a
525 searching for changes
525 searching for changes
526 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
526 abort: preoutgoing.badmodule hook is invalid: import of "nomodule" failed
527 (run with --traceback for stack trace)
527 (run with --traceback for stack trace)
528 [255]
528 [255]
529
529
530 $ echo '[hooks]' > ../a/.hg/hgrc
530 $ echo '[hooks]' > ../a/.hg/hgrc
531 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
531 $ echo 'preoutgoing.unreachable = python:hooktests.container.unreachable' >> ../a/.hg/hgrc
532 $ hg pull ../a
532 $ hg pull ../a
533 pulling from ../a
533 pulling from ../a
534 searching for changes
534 searching for changes
535 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
535 abort: preoutgoing.unreachable hook is invalid: import of "hooktests.container" failed
536 (run with --traceback for stack trace)
536 (run with --traceback for stack trace)
537 [255]
537 [255]
538
538
539 $ echo '[hooks]' > ../a/.hg/hgrc
539 $ echo '[hooks]' > ../a/.hg/hgrc
540 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
540 $ echo 'preoutgoing.syntaxerror = python:syntaxerror.syntaxerror' >> ../a/.hg/hgrc
541 $ hg pull ../a
541 $ hg pull ../a
542 pulling from ../a
542 pulling from ../a
543 searching for changes
543 searching for changes
544 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
544 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
545 (run with --traceback for stack trace)
545 (run with --traceback for stack trace)
546 [255]
546 [255]
547
547
548 The second egrep is to filter out lines like ' ^', which are slightly
548 The second egrep is to filter out lines like ' ^', which are slightly
549 different between Python 2.6 and Python 2.7.
549 different between Python 2.6 and Python 2.7.
550 $ hg pull ../a --traceback 2>&1 | egrep -v '^( +File| [_a-zA-Z*(])' | egrep -v '^( )+(\^)?$'
550 $ hg pull ../a --traceback 2>&1 | egrep -v '^( +File| [_a-zA-Z*(])' | egrep -v '^( )+(\^)?$'
551 pulling from ../a
551 pulling from ../a
552 searching for changes
552 searching for changes
553 exception from first failed import attempt:
553 exception from first failed import attempt:
554 Traceback (most recent call last):
554 Traceback (most recent call last):
555 SyntaxError: * (glob)
555 SyntaxError: * (glob)
556 exception from second failed import attempt:
556 exception from second failed import attempt:
557 Traceback (most recent call last):
557 Traceback (most recent call last):
558 ImportError: No module named hgext_syntaxerror
558 ImportError: No module named hgext_syntaxerror
559 Traceback (most recent call last):
559 Traceback (most recent call last):
560 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
560 HookLoadError: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
561 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
561 abort: preoutgoing.syntaxerror hook is invalid: import of "syntaxerror" failed
562
562
563 $ echo '[hooks]' > ../a/.hg/hgrc
563 $ echo '[hooks]' > ../a/.hg/hgrc
564 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
564 $ echo 'preoutgoing.pass = python:hooktests.passhook' >> ../a/.hg/hgrc
565 $ hg pull ../a
565 $ hg pull ../a
566 pulling from ../a
566 pulling from ../a
567 searching for changes
567 searching for changes
568 hook args:
568 hook args:
569 hooktype preoutgoing
569 hooktype preoutgoing
570 source pull
570 source pull
571 adding changesets
571 adding changesets
572 adding manifests
572 adding manifests
573 adding file changes
573 adding file changes
574 added 1 changesets with 1 changes to 1 files
574 added 1 changesets with 1 changes to 1 files
575 adding remote bookmark quux
575 adding remote bookmark quux
576 (run 'hg update' to get a working copy)
576 (run 'hg update' to get a working copy)
577
577
578 post- python hooks that fail to *run* don't cause an abort
578 post- python hooks that fail to *run* don't cause an abort
579 $ rm ../a/.hg/hgrc
579 $ rm ../a/.hg/hgrc
580 $ echo '[hooks]' > .hg/hgrc
580 $ echo '[hooks]' > .hg/hgrc
581 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
581 $ echo 'post-pull.broken = python:hooktests.brokenhook' >> .hg/hgrc
582 $ hg pull ../a
582 $ hg pull ../a
583 pulling from ../a
583 pulling from ../a
584 searching for changes
584 searching for changes
585 no changes found
585 no changes found
586 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
586 error: post-pull.broken hook raised an exception: unsupported operand type(s) for +: 'int' and 'dict'
587 (run with --traceback for stack trace)
587 (run with --traceback for stack trace)
588
588
589 but post- python hooks that fail to *load* do
589 but post- python hooks that fail to *load* do
590 $ echo '[hooks]' > .hg/hgrc
590 $ echo '[hooks]' > .hg/hgrc
591 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
591 $ echo 'post-pull.nomodule = python:nomodule' >> .hg/hgrc
592 $ hg pull ../a
592 $ hg pull ../a
593 pulling from ../a
593 pulling from ../a
594 searching for changes
594 searching for changes
595 no changes found
595 no changes found
596 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
596 abort: post-pull.nomodule hook is invalid: "nomodule" not in a module
597 [255]
597 [255]
598
598
599 $ echo '[hooks]' > .hg/hgrc
599 $ echo '[hooks]' > .hg/hgrc
600 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
600 $ echo 'post-pull.badmodule = python:nomodule.nowhere' >> .hg/hgrc
601 $ hg pull ../a
601 $ hg pull ../a
602 pulling from ../a
602 pulling from ../a
603 searching for changes
603 searching for changes
604 no changes found
604 no changes found
605 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
605 abort: post-pull.badmodule hook is invalid: import of "nomodule" failed
606 (run with --traceback for stack trace)
606 (run with --traceback for stack trace)
607 [255]
607 [255]
608
608
609 $ echo '[hooks]' > .hg/hgrc
609 $ echo '[hooks]' > .hg/hgrc
610 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
610 $ echo 'post-pull.nohook = python:hooktests.nohook' >> .hg/hgrc
611 $ hg pull ../a
611 $ hg pull ../a
612 pulling from ../a
612 pulling from ../a
613 searching for changes
613 searching for changes
614 no changes found
614 no changes found
615 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
615 abort: post-pull.nohook hook is invalid: "hooktests.nohook" is not defined
616 [255]
616 [255]
617
617
618 make sure --traceback works
618 make sure --traceback works
619
619
620 $ echo '[hooks]' > .hg/hgrc
620 $ echo '[hooks]' > .hg/hgrc
621 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
621 $ echo 'commit.abort = python:hooktests.aborthook' >> .hg/hgrc
622
622
623 $ echo aa > a
623 $ echo aa > a
624 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
624 $ hg --traceback commit -d '0 0' -ma 2>&1 | grep '^Traceback'
625 Traceback (most recent call last):
625 Traceback (most recent call last):
626
626
627 $ cd ..
627 $ cd ..
628 $ hg init c
628 $ hg init c
629 $ cd c
629 $ cd c
630
630
631 $ cat > hookext.py <<EOF
631 $ cat > hookext.py <<EOF
632 > def autohook(**args):
632 > def autohook(**args):
633 > print "Automatically installed hook"
633 > print "Automatically installed hook"
634 >
634 >
635 > def reposetup(ui, repo):
635 > def reposetup(ui, repo):
636 > repo.ui.setconfig("hooks", "commit.auto", autohook)
636 > repo.ui.setconfig("hooks", "commit.auto", autohook)
637 > EOF
637 > EOF
638 $ echo '[extensions]' >> .hg/hgrc
638 $ echo '[extensions]' >> .hg/hgrc
639 $ echo 'hookext = hookext.py' >> .hg/hgrc
639 $ echo 'hookext = hookext.py' >> .hg/hgrc
640
640
641 $ touch foo
641 $ touch foo
642 $ hg add foo
642 $ hg add foo
643 $ hg ci -d '0 0' -m 'add foo'
643 $ hg ci -d '0 0' -m 'add foo'
644 Automatically installed hook
644 Automatically installed hook
645 $ echo >> foo
645 $ echo >> foo
646 $ hg ci --debug -d '0 0' -m 'change foo'
646 $ hg ci --debug -d '0 0' -m 'change foo'
647 committing files:
647 committing files:
648 foo
648 foo
649 committing manifest
649 committing manifest
650 committing changelog
650 committing changelog
651 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
651 committed changeset 1:52998019f6252a2b893452765fcb0a47351a5708
652 calling hook commit.auto: hgext_hookext.autohook
652 calling hook commit.auto: hgext_hookext.autohook
653 Automatically installed hook
653 Automatically installed hook
654
654
655 $ hg showconfig hooks
655 $ hg showconfig hooks
656 hooks.commit.auto=<function autohook at *> (glob)
656 hooks.commit.auto=<function autohook at *> (glob)
657
657
658 test python hook configured with python:[file]:[hook] syntax
658 test python hook configured with python:[file]:[hook] syntax
659
659
660 $ cd ..
660 $ cd ..
661 $ mkdir d
661 $ mkdir d
662 $ cd d
662 $ cd d
663 $ hg init repo
663 $ hg init repo
664 $ mkdir hooks
664 $ mkdir hooks
665
665
666 $ cd hooks
666 $ cd hooks
667 $ cat > testhooks.py <<EOF
667 $ cat > testhooks.py <<EOF
668 > def testhook(**args):
668 > def testhook(**args):
669 > print 'hook works'
669 > print 'hook works'
670 > EOF
670 > EOF
671 $ echo '[hooks]' > ../repo/.hg/hgrc
671 $ echo '[hooks]' > ../repo/.hg/hgrc
672 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
672 $ echo "pre-commit.test = python:`pwd`/testhooks.py:testhook" >> ../repo/.hg/hgrc
673
673
674 $ cd ../repo
674 $ cd ../repo
675 $ hg commit -d '0 0'
675 $ hg commit -d '0 0'
676 hook works
676 hook works
677 nothing changed
677 nothing changed
678 [1]
678 [1]
679
679
680 $ echo '[hooks]' > .hg/hgrc
680 $ echo '[hooks]' > .hg/hgrc
681 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
681 $ echo "update.ne = python:`pwd`/nonexistent.py:testhook" >> .hg/hgrc
682 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
682 $ echo "pre-identify.npmd = python:`pwd`/:no_python_module_dir" >> .hg/hgrc
683
683
684 $ hg up null
684 $ hg up null
685 loading update.ne hook failed:
685 loading update.ne hook failed:
686 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
686 abort: No such file or directory: $TESTTMP/d/repo/nonexistent.py
687 [255]
687 [255]
688
688
689 $ hg id
689 $ hg id
690 loading pre-identify.npmd hook failed:
690 loading pre-identify.npmd hook failed:
691 abort: No module named repo!
691 abort: No module named repo!
692 [255]
692 [255]
693
693
694 $ cd ../../b
694 $ cd ../../b
695
695
696 make sure --traceback works on hook import failure
696 make sure --traceback works on hook import failure
697
697
698 $ cat > importfail.py <<EOF
698 $ cat > importfail.py <<EOF
699 > import somebogusmodule
699 > import somebogusmodule
700 > # dereference something in the module to force demandimport to load it
700 > # dereference something in the module to force demandimport to load it
701 > somebogusmodule.whatever
701 > somebogusmodule.whatever
702 > EOF
702 > EOF
703
703
704 $ echo '[hooks]' > .hg/hgrc
704 $ echo '[hooks]' > .hg/hgrc
705 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
705 $ echo 'precommit.importfail = python:importfail.whatever' >> .hg/hgrc
706
706
707 $ echo a >> a
707 $ echo a >> a
708 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
708 $ hg --traceback commit -ma 2>&1 | egrep -v '^( +File| [a-zA-Z(])'
709 exception from first failed import attempt:
709 exception from first failed import attempt:
710 Traceback (most recent call last):
710 Traceback (most recent call last):
711 ImportError: No module named somebogusmodule
711 ImportError: No module named somebogusmodule
712 exception from second failed import attempt:
712 exception from second failed import attempt:
713 Traceback (most recent call last):
713 Traceback (most recent call last):
714 ImportError: No module named hgext_importfail
714 ImportError: No module named hgext_importfail
715 Traceback (most recent call last):
715 Traceback (most recent call last):
716 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
716 HookLoadError: precommit.importfail hook is invalid: import of "importfail" failed
717 abort: precommit.importfail hook is invalid: import of "importfail" failed
717 abort: precommit.importfail hook is invalid: import of "importfail" failed
718
718
719 Issue1827: Hooks Update & Commit not completely post operation
719 Issue1827: Hooks Update & Commit not completely post operation
720
720
721 commit and update hooks should run after command completion. The largefiles
721 commit and update hooks should run after command completion. The largefiles
722 use demonstrates a recursive wlock, showing the hook doesn't run until the
722 use demonstrates a recursive wlock, showing the hook doesn't run until the
723 final release (and dirstate flush).
723 final release (and dirstate flush).
724
724
725 $ echo '[hooks]' > .hg/hgrc
725 $ echo '[hooks]' > .hg/hgrc
726 $ echo 'commit = hg id' >> .hg/hgrc
726 $ echo 'commit = hg id' >> .hg/hgrc
727 $ echo 'update = hg id' >> .hg/hgrc
727 $ echo 'update = hg id' >> .hg/hgrc
728 $ echo bb > a
728 $ echo bb > a
729 $ hg ci -ma
729 $ hg ci -ma
730 223eafe2750c tip
730 223eafe2750c tip
731 $ hg up 0 --config extensions.largefiles=
731 $ hg up 0 --config extensions.largefiles=
732 cb9a9f314b8b
732 cb9a9f314b8b
733 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
733 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
734
734
735 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
735 make sure --verbose (and --quiet/--debug etc.) are propagated to the local ui
736 that is passed to pre/post hooks
736 that is passed to pre/post hooks
737
737
738 $ echo '[hooks]' > .hg/hgrc
738 $ echo '[hooks]' > .hg/hgrc
739 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
739 $ echo 'pre-identify = python:hooktests.verbosehook' >> .hg/hgrc
740 $ hg id
740 $ hg id
741 cb9a9f314b8b
741 cb9a9f314b8b
742 $ hg id --verbose
742 $ hg id --verbose
743 calling hook pre-identify: hooktests.verbosehook
743 calling hook pre-identify: hooktests.verbosehook
744 verbose output from hook
744 verbose output from hook
745 cb9a9f314b8b
745 cb9a9f314b8b
746
746
747 Ensure hooks can be prioritized
747 Ensure hooks can be prioritized
748
748
749 $ echo '[hooks]' > .hg/hgrc
749 $ echo '[hooks]' > .hg/hgrc
750 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
750 $ echo 'pre-identify.a = python:hooktests.verbosehook' >> .hg/hgrc
751 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
751 $ echo 'pre-identify.b = python:hooktests.verbosehook' >> .hg/hgrc
752 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
752 $ echo 'priority.pre-identify.b = 1' >> .hg/hgrc
753 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
753 $ echo 'pre-identify.c = python:hooktests.verbosehook' >> .hg/hgrc
754 $ hg id --verbose
754 $ hg id --verbose
755 calling hook pre-identify.b: hooktests.verbosehook
755 calling hook pre-identify.b: hooktests.verbosehook
756 verbose output from hook
756 verbose output from hook
757 calling hook pre-identify.a: hooktests.verbosehook
757 calling hook pre-identify.a: hooktests.verbosehook
758 verbose output from hook
758 verbose output from hook
759 calling hook pre-identify.c: hooktests.verbosehook
759 calling hook pre-identify.c: hooktests.verbosehook
760 verbose output from hook
760 verbose output from hook
761 cb9a9f314b8b
761 cb9a9f314b8b
762
762
763 new tags must be visible in pretxncommit (issue3210)
763 new tags must be visible in pretxncommit (issue3210)
764
764
765 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
765 $ echo 'pretxncommit.printtags = python:hooktests.printtags' >> .hg/hgrc
766 $ hg tag -f foo
766 $ hg tag -f foo
767 ['a', 'foo', 'tip']
767 ['a', 'foo', 'tip']
768
768
769 post-init hooks must not crash (issue4983)
769 post-init hooks must not crash (issue4983)
770 This also creates the `to` repo for the next test block.
770 This also creates the `to` repo for the next test block.
771
771
772 $ cd ..
772 $ cd ..
773 $ cat << EOF >> hgrc-with-post-init-hook
773 $ cat << EOF >> hgrc-with-post-init-hook
774 > [hooks]
774 > [hooks]
775 > post-init = sh -c "printenv.py post-init"
775 > post-init = sh -c "printenv.py post-init"
776 > EOF
776 > EOF
777 $ HGRCPATH=hgrc-with-post-init-hook hg init to
777 $ HGRCPATH=hgrc-with-post-init-hook hg init to
778 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
778 post-init hook: HG_ARGS=init to HG_OPTS={'insecure': None, 'remotecmd': '', 'ssh': ''} HG_PATS=['to'] HG_RESULT=0
779
779
780 new commits must be visible in pretxnchangegroup (issue3428)
780 new commits must be visible in pretxnchangegroup (issue3428)
781
781
782 $ echo '[hooks]' >> to/.hg/hgrc
782 $ echo '[hooks]' >> to/.hg/hgrc
783 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
783 $ echo 'prechangegroup = hg --traceback tip' >> to/.hg/hgrc
784 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
784 $ echo 'pretxnchangegroup = hg --traceback tip' >> to/.hg/hgrc
785 $ echo a >> to/a
785 $ echo a >> to/a
786 $ hg --cwd to ci -Ama
786 $ hg --cwd to ci -Ama
787 adding a
787 adding a
788 $ hg clone to from
788 $ hg clone to from
789 updating to branch default
789 updating to branch default
790 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
791 $ echo aa >> from/a
791 $ echo aa >> from/a
792 $ hg --cwd from ci -mb
792 $ hg --cwd from ci -mb
793 $ hg --cwd from push
793 $ hg --cwd from push
794 pushing to $TESTTMP/to (glob)
794 pushing to $TESTTMP/to (glob)
795 searching for changes
795 searching for changes
796 changeset: 0:cb9a9f314b8b
796 changeset: 0:cb9a9f314b8b
797 tag: tip
797 tag: tip
798 user: test
798 user: test
799 date: Thu Jan 01 00:00:00 1970 +0000
799 date: Thu Jan 01 00:00:00 1970 +0000
800 summary: a
800 summary: a
801
801
802 adding changesets
802 adding changesets
803 adding manifests
803 adding manifests
804 adding file changes
804 adding file changes
805 added 1 changesets with 1 changes to 1 files
805 added 1 changesets with 1 changes to 1 files
806 changeset: 1:9836a07b9b9d
806 changeset: 1:9836a07b9b9d
807 tag: tip
807 tag: tip
808 user: test
808 user: test
809 date: Thu Jan 01 00:00:00 1970 +0000
809 date: Thu Jan 01 00:00:00 1970 +0000
810 summary: b
810 summary: b
811
811
812
812
813 pretxnclose hook failure should abort the transaction
813 pretxnclose hook failure should abort the transaction
814
814
815 $ hg init txnfailure
815 $ hg init txnfailure
816 $ cd txnfailure
816 $ cd txnfailure
817 $ touch a && hg commit -Aqm a
817 $ touch a && hg commit -Aqm a
818 $ cat >> .hg/hgrc <<EOF
818 $ cat >> .hg/hgrc <<EOF
819 > [hooks]
819 > [hooks]
820 > pretxnclose.error = exit 1
820 > pretxnclose.error = exit 1
821 > EOF
821 > EOF
822 $ hg strip -r 0 --config extensions.strip=
822 $ hg strip -r 0 --config extensions.strip=
823 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
823 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
824 saved backup bundle to * (glob)
824 saved backup bundle to * (glob)
825 transaction abort!
825 transaction abort!
826 rollback completed
826 rollback completed
827 strip failed, backup bundle stored in * (glob)
827 strip failed, backup bundle stored in * (glob)
828 abort: pretxnclose.error hook exited with status 1
828 abort: pretxnclose.error hook exited with status 1
829 [255]
829 [255]
830 $ hg recover
830 $ hg recover
831 no interrupted transaction available
831 no interrupted transaction available
832 [1]
832 [1]
833 $ cd ..
833 $ cd ..
834
834
835 check whether HG_PENDING makes pending changes only in related
835 check whether HG_PENDING makes pending changes only in related
836 repositories visible to an external hook.
836 repositories visible to an external hook.
837
837
838 (emulate a transaction running concurrently by copied
838 (emulate a transaction running concurrently by copied
839 .hg/store/00changelog.i.a in subsequent test)
839 .hg/store/00changelog.i.a in subsequent test)
840
840
841 $ cat > $TESTTMP/savepending.sh <<EOF
841 $ cat > $TESTTMP/savepending.sh <<EOF
842 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
842 > cp .hg/store/00changelog.i.a .hg/store/00changelog.i.a.saved
843 > exit 1 # to avoid adding new revision for subsequent tests
843 > exit 1 # to avoid adding new revision for subsequent tests
844 > EOF
844 > EOF
845 $ cd a
845 $ cd a
846 $ hg tip -q
846 $ hg tip -q
847 4:539e4b31b6dc
847 4:539e4b31b6dc
848 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
848 $ hg --config hooks.pretxnclose="sh $TESTTMP/savepending.sh" commit -m "invisible"
849 transaction abort!
849 transaction abort!
850 rollback completed
850 rollback completed
851 abort: pretxnclose hook exited with status 1
851 abort: pretxnclose hook exited with status 1
852 [255]
852 [255]
853 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
853 $ cp .hg/store/00changelog.i.a.saved .hg/store/00changelog.i.a
854
854
855 (check (in)visibility of new changeset while transaction running in
855 (check (in)visibility of new changeset while transaction running in
856 repo)
856 repo)
857
857
858 $ cat > $TESTTMP/checkpending.sh <<EOF
858 $ cat > $TESTTMP/checkpending.sh <<EOF
859 > echo '@a'
859 > echo '@a'
860 > hg -R $TESTTMP/a tip -q
860 > hg -R $TESTTMP/a tip -q
861 > echo '@a/nested'
861 > echo '@a/nested'
862 > hg -R $TESTTMP/a/nested tip -q
862 > hg -R $TESTTMP/a/nested tip -q
863 > exit 1 # to avoid adding new revision for subsequent tests
863 > exit 1 # to avoid adding new revision for subsequent tests
864 > EOF
864 > EOF
865 $ hg init nested
865 $ hg init nested
866 $ cd nested
866 $ cd nested
867 $ echo a > a
867 $ echo a > a
868 $ hg add a
868 $ hg add a
869 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
869 $ hg --config hooks.pretxnclose="sh $TESTTMP/checkpending.sh" commit -m '#0'
870 @a
870 @a
871 4:539e4b31b6dc
871 4:539e4b31b6dc
872 @a/nested
872 @a/nested
873 0:bf5e395ced2c
873 0:bf5e395ced2c
874 transaction abort!
874 transaction abort!
875 rollback completed
875 rollback completed
876 abort: pretxnclose hook exited with status 1
876 abort: pretxnclose hook exited with status 1
877 [255]
877 [255]
878
878
879 Hook from untrusted hgrc are reported as failure
879 Hook from untrusted hgrc are reported as failure
880 ================================================
880 ================================================
881
881
882 $ cat << EOF > $TESTTMP/untrusted.py
882 $ cat << EOF > $TESTTMP/untrusted.py
883 > from mercurial import scmutil, util
883 > from mercurial import scmutil, util
884 > def uisetup(ui):
884 > def uisetup(ui):
885 > class untrustedui(ui.__class__):
885 > class untrustedui(ui.__class__):
886 > def _trusted(self, fp, f):
886 > def _trusted(self, fp, f):
887 > if util.normpath(fp.name).endswith('untrusted/.hg/hgrc'):
887 > if util.normpath(fp.name).endswith('untrusted/.hg/hgrc'):
888 > return False
888 > return False
889 > return super(untrustedui, self)._trusted(fp, f)
889 > return super(untrustedui, self)._trusted(fp, f)
890 > ui.__class__ = untrustedui
890 > ui.__class__ = untrustedui
891 > EOF
891 > EOF
892 $ cat << EOF >> $HGRCPATH
892 $ cat << EOF >> $HGRCPATH
893 > [extensions]
893 > [extensions]
894 > untrusted=$TESTTMP/untrusted.py
894 > untrusted=$TESTTMP/untrusted.py
895 > EOF
895 > EOF
896 $ hg init untrusted
896 $ hg init untrusted
897 $ cd untrusted
897 $ cd untrusted
898
898
899 Non-blocking hook
899 Non-blocking hook
900 -----------------
900 -----------------
901
901
902 $ cat << EOF >> .hg/hgrc
902 $ cat << EOF >> .hg/hgrc
903 > [hooks]
903 > [hooks]
904 > txnclose.testing=echo txnclose hook called
904 > txnclose.testing=echo txnclose hook called
905 > EOF
905 > EOF
906 $ touch a && hg commit -Aqm a
906 $ touch a && hg commit -Aqm a
907 warning: untrusted hook txnclose not executed
907 warning: untrusted hook txnclose not executed
908 $ hg log
908 $ hg log
909 changeset: 0:3903775176ed
909 changeset: 0:3903775176ed
910 tag: tip
910 tag: tip
911 user: test
911 user: test
912 date: Thu Jan 01 00:00:00 1970 +0000
912 date: Thu Jan 01 00:00:00 1970 +0000
913 summary: a
913 summary: a
914
914
915
915
916 Non-blocking hook
916 Non-blocking hook
917 -----------------
917 -----------------
918
918
919 $ cat << EOF >> .hg/hgrc
919 $ cat << EOF >> .hg/hgrc
920 > [hooks]
920 > [hooks]
921 > pretxnclose.testing=echo pre-txnclose hook called
921 > pretxnclose.testing=echo pre-txnclose hook called
922 > EOF
922 > EOF
923 $ touch b && hg commit -Aqm a
923 $ touch b && hg commit -Aqm a
924 transaction abort!
924 transaction abort!
925 rollback completed
925 rollback completed
926 abort: untrusted hook pretxnclose not executed
926 abort: untrusted hook pretxnclose not executed
927 (see 'hg help config.trusted')
927 (see 'hg help config.trusted')
928 [255]
928 [255]
929 $ hg log
929 $ hg log
930 changeset: 0:3903775176ed
930 changeset: 0:3903775176ed
931 tag: tip
931 tag: tip
932 user: test
932 user: test
933 date: Thu Jan 01 00:00:00 1970 +0000
933 date: Thu Jan 01 00:00:00 1970 +0000
934 summary: a
934 summary: a
935
935
@@ -1,347 +1,347 b''
1 #require serve
1 #require serve
2
2
3 This test is a duplicate of 'test-http.t', feel free to factor out
3 This test is a duplicate of 'test-http.t', feel free to factor out
4 parts that are not bundle1/bundle2 specific.
4 parts that are not bundle1/bundle2 specific.
5
5
6 $ cat << EOF >> $HGRCPATH
6 $ cat << EOF >> $HGRCPATH
7 > [devel]
7 > [devel]
8 > # This test is dedicated to interaction through old bundle
8 > # This test is dedicated to interaction through old bundle
9 > legacy.exchange = bundle1
9 > legacy.exchange = bundle1
10 > EOF
10 > EOF
11
11
12 $ hg init test
12 $ hg init test
13 $ cd test
13 $ cd test
14 $ echo foo>foo
14 $ echo foo>foo
15 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
15 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
16 $ echo foo>foo.d/foo
16 $ echo foo>foo.d/foo
17 $ echo bar>foo.d/bAr.hg.d/BaR
17 $ echo bar>foo.d/bAr.hg.d/BaR
18 $ echo bar>foo.d/baR.d.hg/bAR
18 $ echo bar>foo.d/baR.d.hg/bAR
19 $ hg commit -A -m 1
19 $ hg commit -A -m 1
20 adding foo
20 adding foo
21 adding foo.d/bAr.hg.d/BaR
21 adding foo.d/bAr.hg.d/BaR
22 adding foo.d/baR.d.hg/bAR
22 adding foo.d/baR.d.hg/bAR
23 adding foo.d/foo
23 adding foo.d/foo
24 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
24 $ hg serve -p $HGPORT -d --pid-file=../hg1.pid -E ../error.log
25 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
25 $ hg serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
26
26
27 Test server address cannot be reused
27 Test server address cannot be reused
28
28
29 #if windows
29 #if windows
30 $ hg serve -p $HGPORT1 2>&1
30 $ hg serve -p $HGPORT1 2>&1
31 abort: cannot start server at 'localhost:$HGPORT1': * (glob)
31 abort: cannot start server at 'localhost:$HGPORT1': * (glob)
32 [255]
32 [255]
33 #else
33 #else
34 $ hg serve -p $HGPORT1 2>&1
34 $ hg serve -p $HGPORT1 2>&1
35 abort: cannot start server at 'localhost:$HGPORT1': Address already in use
35 abort: cannot start server at 'localhost:$HGPORT1': Address already in use
36 [255]
36 [255]
37 #endif
37 #endif
38 $ cd ..
38 $ cd ..
39 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
39 $ cat hg1.pid hg2.pid >> $DAEMON_PIDS
40
40
41 clone via stream
41 clone via stream
42
42
43 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
43 $ hg clone --uncompressed http://localhost:$HGPORT/ copy 2>&1
44 streaming all changes
44 streaming all changes
45 6 files to transfer, 606 bytes of data
45 6 files to transfer, 606 bytes of data
46 transferred * bytes in * seconds (*/sec) (glob)
46 transferred * bytes in * seconds (*/sec) (glob)
47 searching for changes
47 searching for changes
48 no changes found
48 no changes found
49 updating to branch default
49 updating to branch default
50 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
50 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 $ hg verify -R copy
51 $ hg verify -R copy
52 checking changesets
52 checking changesets
53 checking manifests
53 checking manifests
54 crosschecking files in changesets and manifests
54 crosschecking files in changesets and manifests
55 checking files
55 checking files
56 4 files, 1 changesets, 4 total revisions
56 4 files, 1 changesets, 4 total revisions
57
57
58 try to clone via stream, should use pull instead
58 try to clone via stream, should use pull instead
59
59
60 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
60 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
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
68
69 clone via pull
69 clone via pull
70
70
71 $ hg clone http://localhost:$HGPORT1/ copy-pull
71 $ hg clone http://localhost:$HGPORT1/ copy-pull
72 requesting all changes
72 requesting all changes
73 adding changesets
73 adding changesets
74 adding manifests
74 adding manifests
75 adding file changes
75 adding file changes
76 added 1 changesets with 4 changes to 4 files
76 added 1 changesets with 4 changes to 4 files
77 updating to branch default
77 updating to branch default
78 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 $ hg verify -R copy-pull
79 $ hg verify -R copy-pull
80 checking changesets
80 checking changesets
81 checking manifests
81 checking manifests
82 crosschecking files in changesets and manifests
82 crosschecking files in changesets and manifests
83 checking files
83 checking files
84 4 files, 1 changesets, 4 total revisions
84 4 files, 1 changesets, 4 total revisions
85 $ cd test
85 $ cd test
86 $ echo bar > bar
86 $ echo bar > bar
87 $ hg commit -A -d '1 0' -m 2
87 $ hg commit -A -d '1 0' -m 2
88 adding bar
88 adding bar
89 $ cd ..
89 $ cd ..
90
90
91 clone over http with --update
91 clone over http with --update
92
92
93 $ hg clone http://localhost:$HGPORT1/ updated --update 0
93 $ hg clone http://localhost:$HGPORT1/ updated --update 0
94 requesting all changes
94 requesting all changes
95 adding changesets
95 adding changesets
96 adding manifests
96 adding manifests
97 adding file changes
97 adding file changes
98 added 2 changesets with 5 changes to 5 files
98 added 2 changesets with 5 changes to 5 files
99 updating to branch default
99 updating to branch default
100 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
101 $ hg log -r . -R updated
101 $ hg log -r . -R updated
102 changeset: 0:8b6053c928fe
102 changeset: 0:8b6053c928fe
103 user: test
103 user: test
104 date: Thu Jan 01 00:00:00 1970 +0000
104 date: Thu Jan 01 00:00:00 1970 +0000
105 summary: 1
105 summary: 1
106
106
107 $ rm -rf updated
107 $ rm -rf updated
108
108
109 incoming via HTTP
109 incoming via HTTP
110
110
111 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
111 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
112 adding changesets
112 adding changesets
113 adding manifests
113 adding manifests
114 adding file changes
114 adding file changes
115 added 1 changesets with 4 changes to 4 files
115 added 1 changesets with 4 changes to 4 files
116 updating to branch default
116 updating to branch default
117 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 $ cd partial
118 $ cd partial
119 $ touch LOCAL
119 $ touch LOCAL
120 $ hg ci -qAm LOCAL
120 $ hg ci -qAm LOCAL
121 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
121 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
122 comparing with http://localhost:$HGPORT1/
122 comparing with http://localhost:$HGPORT1/
123 searching for changes
123 searching for changes
124 2
124 2
125 $ cd ..
125 $ cd ..
126
126
127 pull
127 pull
128
128
129 $ cd copy-pull
129 $ cd copy-pull
130 $ cat >> .hg/hgrc <<EOF
130 $ cat >> .hg/hgrc <<EOF
131 > [hooks]
131 > [hooks]
132 > changegroup = sh -c "printenv.py changegroup"
132 > changegroup = sh -c "printenv.py changegroup"
133 > EOF
133 > EOF
134 $ hg pull
134 $ hg pull
135 pulling from http://localhost:$HGPORT1/
135 pulling from http://localhost:$HGPORT1/
136 searching for changes
136 searching for changes
137 adding changesets
137 adding changesets
138 adding manifests
138 adding manifests
139 adding file changes
139 adding file changes
140 added 1 changesets with 1 changes to 1 files
140 added 1 changesets with 1 changes to 1 files
141 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
141 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=http://localhost:$HGPORT1/
142 (run 'hg update' to get a working copy)
142 (run 'hg update' to get a working copy)
143 $ cd ..
143 $ cd ..
144
144
145 clone from invalid URL
145 clone from invalid URL
146
146
147 $ hg clone http://localhost:$HGPORT/bad
147 $ hg clone http://localhost:$HGPORT/bad
148 abort: HTTP Error 404: Not Found
148 abort: HTTP Error 404: Not Found
149 [255]
149 [255]
150
150
151 test http authentication
151 test http authentication
152 + use the same server to test server side streaming preference
152 + use the same server to test server side streaming preference
153
153
154 $ cd test
154 $ cd test
155 $ cat << EOT > userpass.py
155 $ cat << EOT > userpass.py
156 > import base64
156 > import base64
157 > from mercurial.hgweb import common
157 > from mercurial.hgweb import common
158 > def perform_authentication(hgweb, req, op):
158 > def perform_authentication(hgweb, req, op):
159 > auth = req.env.get('HTTP_AUTHORIZATION')
159 > auth = req.env.get('HTTP_AUTHORIZATION')
160 > if not auth:
160 > if not auth:
161 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
161 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
162 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
162 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
163 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
163 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
164 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
164 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
165 > def extsetup():
165 > def extsetup():
166 > common.permhooks.insert(0, perform_authentication)
166 > common.permhooks.insert(0, perform_authentication)
167 > EOT
167 > EOT
168 $ hg serve --config extensions.x=userpass.py -p $HGPORT2 -d --pid-file=pid \
168 $ hg serve --config extensions.x=userpass.py -p $HGPORT2 -d --pid-file=pid \
169 > --config server.preferuncompressed=True \
169 > --config server.preferuncompressed=True \
170 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
170 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
171 $ cat pid >> $DAEMON_PIDS
171 $ cat pid >> $DAEMON_PIDS
172
172
173 $ cat << EOF > get_pass.py
173 $ cat << EOF > get_pass.py
174 > import getpass
174 > import getpass
175 > def newgetpass(arg):
175 > def newgetpass(arg):
176 > return "pass"
176 > return "pass"
177 > getpass.getpass = newgetpass
177 > getpass.getpass = newgetpass
178 > EOF
178 > EOF
179
179
180 $ hg id http://localhost:$HGPORT2/
180 $ hg id http://localhost:$HGPORT2/
181 abort: http authorization required for http://localhost:$HGPORT2/
181 abort: http authorization required for http://localhost:$HGPORT2/
182 [255]
182 [255]
183 $ hg id http://localhost:$HGPORT2/
183 $ hg id http://localhost:$HGPORT2/
184 abort: http authorization required for http://localhost:$HGPORT2/
184 abort: http authorization required for http://localhost:$HGPORT2/
185 [255]
185 [255]
186 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
186 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
187 http authorization required for http://localhost:$HGPORT2/
187 http authorization required for http://localhost:$HGPORT2/
188 realm: mercurial
188 realm: mercurial
189 user: user
189 user: user
190 password: 5fed3813f7f5
190 password: 5fed3813f7f5
191 $ hg id http://user:pass@localhost:$HGPORT2/
191 $ hg id http://user:pass@localhost:$HGPORT2/
192 5fed3813f7f5
192 5fed3813f7f5
193 $ echo '[auth]' >> .hg/hgrc
193 $ echo '[auth]' >> .hg/hgrc
194 $ echo 'l.schemes=http' >> .hg/hgrc
194 $ echo 'l.schemes=http' >> .hg/hgrc
195 $ echo 'l.prefix=lo' >> .hg/hgrc
195 $ echo 'l.prefix=lo' >> .hg/hgrc
196 $ echo 'l.username=user' >> .hg/hgrc
196 $ echo 'l.username=user' >> .hg/hgrc
197 $ echo 'l.password=pass' >> .hg/hgrc
197 $ echo 'l.password=pass' >> .hg/hgrc
198 $ hg id http://localhost:$HGPORT2/
198 $ hg id http://localhost:$HGPORT2/
199 5fed3813f7f5
199 5fed3813f7f5
200 $ hg id http://localhost:$HGPORT2/
200 $ hg id http://localhost:$HGPORT2/
201 5fed3813f7f5
201 5fed3813f7f5
202 $ hg id http://user@localhost:$HGPORT2/
202 $ hg id http://user@localhost:$HGPORT2/
203 5fed3813f7f5
203 5fed3813f7f5
204 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
204 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
205 streaming all changes
205 streaming all changes
206 7 files to transfer, 916 bytes of data
206 7 files to transfer, 916 bytes of data
207 transferred * bytes in * seconds (*/sec) (glob)
207 transferred * bytes in * seconds (*/sec) (glob)
208 searching for changes
208 searching for changes
209 no changes found
209 no changes found
210 updating to branch default
210 updating to branch default
211 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 --pull should override server's preferuncompressed
212 --pull should override server's preferuncompressed
213 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
213 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
214 requesting all changes
214 requesting all changes
215 adding changesets
215 adding changesets
216 adding manifests
216 adding manifests
217 adding file changes
217 adding file changes
218 added 2 changesets with 5 changes to 5 files
218 added 2 changesets with 5 changes to 5 files
219 updating to branch default
219 updating to branch default
220 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
220 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
221
221
222 $ hg id http://user2@localhost:$HGPORT2/
222 $ hg id http://user2@localhost:$HGPORT2/
223 abort: http authorization required for http://localhost:$HGPORT2/
223 abort: http authorization required for http://localhost:$HGPORT2/
224 [255]
224 [255]
225 $ hg id http://user:pass2@localhost:$HGPORT2/
225 $ hg id http://user:pass2@localhost:$HGPORT2/
226 abort: HTTP Error 403: no
226 abort: HTTP Error 403: no
227 [255]
227 [255]
228
228
229 $ hg -R dest tag -r tip top
229 $ hg -R dest tag -r tip top
230 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
230 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
231 pushing to http://user:***@localhost:$HGPORT2/
231 pushing to http://user:***@localhost:$HGPORT2/
232 searching for changes
232 searching for changes
233 remote: adding changesets
233 remote: adding changesets
234 remote: adding manifests
234 remote: adding manifests
235 remote: adding file changes
235 remote: adding file changes
236 remote: added 1 changesets with 1 changes to 1 files
236 remote: added 1 changesets with 1 changes to 1 files
237 $ hg rollback -q
237 $ hg rollback -q
238
238
239 $ sed 's/.*] "/"/' < ../access.log
239 $ sed 's/.*] "/"/' < ../access.log
240 "GET /?cmd=capabilities HTTP/1.1" 200 -
240 "GET /?cmd=capabilities HTTP/1.1" 200 -
241 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
241 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
242 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
242 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
243 "GET /?cmd=capabilities HTTP/1.1" 200 -
243 "GET /?cmd=capabilities HTTP/1.1" 200 -
244 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
244 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
245 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
245 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
246 "GET /?cmd=capabilities HTTP/1.1" 200 -
246 "GET /?cmd=capabilities HTTP/1.1" 200 -
247 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
247 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
248 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
248 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
249 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
249 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
250 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
250 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
251 "GET /?cmd=capabilities HTTP/1.1" 200 -
251 "GET /?cmd=capabilities HTTP/1.1" 200 -
252 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
252 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
253 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
253 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
254 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
254 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
255 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
255 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
256 "GET /?cmd=capabilities HTTP/1.1" 200 -
256 "GET /?cmd=capabilities HTTP/1.1" 200 -
257 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
257 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
258 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
258 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
259 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
259 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
260 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
260 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
261 "GET /?cmd=capabilities HTTP/1.1" 200 -
261 "GET /?cmd=capabilities HTTP/1.1" 200 -
262 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
262 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
263 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
263 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
264 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
264 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
265 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
265 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
266 "GET /?cmd=capabilities HTTP/1.1" 200 -
266 "GET /?cmd=capabilities HTTP/1.1" 200 -
267 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
267 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
268 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
268 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
269 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
269 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
270 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
270 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
271 "GET /?cmd=capabilities HTTP/1.1" 200 -
271 "GET /?cmd=capabilities HTTP/1.1" 200 -
272 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
272 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
273 "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
273 "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
274 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
274 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
275 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
275 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
276 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
276 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
277 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
277 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
278 "GET /?cmd=capabilities HTTP/1.1" 200 -
278 "GET /?cmd=capabilities HTTP/1.1" 200 -
279 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
279 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
280 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
280 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
281 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
281 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
282 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
282 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
284 "GET /?cmd=capabilities HTTP/1.1" 200 -
284 "GET /?cmd=capabilities HTTP/1.1" 200 -
285 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
285 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
286 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
286 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
287 "GET /?cmd=capabilities HTTP/1.1" 200 -
287 "GET /?cmd=capabilities HTTP/1.1" 200 -
288 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
288 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
289 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
289 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
290 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
290 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
291 "GET /?cmd=capabilities HTTP/1.1" 200 -
291 "GET /?cmd=capabilities HTTP/1.1" 200 -
292 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
292 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
293 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
293 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
294 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
294 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
295 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
295 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
296 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
296 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
297 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
297 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
298 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
298 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
299 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524* (glob)
299 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=686173686564+5eb5abfefeea63c80dd7553bcc3783f37e0c5524* (glob)
300 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
300 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
301
301
302 $ cd ..
302 $ cd ..
303
303
304 clone of serve with repo in root and unserved subrepo (issue2970)
304 clone of serve with repo in root and unserved subrepo (issue2970)
305
305
306 $ hg --cwd test init sub
306 $ hg --cwd test init sub
307 $ echo empty > test/sub/empty
307 $ echo empty > test/sub/empty
308 $ hg --cwd test/sub add empty
308 $ hg --cwd test/sub add empty
309 $ hg --cwd test/sub commit -qm 'add empty'
309 $ hg --cwd test/sub commit -qm 'add empty'
310 $ hg --cwd test/sub tag -r 0 something
310 $ hg --cwd test/sub tag -r 0 something
311 $ echo sub = sub > test/.hgsub
311 $ echo sub = sub > test/.hgsub
312 $ hg --cwd test add .hgsub
312 $ hg --cwd test add .hgsub
313 $ hg --cwd test commit -qm 'add subrepo'
313 $ hg --cwd test commit -qm 'add subrepo'
314 $ hg clone http://localhost:$HGPORT noslash-clone
314 $ hg clone http://localhost:$HGPORT noslash-clone
315 requesting all changes
315 requesting all changes
316 adding changesets
316 adding changesets
317 adding manifests
317 adding manifests
318 adding file changes
318 adding file changes
319 added 3 changesets with 7 changes to 7 files
319 added 3 changesets with 7 changes to 7 files
320 updating to branch default
320 updating to branch default
321 abort: HTTP Error 404: Not Found
321 abort: HTTP Error 404: Not Found
322 [255]
322 [255]
323 $ hg clone http://localhost:$HGPORT/ slash-clone
323 $ hg clone http://localhost:$HGPORT/ slash-clone
324 requesting all changes
324 requesting all changes
325 adding changesets
325 adding changesets
326 adding manifests
326 adding manifests
327 adding file changes
327 adding file changes
328 added 3 changesets with 7 changes to 7 files
328 added 3 changesets with 7 changes to 7 files
329 updating to branch default
329 updating to branch default
330 abort: HTTP Error 404: Not Found
330 abort: HTTP Error 404: Not Found
331 [255]
331 [255]
332
332
333 check error log
333 check error log
334
334
335 $ cat error.log
335 $ cat error.log
336
336
337 Check error reporting while pulling/cloning
337 Check error reporting while pulling/cloning
338
338
339 $ $RUNTESTDIR/killdaemons.py
339 $ $RUNTESTDIR/killdaemons.py
340 $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
340 $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
341 $ cat hg3.pid >> $DAEMON_PIDS
341 $ cat hg3.pid >> $DAEMON_PIDS
342 $ hg clone http://localhost:$HGPORT/ abort-clone
342 $ hg clone http://localhost:$HGPORT/ abort-clone
343 requesting all changes
343 requesting all changes
344 abort: remote error:
344 abort: remote error:
345 this is an exercise
345 this is an exercise
346 [255]
346 [255]
347 $ cat error.log
347 $ cat error.log
@@ -1,335 +1,335 b''
1 #require serve
1 #require serve
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 serve --config server.uncompressed=False -p $HGPORT1 -d --pid-file=../hg2.pid
16 $ hg serve --config server.uncompressed=False -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 'localhost:$HGPORT1': Address already in use
26 abort: cannot start server at 'localhost:$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 searching for changes
38 searching for changes
39 no changes found
39 no changes found
40 updating to branch default
40 updating to branch default
41 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
41 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
42 $ hg verify -R copy
42 $ hg verify -R copy
43 checking changesets
43 checking changesets
44 checking manifests
44 checking manifests
45 crosschecking files in changesets and manifests
45 crosschecking files in changesets and manifests
46 checking files
46 checking files
47 4 files, 1 changesets, 4 total revisions
47 4 files, 1 changesets, 4 total revisions
48
48
49 try to clone via stream, should use pull instead
49 try to clone via stream, should use pull instead
50
50
51 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
51 $ hg clone --uncompressed http://localhost:$HGPORT1/ copy2
52 requesting all changes
52 requesting all changes
53 adding changesets
53 adding changesets
54 adding manifests
54 adding manifests
55 adding file changes
55 adding file changes
56 added 1 changesets with 4 changes to 4 files
56 added 1 changesets with 4 changes to 4 files
57 updating to branch default
57 updating to branch default
58 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
59
59
60 clone via pull
60 clone via pull
61
61
62 $ hg clone http://localhost:$HGPORT1/ copy-pull
62 $ hg clone http://localhost:$HGPORT1/ copy-pull
63 requesting all changes
63 requesting all changes
64 adding changesets
64 adding changesets
65 adding manifests
65 adding manifests
66 adding file changes
66 adding file changes
67 added 1 changesets with 4 changes to 4 files
67 added 1 changesets with 4 changes to 4 files
68 updating to branch default
68 updating to branch default
69 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 $ hg verify -R copy-pull
70 $ hg verify -R copy-pull
71 checking changesets
71 checking changesets
72 checking manifests
72 checking manifests
73 crosschecking files in changesets and manifests
73 crosschecking files in changesets and manifests
74 checking files
74 checking files
75 4 files, 1 changesets, 4 total revisions
75 4 files, 1 changesets, 4 total revisions
76 $ cd test
76 $ cd test
77 $ echo bar > bar
77 $ echo bar > bar
78 $ hg commit -A -d '1 0' -m 2
78 $ hg commit -A -d '1 0' -m 2
79 adding bar
79 adding bar
80 $ cd ..
80 $ cd ..
81
81
82 clone over http with --update
82 clone over http with --update
83
83
84 $ hg clone http://localhost:$HGPORT1/ updated --update 0
84 $ hg clone http://localhost:$HGPORT1/ updated --update 0
85 requesting all changes
85 requesting all changes
86 adding changesets
86 adding changesets
87 adding manifests
87 adding manifests
88 adding file changes
88 adding file changes
89 added 2 changesets with 5 changes to 5 files
89 added 2 changesets with 5 changes to 5 files
90 updating to branch default
90 updating to branch default
91 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
92 $ hg log -r . -R updated
92 $ hg log -r . -R updated
93 changeset: 0:8b6053c928fe
93 changeset: 0:8b6053c928fe
94 user: test
94 user: test
95 date: Thu Jan 01 00:00:00 1970 +0000
95 date: Thu Jan 01 00:00:00 1970 +0000
96 summary: 1
96 summary: 1
97
97
98 $ rm -rf updated
98 $ rm -rf updated
99
99
100 incoming via HTTP
100 incoming via HTTP
101
101
102 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
102 $ hg clone http://localhost:$HGPORT1/ --rev 0 partial
103 adding changesets
103 adding changesets
104 adding manifests
104 adding manifests
105 adding file changes
105 adding file changes
106 added 1 changesets with 4 changes to 4 files
106 added 1 changesets with 4 changes to 4 files
107 updating to branch default
107 updating to branch default
108 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
108 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 $ cd partial
109 $ cd partial
110 $ touch LOCAL
110 $ touch LOCAL
111 $ hg ci -qAm LOCAL
111 $ hg ci -qAm LOCAL
112 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
112 $ hg incoming http://localhost:$HGPORT1/ --template '{desc}\n'
113 comparing with http://localhost:$HGPORT1/
113 comparing with http://localhost:$HGPORT1/
114 searching for changes
114 searching for changes
115 2
115 2
116 $ cd ..
116 $ cd ..
117
117
118 pull
118 pull
119
119
120 $ cd copy-pull
120 $ cd copy-pull
121 $ cat >> .hg/hgrc <<EOF
121 $ cat >> .hg/hgrc <<EOF
122 > [hooks]
122 > [hooks]
123 > changegroup = sh -c "printenv.py changegroup"
123 > changegroup = sh -c "printenv.py changegroup"
124 > EOF
124 > EOF
125 $ hg pull
125 $ hg pull
126 pulling from http://localhost:$HGPORT1/
126 pulling from http://localhost:$HGPORT1/
127 searching for changes
127 searching for changes
128 adding changesets
128 adding changesets
129 adding manifests
129 adding manifests
130 adding file changes
130 adding file changes
131 added 1 changesets with 1 changes to 1 files
131 added 1 changesets with 1 changes to 1 files
132 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT1/ (glob)
132 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=http://localhost:$HGPORT1/
133 (run 'hg update' to get a working copy)
133 (run 'hg update' to get a working copy)
134 $ cd ..
134 $ cd ..
135
135
136 clone from invalid URL
136 clone from invalid URL
137
137
138 $ hg clone http://localhost:$HGPORT/bad
138 $ hg clone http://localhost:$HGPORT/bad
139 abort: HTTP Error 404: Not Found
139 abort: HTTP Error 404: Not Found
140 [255]
140 [255]
141
141
142 test http authentication
142 test http authentication
143 + use the same server to test server side streaming preference
143 + use the same server to test server side streaming preference
144
144
145 $ cd test
145 $ cd test
146 $ cat << EOT > userpass.py
146 $ cat << EOT > userpass.py
147 > import base64
147 > import base64
148 > from mercurial.hgweb import common
148 > from mercurial.hgweb import common
149 > def perform_authentication(hgweb, req, op):
149 > def perform_authentication(hgweb, req, op):
150 > auth = req.env.get('HTTP_AUTHORIZATION')
150 > auth = req.env.get('HTTP_AUTHORIZATION')
151 > if not auth:
151 > if not auth:
152 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
152 > raise common.ErrorResponse(common.HTTP_UNAUTHORIZED, 'who',
153 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
153 > [('WWW-Authenticate', 'Basic Realm="mercurial"')])
154 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
154 > if base64.b64decode(auth.split()[1]).split(':', 1) != ['user', 'pass']:
155 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
155 > raise common.ErrorResponse(common.HTTP_FORBIDDEN, 'no')
156 > def extsetup():
156 > def extsetup():
157 > common.permhooks.insert(0, perform_authentication)
157 > common.permhooks.insert(0, perform_authentication)
158 > EOT
158 > EOT
159 $ hg serve --config extensions.x=userpass.py -p $HGPORT2 -d --pid-file=pid \
159 $ hg serve --config extensions.x=userpass.py -p $HGPORT2 -d --pid-file=pid \
160 > --config server.preferuncompressed=True \
160 > --config server.preferuncompressed=True \
161 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
161 > --config web.push_ssl=False --config web.allow_push=* -A ../access.log
162 $ cat pid >> $DAEMON_PIDS
162 $ cat pid >> $DAEMON_PIDS
163
163
164 $ cat << EOF > get_pass.py
164 $ cat << EOF > get_pass.py
165 > import getpass
165 > import getpass
166 > def newgetpass(arg):
166 > def newgetpass(arg):
167 > return "pass"
167 > return "pass"
168 > getpass.getpass = newgetpass
168 > getpass.getpass = newgetpass
169 > EOF
169 > EOF
170
170
171 $ hg id http://localhost:$HGPORT2/
171 $ hg id http://localhost:$HGPORT2/
172 abort: http authorization required for http://localhost:$HGPORT2/
172 abort: http authorization required for http://localhost:$HGPORT2/
173 [255]
173 [255]
174 $ hg id http://localhost:$HGPORT2/
174 $ hg id http://localhost:$HGPORT2/
175 abort: http authorization required for http://localhost:$HGPORT2/
175 abort: http authorization required for http://localhost:$HGPORT2/
176 [255]
176 [255]
177 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
177 $ hg id --config ui.interactive=true --config extensions.getpass=get_pass.py http://user@localhost:$HGPORT2/
178 http authorization required for http://localhost:$HGPORT2/
178 http authorization required for http://localhost:$HGPORT2/
179 realm: mercurial
179 realm: mercurial
180 user: user
180 user: user
181 password: 5fed3813f7f5
181 password: 5fed3813f7f5
182 $ hg id http://user:pass@localhost:$HGPORT2/
182 $ hg id http://user:pass@localhost:$HGPORT2/
183 5fed3813f7f5
183 5fed3813f7f5
184 $ echo '[auth]' >> .hg/hgrc
184 $ echo '[auth]' >> .hg/hgrc
185 $ echo 'l.schemes=http' >> .hg/hgrc
185 $ echo 'l.schemes=http' >> .hg/hgrc
186 $ echo 'l.prefix=lo' >> .hg/hgrc
186 $ echo 'l.prefix=lo' >> .hg/hgrc
187 $ echo 'l.username=user' >> .hg/hgrc
187 $ echo 'l.username=user' >> .hg/hgrc
188 $ echo 'l.password=pass' >> .hg/hgrc
188 $ echo 'l.password=pass' >> .hg/hgrc
189 $ hg id http://localhost:$HGPORT2/
189 $ hg id http://localhost:$HGPORT2/
190 5fed3813f7f5
190 5fed3813f7f5
191 $ hg id http://localhost:$HGPORT2/
191 $ hg id http://localhost:$HGPORT2/
192 5fed3813f7f5
192 5fed3813f7f5
193 $ hg id http://user@localhost:$HGPORT2/
193 $ hg id http://user@localhost:$HGPORT2/
194 5fed3813f7f5
194 5fed3813f7f5
195 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
195 $ hg clone http://user:pass@localhost:$HGPORT2/ dest 2>&1
196 streaming all changes
196 streaming all changes
197 7 files to transfer, 916 bytes of data
197 7 files to transfer, 916 bytes of data
198 transferred * bytes in * seconds (*/sec) (glob)
198 transferred * bytes in * seconds (*/sec) (glob)
199 searching for changes
199 searching for changes
200 no changes found
200 no changes found
201 updating to branch default
201 updating to branch default
202 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 --pull should override server's preferuncompressed
203 --pull should override server's preferuncompressed
204 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
204 $ hg clone --pull http://user:pass@localhost:$HGPORT2/ dest-pull 2>&1
205 requesting all changes
205 requesting all changes
206 adding changesets
206 adding changesets
207 adding manifests
207 adding manifests
208 adding file changes
208 adding file changes
209 added 2 changesets with 5 changes to 5 files
209 added 2 changesets with 5 changes to 5 files
210 updating to branch default
210 updating to branch default
211 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
212
212
213 $ hg id http://user2@localhost:$HGPORT2/
213 $ hg id http://user2@localhost:$HGPORT2/
214 abort: http authorization required for http://localhost:$HGPORT2/
214 abort: http authorization required for http://localhost:$HGPORT2/
215 [255]
215 [255]
216 $ hg id http://user:pass2@localhost:$HGPORT2/
216 $ hg id http://user:pass2@localhost:$HGPORT2/
217 abort: HTTP Error 403: no
217 abort: HTTP Error 403: no
218 [255]
218 [255]
219
219
220 $ hg -R dest tag -r tip top
220 $ hg -R dest tag -r tip top
221 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
221 $ hg -R dest push http://user:pass@localhost:$HGPORT2/
222 pushing to http://user:***@localhost:$HGPORT2/
222 pushing to http://user:***@localhost:$HGPORT2/
223 searching for changes
223 searching for changes
224 remote: adding changesets
224 remote: adding changesets
225 remote: adding manifests
225 remote: adding manifests
226 remote: adding file changes
226 remote: adding file changes
227 remote: added 1 changesets with 1 changes to 1 files
227 remote: added 1 changesets with 1 changes to 1 files
228 $ hg rollback -q
228 $ hg rollback -q
229
229
230 $ sed 's/.*] "/"/' < ../access.log
230 $ sed 's/.*] "/"/' < ../access.log
231 "GET /?cmd=capabilities HTTP/1.1" 200 -
231 "GET /?cmd=capabilities HTTP/1.1" 200 -
232 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
232 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
233 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
233 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
234 "GET /?cmd=capabilities HTTP/1.1" 200 -
234 "GET /?cmd=capabilities HTTP/1.1" 200 -
235 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
235 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
236 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
236 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
237 "GET /?cmd=capabilities HTTP/1.1" 200 -
237 "GET /?cmd=capabilities HTTP/1.1" 200 -
238 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
238 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
239 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
239 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
240 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
240 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
241 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
241 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
242 "GET /?cmd=capabilities HTTP/1.1" 200 -
242 "GET /?cmd=capabilities HTTP/1.1" 200 -
243 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
243 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
244 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
244 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
245 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
245 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
246 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
246 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
247 "GET /?cmd=capabilities HTTP/1.1" 200 -
247 "GET /?cmd=capabilities HTTP/1.1" 200 -
248 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
248 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
249 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
249 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
250 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
250 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
251 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
251 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
252 "GET /?cmd=capabilities HTTP/1.1" 200 -
252 "GET /?cmd=capabilities HTTP/1.1" 200 -
253 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
253 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
254 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
254 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
255 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
255 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
256 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
256 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
257 "GET /?cmd=capabilities HTTP/1.1" 200 -
257 "GET /?cmd=capabilities HTTP/1.1" 200 -
258 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
258 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
259 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
259 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
260 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
260 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
261 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
261 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
262 "GET /?cmd=capabilities HTTP/1.1" 200 -
262 "GET /?cmd=capabilities HTTP/1.1" 200 -
263 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
263 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
264 "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
264 "GET /?cmd=stream_out HTTP/1.1" 401 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
265 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
265 "GET /?cmd=stream_out HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
266 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
266 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D5fed3813f7f5e1824344fdc9cf8f63bb662c292d x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
267 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
267 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=0&common=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
268 "GET /?cmd=capabilities HTTP/1.1" 200 -
268 "GET /?cmd=capabilities HTTP/1.1" 200 -
269 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
269 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
270 "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
270 "GET /?cmd=getbundle HTTP/1.1" 401 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
271 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
271 "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:bundlecaps=HG20%2Cbundle2%3DHG20%250Achangegroup%253D01%252C02%250Adigests%253Dmd5%252Csha1%252Csha512%250Aerror%253Dabort%252Cunsupportedcontent%252Cpushraced%252Cpushkey%250Ahgtagsfnodes%250Alistkeys%250Apushkey%250Aremote-changegroup%253Dhttp%252Chttps&cg=1&common=0000000000000000000000000000000000000000&heads=5fed3813f7f5e1824344fdc9cf8f63bb662c292d&listkeys=phases%2Cbookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
272 "GET /?cmd=capabilities HTTP/1.1" 200 -
272 "GET /?cmd=capabilities HTTP/1.1" 200 -
273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
273 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
274 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
274 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
275 "GET /?cmd=capabilities HTTP/1.1" 200 -
275 "GET /?cmd=capabilities HTTP/1.1" 200 -
276 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
276 "GET /?cmd=lookup HTTP/1.1" 200 - x-hgarg-1:key=tip x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
277 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
277 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
278 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
278 "GET /?cmd=listkeys HTTP/1.1" 403 - x-hgarg-1:namespace=namespaces x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
279 "GET /?cmd=capabilities HTTP/1.1" 200 -
279 "GET /?cmd=capabilities HTTP/1.1" 200 -
280 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
280 "GET /?cmd=batch HTTP/1.1" 200 - x-hgarg-1:cmds=heads+%3Bknown+nodes%3D7f4e523d01f2cc3765ac8934da3d14db775ff872 x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
281 "GET /?cmd=listkeys HTTP/1.1" 401 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
282 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
283 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
284 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
284 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
285 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
285 "GET /?cmd=branchmap HTTP/1.1" 200 - x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
286 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=bookmarks x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
287 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
287 "POST /?cmd=unbundle HTTP/1.1" 200 - x-hgarg-1:heads=666f726365* (glob)
288 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
288 "GET /?cmd=listkeys HTTP/1.1" 200 - x-hgarg-1:namespace=phases x-hgproto-1:0.1 0.2 comp=*zlib,none,bzip2 (glob)
289
289
290 $ cd ..
290 $ cd ..
291
291
292 clone of serve with repo in root and unserved subrepo (issue2970)
292 clone of serve with repo in root and unserved subrepo (issue2970)
293
293
294 $ hg --cwd test init sub
294 $ hg --cwd test init sub
295 $ echo empty > test/sub/empty
295 $ echo empty > test/sub/empty
296 $ hg --cwd test/sub add empty
296 $ hg --cwd test/sub add empty
297 $ hg --cwd test/sub commit -qm 'add empty'
297 $ hg --cwd test/sub commit -qm 'add empty'
298 $ hg --cwd test/sub tag -r 0 something
298 $ hg --cwd test/sub tag -r 0 something
299 $ echo sub = sub > test/.hgsub
299 $ echo sub = sub > test/.hgsub
300 $ hg --cwd test add .hgsub
300 $ hg --cwd test add .hgsub
301 $ hg --cwd test commit -qm 'add subrepo'
301 $ hg --cwd test commit -qm 'add subrepo'
302 $ hg clone http://localhost:$HGPORT noslash-clone
302 $ hg clone http://localhost:$HGPORT noslash-clone
303 requesting all changes
303 requesting all changes
304 adding changesets
304 adding changesets
305 adding manifests
305 adding manifests
306 adding file changes
306 adding file changes
307 added 3 changesets with 7 changes to 7 files
307 added 3 changesets with 7 changes to 7 files
308 updating to branch default
308 updating to branch default
309 abort: HTTP Error 404: Not Found
309 abort: HTTP Error 404: Not Found
310 [255]
310 [255]
311 $ hg clone http://localhost:$HGPORT/ slash-clone
311 $ hg clone http://localhost:$HGPORT/ slash-clone
312 requesting all changes
312 requesting all changes
313 adding changesets
313 adding changesets
314 adding manifests
314 adding manifests
315 adding file changes
315 adding file changes
316 added 3 changesets with 7 changes to 7 files
316 added 3 changesets with 7 changes to 7 files
317 updating to branch default
317 updating to branch default
318 abort: HTTP Error 404: Not Found
318 abort: HTTP Error 404: Not Found
319 [255]
319 [255]
320
320
321 check error log
321 check error log
322
322
323 $ cat error.log
323 $ cat error.log
324
324
325 check abort error reporting while pulling/cloning
325 check abort error reporting while pulling/cloning
326
326
327 $ $RUNTESTDIR/killdaemons.py
327 $ $RUNTESTDIR/killdaemons.py
328 $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
328 $ hg -R test serve -p $HGPORT -d --pid-file=hg3.pid -E error.log --config extensions.crash=${TESTDIR}/crashgetbundler.py
329 $ cat hg3.pid >> $DAEMON_PIDS
329 $ cat hg3.pid >> $DAEMON_PIDS
330 $ hg clone http://localhost:$HGPORT/ abort-clone
330 $ hg clone http://localhost:$HGPORT/ abort-clone
331 requesting all changes
331 requesting all changes
332 remote: abort: this is an exercise
332 remote: abort: this is an exercise
333 abort: pull failed on remote
333 abort: pull failed on remote
334 [255]
334 [255]
335 $ cat error.log
335 $ cat error.log
@@ -1,644 +1,644 b''
1 #require serve ssl
1 #require serve ssl
2
2
3 Proper https client requires the built-in ssl from Python 2.6.
3 Proper https client requires the built-in ssl from Python 2.6.
4
4
5 Make server certificates:
5 Make server certificates:
6
6
7 $ CERTSDIR="$TESTDIR/sslcerts"
7 $ CERTSDIR="$TESTDIR/sslcerts"
8 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
8 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub.pem" >> server.pem
9 $ PRIV=`pwd`/server.pem
9 $ PRIV=`pwd`/server.pem
10 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-not-yet.pem" > server-not-yet.pem
10 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-not-yet.pem" > server-not-yet.pem
11 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-expired.pem" > server-expired.pem
11 $ cat "$CERTSDIR/priv.pem" "$CERTSDIR/pub-expired.pem" > server-expired.pem
12
12
13 $ hg init test
13 $ hg init test
14 $ cd test
14 $ cd test
15 $ echo foo>foo
15 $ echo foo>foo
16 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
16 $ mkdir foo.d foo.d/bAr.hg.d foo.d/baR.d.hg
17 $ echo foo>foo.d/foo
17 $ echo foo>foo.d/foo
18 $ echo bar>foo.d/bAr.hg.d/BaR
18 $ echo bar>foo.d/bAr.hg.d/BaR
19 $ echo bar>foo.d/baR.d.hg/bAR
19 $ echo bar>foo.d/baR.d.hg/bAR
20 $ hg commit -A -m 1
20 $ hg commit -A -m 1
21 adding foo
21 adding foo
22 adding foo.d/bAr.hg.d/BaR
22 adding foo.d/bAr.hg.d/BaR
23 adding foo.d/baR.d.hg/bAR
23 adding foo.d/baR.d.hg/bAR
24 adding foo.d/foo
24 adding foo.d/foo
25 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
25 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV
26 $ cat ../hg0.pid >> $DAEMON_PIDS
26 $ cat ../hg0.pid >> $DAEMON_PIDS
27
27
28 cacert not found
28 cacert not found
29
29
30 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
30 $ hg in --config web.cacerts=no-such.pem https://localhost:$HGPORT/
31 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
31 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
32 abort: could not find web.cacerts: no-such.pem
32 abort: could not find web.cacerts: no-such.pem
33 [255]
33 [255]
34
34
35 Test server address cannot be reused
35 Test server address cannot be reused
36
36
37 #if windows
37 #if windows
38 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
38 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
39 abort: cannot start server at 'localhost:$HGPORT':
39 abort: cannot start server at 'localhost:$HGPORT':
40 [255]
40 [255]
41 #else
41 #else
42 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
42 $ hg serve -p $HGPORT --certificate=$PRIV 2>&1
43 abort: cannot start server at 'localhost:$HGPORT': Address already in use
43 abort: cannot start server at 'localhost:$HGPORT': Address already in use
44 [255]
44 [255]
45 #endif
45 #endif
46 $ cd ..
46 $ cd ..
47
47
48 Our test cert is not signed by a trusted CA. It should fail to verify if
48 Our test cert is not signed by a trusted CA. It should fail to verify if
49 we are able to load CA certs.
49 we are able to load CA certs.
50
50
51 #if sslcontext defaultcacerts no-defaultcacertsloaded
51 #if sslcontext defaultcacerts no-defaultcacertsloaded
52 $ hg clone https://localhost:$HGPORT/ copy-pull
52 $ hg clone https://localhost:$HGPORT/ copy-pull
53 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
53 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
54 abort: error: *certificate verify failed* (glob)
54 abort: error: *certificate verify failed* (glob)
55 [255]
55 [255]
56 #endif
56 #endif
57
57
58 #if no-sslcontext defaultcacerts
58 #if no-sslcontext defaultcacerts
59 $ hg clone https://localhost:$HGPORT/ copy-pull
59 $ hg clone https://localhost:$HGPORT/ copy-pull
60 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
60 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
61 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
61 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
62 abort: error: *certificate verify failed* (glob)
62 abort: error: *certificate verify failed* (glob)
63 [255]
63 [255]
64 #endif
64 #endif
65
65
66 #if no-sslcontext windows
66 #if no-sslcontext windows
67 $ hg clone https://localhost:$HGPORT/ copy-pull
67 $ hg clone https://localhost:$HGPORT/ copy-pull
68 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
68 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
69 (unable to load Windows CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
69 (unable to load Windows CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
70 abort: error: *certificate verify failed* (glob)
70 abort: error: *certificate verify failed* (glob)
71 [255]
71 [255]
72 #endif
72 #endif
73
73
74 #if no-sslcontext osx
74 #if no-sslcontext osx
75 $ hg clone https://localhost:$HGPORT/ copy-pull
75 $ hg clone https://localhost:$HGPORT/ copy-pull
76 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
76 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
77 (unable to load CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
77 (unable to load CA certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message)
78 abort: localhost certificate error: no certificate received
78 abort: localhost certificate error: no certificate received
79 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
79 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
80 [255]
80 [255]
81 #endif
81 #endif
82
82
83 #if defaultcacertsloaded
83 #if defaultcacertsloaded
84 $ hg clone https://localhost:$HGPORT/ copy-pull
84 $ hg clone https://localhost:$HGPORT/ copy-pull
85 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
85 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
86 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
86 (using CA certificates from *; if you see this message, your Mercurial install is not properly configured; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
87 abort: error: *certificate verify failed* (glob)
87 abort: error: *certificate verify failed* (glob)
88 [255]
88 [255]
89 #endif
89 #endif
90
90
91 #if no-defaultcacerts
91 #if no-defaultcacerts
92 $ hg clone https://localhost:$HGPORT/ copy-pull
92 $ hg clone https://localhost:$HGPORT/ copy-pull
93 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
93 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
94 (unable to load * certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
94 (unable to load * certificates; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this message) (glob) (?)
95 abort: localhost certificate error: no certificate received
95 abort: localhost certificate error: no certificate received
96 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
96 (set hostsecurity.localhost:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
97 [255]
97 [255]
98 #endif
98 #endif
99
99
100 Specifying a per-host certificate file that doesn't exist will abort
100 Specifying a per-host certificate file that doesn't exist will abort
101
101
102 $ hg --config hostsecurity.localhost:verifycertsfile=/does/not/exist clone https://localhost:$HGPORT/
102 $ hg --config hostsecurity.localhost:verifycertsfile=/does/not/exist clone https://localhost:$HGPORT/
103 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
103 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
104 abort: path specified by hostsecurity.localhost:verifycertsfile does not exist: /does/not/exist
104 abort: path specified by hostsecurity.localhost:verifycertsfile does not exist: /does/not/exist
105 [255]
105 [255]
106
106
107 A malformed per-host certificate file will raise an error
107 A malformed per-host certificate file will raise an error
108
108
109 $ echo baddata > badca.pem
109 $ echo baddata > badca.pem
110 #if sslcontext
110 #if sslcontext
111 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
111 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
112 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
112 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
113 abort: error loading CA file badca.pem: * (glob)
113 abort: error loading CA file badca.pem: * (glob)
114 (file is empty or malformed?)
114 (file is empty or malformed?)
115 [255]
115 [255]
116 #else
116 #else
117 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
117 $ hg --config hostsecurity.localhost:verifycertsfile=badca.pem clone https://localhost:$HGPORT/
118 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
118 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
119 abort: error: * (glob)
119 abort: error: * (glob)
120 [255]
120 [255]
121 #endif
121 #endif
122
122
123 A per-host certificate mismatching the server will fail verification
123 A per-host certificate mismatching the server will fail verification
124
124
125 (modern ssl is able to discern whether the loaded cert is a CA cert)
125 (modern ssl is able to discern whether the loaded cert is a CA cert)
126 #if sslcontext
126 #if sslcontext
127 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
127 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
128 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
128 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
129 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
129 (an attempt was made to load CA certificates but none were loaded; see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error)
130 abort: error: *certificate verify failed* (glob)
130 abort: error: *certificate verify failed* (glob)
131 [255]
131 [255]
132 #else
132 #else
133 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
133 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/client-cert.pem" clone https://localhost:$HGPORT/
134 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
134 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
135 abort: error: *certificate verify failed* (glob)
135 abort: error: *certificate verify failed* (glob)
136 [255]
136 [255]
137 #endif
137 #endif
138
138
139 A per-host certificate matching the server's cert will be accepted
139 A per-host certificate matching the server's cert will be accepted
140
140
141 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" clone -U https://localhost:$HGPORT/ perhostgood1
141 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" clone -U https://localhost:$HGPORT/ perhostgood1
142 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
142 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
143 requesting all changes
143 requesting all changes
144 adding changesets
144 adding changesets
145 adding manifests
145 adding manifests
146 adding file changes
146 adding file changes
147 added 1 changesets with 4 changes to 4 files
147 added 1 changesets with 4 changes to 4 files
148
148
149 A per-host certificate with multiple certs and one matching will be accepted
149 A per-host certificate with multiple certs and one matching will be accepted
150
150
151 $ cat "$CERTSDIR/client-cert.pem" "$CERTSDIR/pub.pem" > perhost.pem
151 $ cat "$CERTSDIR/client-cert.pem" "$CERTSDIR/pub.pem" > perhost.pem
152 $ hg --config hostsecurity.localhost:verifycertsfile=perhost.pem clone -U https://localhost:$HGPORT/ perhostgood2
152 $ hg --config hostsecurity.localhost:verifycertsfile=perhost.pem clone -U https://localhost:$HGPORT/ perhostgood2
153 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
153 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
154 requesting all changes
154 requesting all changes
155 adding changesets
155 adding changesets
156 adding manifests
156 adding manifests
157 adding file changes
157 adding file changes
158 added 1 changesets with 4 changes to 4 files
158 added 1 changesets with 4 changes to 4 files
159
159
160 Defining both per-host certificate and a fingerprint will print a warning
160 Defining both per-host certificate and a fingerprint will print a warning
161
161
162 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 clone -U https://localhost:$HGPORT/ caandfingerwarning
162 $ hg --config hostsecurity.localhost:verifycertsfile="$CERTSDIR/pub.pem" --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 clone -U https://localhost:$HGPORT/ caandfingerwarning
163 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
163 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
164 (hostsecurity.localhost:verifycertsfile ignored when host fingerprints defined; using host fingerprints for verification)
164 (hostsecurity.localhost:verifycertsfile ignored when host fingerprints defined; using host fingerprints for verification)
165 requesting all changes
165 requesting all changes
166 adding changesets
166 adding changesets
167 adding manifests
167 adding manifests
168 adding file changes
168 adding file changes
169 added 1 changesets with 4 changes to 4 files
169 added 1 changesets with 4 changes to 4 files
170
170
171 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
171 $ DISABLECACERTS="--config devel.disableloaddefaultcerts=true"
172
172
173 Inability to verify peer certificate will result in abort
173 Inability to verify peer certificate will result in abort
174
174
175 $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLECACERTS
175 $ hg clone https://localhost:$HGPORT/ copy-pull $DISABLECACERTS
176 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
176 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
177 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
177 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
178 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
178 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
179 [255]
179 [255]
180
180
181 $ hg clone --insecure https://localhost:$HGPORT/ copy-pull
181 $ hg clone --insecure https://localhost:$HGPORT/ copy-pull
182 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
182 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
183 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
183 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
184 requesting all changes
184 requesting all changes
185 adding changesets
185 adding changesets
186 adding manifests
186 adding manifests
187 adding file changes
187 adding file changes
188 added 1 changesets with 4 changes to 4 files
188 added 1 changesets with 4 changes to 4 files
189 updating to branch default
189 updating to branch default
190 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 $ hg verify -R copy-pull
191 $ hg verify -R copy-pull
192 checking changesets
192 checking changesets
193 checking manifests
193 checking manifests
194 crosschecking files in changesets and manifests
194 crosschecking files in changesets and manifests
195 checking files
195 checking files
196 4 files, 1 changesets, 4 total revisions
196 4 files, 1 changesets, 4 total revisions
197 $ cd test
197 $ cd test
198 $ echo bar > bar
198 $ echo bar > bar
199 $ hg commit -A -d '1 0' -m 2
199 $ hg commit -A -d '1 0' -m 2
200 adding bar
200 adding bar
201 $ cd ..
201 $ cd ..
202
202
203 pull without cacert
203 pull without cacert
204
204
205 $ cd copy-pull
205 $ cd copy-pull
206 $ cat >> .hg/hgrc <<EOF
206 $ cat >> .hg/hgrc <<EOF
207 > [hooks]
207 > [hooks]
208 > changegroup = sh -c "printenv.py changegroup"
208 > changegroup = sh -c "printenv.py changegroup"
209 > EOF
209 > EOF
210 $ hg pull $DISABLECACERTS
210 $ hg pull $DISABLECACERTS
211 pulling from https://localhost:$HGPORT/
211 pulling from https://localhost:$HGPORT/
212 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
212 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
213 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
213 abort: unable to verify security of localhost (no loaded CA certificates); refusing to connect
214 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
214 (see https://mercurial-scm.org/wiki/SecureConnections for how to configure Mercurial to avoid this error or set hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e to trust this server)
215 [255]
215 [255]
216
216
217 $ hg pull --insecure
217 $ hg pull --insecure
218 pulling from https://localhost:$HGPORT/
218 pulling from https://localhost:$HGPORT/
219 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
219 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
220 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
220 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
221 searching for changes
221 searching for changes
222 adding changesets
222 adding changesets
223 adding manifests
223 adding manifests
224 adding file changes
224 adding file changes
225 added 1 changesets with 1 changes to 1 files
225 added 1 changesets with 1 changes to 1 files
226 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=https://localhost:$HGPORT/ (glob)
226 changegroup hook: HG_NODE=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_NODE_LAST=5fed3813f7f5e1824344fdc9cf8f63bb662c292d HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=https://localhost:$HGPORT/
227 (run 'hg update' to get a working copy)
227 (run 'hg update' to get a working copy)
228 $ cd ..
228 $ cd ..
229
229
230 cacert configured in local repo
230 cacert configured in local repo
231
231
232 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
232 $ cp copy-pull/.hg/hgrc copy-pull/.hg/hgrc.bu
233 $ echo "[web]" >> copy-pull/.hg/hgrc
233 $ echo "[web]" >> copy-pull/.hg/hgrc
234 $ echo "cacerts=$CERTSDIR/pub.pem" >> copy-pull/.hg/hgrc
234 $ echo "cacerts=$CERTSDIR/pub.pem" >> copy-pull/.hg/hgrc
235 $ hg -R copy-pull pull
235 $ hg -R copy-pull pull
236 pulling from https://localhost:$HGPORT/
236 pulling from https://localhost:$HGPORT/
237 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
237 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
238 searching for changes
238 searching for changes
239 no changes found
239 no changes found
240 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
240 $ mv copy-pull/.hg/hgrc.bu copy-pull/.hg/hgrc
241
241
242 cacert configured globally, also testing expansion of environment
242 cacert configured globally, also testing expansion of environment
243 variables in the filename
243 variables in the filename
244
244
245 $ echo "[web]" >> $HGRCPATH
245 $ echo "[web]" >> $HGRCPATH
246 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
246 $ echo 'cacerts=$P/pub.pem' >> $HGRCPATH
247 $ P="$CERTSDIR" hg -R copy-pull pull
247 $ P="$CERTSDIR" hg -R copy-pull pull
248 pulling from https://localhost:$HGPORT/
248 pulling from https://localhost:$HGPORT/
249 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
249 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
250 searching for changes
250 searching for changes
251 no changes found
251 no changes found
252 $ P="$CERTSDIR" hg -R copy-pull pull --insecure
252 $ P="$CERTSDIR" hg -R copy-pull pull --insecure
253 pulling from https://localhost:$HGPORT/
253 pulling from https://localhost:$HGPORT/
254 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
254 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
255 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
255 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
256 searching for changes
256 searching for changes
257 no changes found
257 no changes found
258
258
259 empty cacert file
259 empty cacert file
260
260
261 $ touch emptycafile
261 $ touch emptycafile
262
262
263 #if sslcontext
263 #if sslcontext
264 $ hg --config web.cacerts=emptycafile -R copy-pull pull
264 $ hg --config web.cacerts=emptycafile -R copy-pull pull
265 pulling from https://localhost:$HGPORT/
265 pulling from https://localhost:$HGPORT/
266 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
266 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
267 abort: error loading CA file emptycafile: * (glob)
267 abort: error loading CA file emptycafile: * (glob)
268 (file is empty or malformed?)
268 (file is empty or malformed?)
269 [255]
269 [255]
270 #else
270 #else
271 $ hg --config web.cacerts=emptycafile -R copy-pull pull
271 $ hg --config web.cacerts=emptycafile -R copy-pull pull
272 pulling from https://localhost:$HGPORT/
272 pulling from https://localhost:$HGPORT/
273 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
273 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
274 abort: error: * (glob)
274 abort: error: * (glob)
275 [255]
275 [255]
276 #endif
276 #endif
277
277
278 cacert mismatch
278 cacert mismatch
279
279
280 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
280 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
281 > https://$LOCALIP:$HGPORT/
281 > https://$LOCALIP:$HGPORT/
282 pulling from https://*:$HGPORT/ (glob)
282 pulling from https://*:$HGPORT/ (glob)
283 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
283 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
284 abort: $LOCALIP certificate error: certificate is for localhost
284 abort: $LOCALIP certificate error: certificate is for localhost
285 (set hostsecurity.$LOCALIP:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
285 (set hostsecurity.$LOCALIP:certfingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e config setting or use --insecure to connect insecurely)
286 [255]
286 [255]
287 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
287 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub.pem" \
288 > https://$LOCALIP:$HGPORT/ --insecure
288 > https://$LOCALIP:$HGPORT/ --insecure
289 pulling from https://*:$HGPORT/ (glob)
289 pulling from https://*:$HGPORT/ (glob)
290 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
290 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
291 warning: connection security to $LOCALIP is disabled per current settings; communication is susceptible to eavesdropping and tampering
291 warning: connection security to $LOCALIP is disabled per current settings; communication is susceptible to eavesdropping and tampering
292 searching for changes
292 searching for changes
293 no changes found
293 no changes found
294 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem"
294 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem"
295 pulling from https://localhost:$HGPORT/
295 pulling from https://localhost:$HGPORT/
296 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
296 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
297 abort: error: *certificate verify failed* (glob)
297 abort: error: *certificate verify failed* (glob)
298 [255]
298 [255]
299 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem" \
299 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-other.pem" \
300 > --insecure
300 > --insecure
301 pulling from https://localhost:$HGPORT/
301 pulling from https://localhost:$HGPORT/
302 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
302 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
303 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
303 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
304 searching for changes
304 searching for changes
305 no changes found
305 no changes found
306
306
307 Test server cert which isn't valid yet
307 Test server cert which isn't valid yet
308
308
309 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
309 $ hg serve -R test -p $HGPORT1 -d --pid-file=hg1.pid --certificate=server-not-yet.pem
310 $ cat hg1.pid >> $DAEMON_PIDS
310 $ cat hg1.pid >> $DAEMON_PIDS
311 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-not-yet.pem" \
311 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-not-yet.pem" \
312 > https://localhost:$HGPORT1/
312 > https://localhost:$HGPORT1/
313 pulling from https://localhost:$HGPORT1/
313 pulling from https://localhost:$HGPORT1/
314 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
314 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
315 abort: error: *certificate verify failed* (glob)
315 abort: error: *certificate verify failed* (glob)
316 [255]
316 [255]
317
317
318 Test server cert which no longer is valid
318 Test server cert which no longer is valid
319
319
320 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
320 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
321 $ cat hg2.pid >> $DAEMON_PIDS
321 $ cat hg2.pid >> $DAEMON_PIDS
322 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-expired.pem" \
322 $ hg -R copy-pull pull --config web.cacerts="$CERTSDIR/pub-expired.pem" \
323 > https://localhost:$HGPORT2/
323 > https://localhost:$HGPORT2/
324 pulling from https://localhost:$HGPORT2/
324 pulling from https://localhost:$HGPORT2/
325 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
325 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
326 abort: error: *certificate verify failed* (glob)
326 abort: error: *certificate verify failed* (glob)
327 [255]
327 [255]
328
328
329 Disabling the TLS 1.0 warning works
329 Disabling the TLS 1.0 warning works
330 $ hg -R copy-pull id https://localhost:$HGPORT/ \
330 $ hg -R copy-pull id https://localhost:$HGPORT/ \
331 > --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 \
331 > --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 \
332 > --config hostsecurity.disabletls10warning=true
332 > --config hostsecurity.disabletls10warning=true
333 5fed3813f7f5
333 5fed3813f7f5
334
334
335 #if no-sslcontext no-py27+
335 #if no-sslcontext no-py27+
336 Setting ciphers doesn't work in Python 2.6
336 Setting ciphers doesn't work in Python 2.6
337 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
337 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
338 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
338 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
339 abort: setting ciphers in [hostsecurity] is not supported by this version of Python
339 abort: setting ciphers in [hostsecurity] is not supported by this version of Python
340 (remove the config option or run Mercurial with a modern Python version (preferred))
340 (remove the config option or run Mercurial with a modern Python version (preferred))
341 [255]
341 [255]
342 #endif
342 #endif
343
343
344 Setting ciphers works in Python 2.7+ but the error message is different on
344 Setting ciphers works in Python 2.7+ but the error message is different on
345 legacy ssl. We test legacy once and do more feature checking on modern
345 legacy ssl. We test legacy once and do more feature checking on modern
346 configs.
346 configs.
347
347
348 #if py27+ no-sslcontext
348 #if py27+ no-sslcontext
349 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
349 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
350 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
350 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
351 abort: *No cipher can be selected. (glob)
351 abort: *No cipher can be selected. (glob)
352 [255]
352 [255]
353
353
354 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
354 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
355 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
355 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info
356 5fed3813f7f5
356 5fed3813f7f5
357 #endif
357 #endif
358
358
359 #if sslcontext
359 #if sslcontext
360 Setting ciphers to an invalid value aborts
360 Setting ciphers to an invalid value aborts
361 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
361 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
362 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
362 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
363 abort: could not set ciphers: No cipher can be selected.
363 abort: could not set ciphers: No cipher can be selected.
364 (change cipher string (invalid) in config)
364 (change cipher string (invalid) in config)
365 [255]
365 [255]
366
366
367 $ P="$CERTSDIR" hg --config hostsecurity.localhost:ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
367 $ P="$CERTSDIR" hg --config hostsecurity.localhost:ciphers=invalid -R copy-pull id https://localhost:$HGPORT/
368 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
368 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
369 abort: could not set ciphers: No cipher can be selected.
369 abort: could not set ciphers: No cipher can be selected.
370 (change cipher string (invalid) in config)
370 (change cipher string (invalid) in config)
371 [255]
371 [255]
372
372
373 Changing the cipher string works
373 Changing the cipher string works
374
374
375 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
375 $ P="$CERTSDIR" hg --config hostsecurity.ciphers=HIGH -R copy-pull id https://localhost:$HGPORT/
376 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
376 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
377 5fed3813f7f5
377 5fed3813f7f5
378 #endif
378 #endif
379
379
380 Fingerprints
380 Fingerprints
381
381
382 - works without cacerts (hostfingerprints)
382 - works without cacerts (hostfingerprints)
383 $ hg -R copy-pull id https://localhost:$HGPORT/ --insecure --config hostfingerprints.localhost=ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
383 $ hg -R copy-pull id https://localhost:$HGPORT/ --insecure --config hostfingerprints.localhost=ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
384 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
384 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
385 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
385 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
386 5fed3813f7f5
386 5fed3813f7f5
387
387
388 - works without cacerts (hostsecurity)
388 - works without cacerts (hostsecurity)
389 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
389 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
390 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
390 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
391 5fed3813f7f5
391 5fed3813f7f5
392
392
393 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e
393 $ hg -R copy-pull id https://localhost:$HGPORT/ --config hostsecurity.localhost:fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e
394 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
394 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
395 5fed3813f7f5
395 5fed3813f7f5
396
396
397 - multiple fingerprints specified and first matches
397 - multiple fingerprints specified and first matches
398 $ hg --config 'hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
398 $ hg --config 'hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
399 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
399 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
400 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
400 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
401 5fed3813f7f5
401 5fed3813f7f5
402
402
403 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
403 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03, sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
404 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
404 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
405 5fed3813f7f5
405 5fed3813f7f5
406
406
407 - multiple fingerprints specified and last matches
407 - multiple fingerprints specified and last matches
408 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/ --insecure
408 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/ --insecure
409 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
409 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
410 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
410 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
411 5fed3813f7f5
411 5fed3813f7f5
412
412
413 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/
413 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03' -R copy-pull id https://localhost:$HGPORT/
414 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
414 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
415 5fed3813f7f5
415 5fed3813f7f5
416
416
417 - multiple fingerprints specified and none match
417 - multiple fingerprints specified and none match
418
418
419 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
419 $ hg --config 'hostfingerprints.localhost=deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/ --insecure
420 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
420 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
421 abort: certificate for localhost has unexpected fingerprint ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
421 abort: certificate for localhost has unexpected fingerprint ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
422 (check hostfingerprint configuration)
422 (check hostfingerprint configuration)
423 [255]
423 [255]
424
424
425 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
425 $ hg --config 'hostsecurity.localhost:fingerprints=sha1:deadbeefdeadbeefdeadbeefdeadbeefdeadbeef, sha1:aeadbeefdeadbeefdeadbeefdeadbeefdeadbeef' -R copy-pull id https://localhost:$HGPORT/
426 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
426 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
427 abort: certificate for localhost has unexpected fingerprint sha1:ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
427 abort: certificate for localhost has unexpected fingerprint sha1:ec:d8:7c:d6:b3:86:d0:4f:c1:b8:b4:1c:9d:8f:5e:16:8e:ef:1c:03
428 (check hostsecurity configuration)
428 (check hostsecurity configuration)
429 [255]
429 [255]
430
430
431 - fails when cert doesn't match hostname (port is ignored)
431 - fails when cert doesn't match hostname (port is ignored)
432 $ hg -R copy-pull id https://localhost:$HGPORT1/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
432 $ hg -R copy-pull id https://localhost:$HGPORT1/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
433 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
433 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
434 abort: certificate for localhost has unexpected fingerprint f4:2f:5a:0c:3e:52:5b:db:e7:24:a8:32:1d:18:97:6d:69:b5:87:84
434 abort: certificate for localhost has unexpected fingerprint f4:2f:5a:0c:3e:52:5b:db:e7:24:a8:32:1d:18:97:6d:69:b5:87:84
435 (check hostfingerprint configuration)
435 (check hostfingerprint configuration)
436 [255]
436 [255]
437
437
438
438
439 - ignores that certificate doesn't match hostname
439 - ignores that certificate doesn't match hostname
440 $ hg -R copy-pull id https://$LOCALIP:$HGPORT/ --config hostfingerprints.$LOCALIP=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
440 $ hg -R copy-pull id https://$LOCALIP:$HGPORT/ --config hostfingerprints.$LOCALIP=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03
441 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
441 warning: connecting to $LOCALIP using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
442 (SHA-1 fingerprint for $LOCALIP found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: $LOCALIP.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
442 (SHA-1 fingerprint for $LOCALIP found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: $LOCALIP.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
443 5fed3813f7f5
443 5fed3813f7f5
444
444
445 Ports used by next test. Kill servers.
445 Ports used by next test. Kill servers.
446
446
447 $ killdaemons.py hg0.pid
447 $ killdaemons.py hg0.pid
448 $ killdaemons.py hg1.pid
448 $ killdaemons.py hg1.pid
449 $ killdaemons.py hg2.pid
449 $ killdaemons.py hg2.pid
450
450
451 #if sslcontext tls1.2
451 #if sslcontext tls1.2
452 Start servers running supported TLS versions
452 Start servers running supported TLS versions
453
453
454 $ cd test
454 $ cd test
455 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
455 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
456 > --config devel.serverexactprotocol=tls1.0
456 > --config devel.serverexactprotocol=tls1.0
457 $ cat ../hg0.pid >> $DAEMON_PIDS
457 $ cat ../hg0.pid >> $DAEMON_PIDS
458 $ hg serve -p $HGPORT1 -d --pid-file=../hg1.pid --certificate=$PRIV \
458 $ hg serve -p $HGPORT1 -d --pid-file=../hg1.pid --certificate=$PRIV \
459 > --config devel.serverexactprotocol=tls1.1
459 > --config devel.serverexactprotocol=tls1.1
460 $ cat ../hg1.pid >> $DAEMON_PIDS
460 $ cat ../hg1.pid >> $DAEMON_PIDS
461 $ hg serve -p $HGPORT2 -d --pid-file=../hg2.pid --certificate=$PRIV \
461 $ hg serve -p $HGPORT2 -d --pid-file=../hg2.pid --certificate=$PRIV \
462 > --config devel.serverexactprotocol=tls1.2
462 > --config devel.serverexactprotocol=tls1.2
463 $ cat ../hg2.pid >> $DAEMON_PIDS
463 $ cat ../hg2.pid >> $DAEMON_PIDS
464 $ cd ..
464 $ cd ..
465
465
466 Clients talking same TLS versions work
466 Clients talking same TLS versions work
467
467
468 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.0 id https://localhost:$HGPORT/
468 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.0 id https://localhost:$HGPORT/
469 5fed3813f7f5
469 5fed3813f7f5
470 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/
470 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT1/
471 5fed3813f7f5
471 5fed3813f7f5
472 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/
472 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT2/
473 5fed3813f7f5
473 5fed3813f7f5
474
474
475 Clients requiring newer TLS version than what server supports fail
475 Clients requiring newer TLS version than what server supports fail
476
476
477 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
477 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
478 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
478 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
479 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
479 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
480 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
480 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
481 abort: error: *unsupported protocol* (glob)
481 abort: error: *unsupported protocol* (glob)
482 [255]
482 [255]
483
483
484 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/
484 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.1 id https://localhost:$HGPORT/
485 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
485 (could not negotiate a common security protocol (tls1.1+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
486 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
486 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
487 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
487 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
488 abort: error: *unsupported protocol* (glob)
488 abort: error: *unsupported protocol* (glob)
489 [255]
489 [255]
490 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/
490 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT/
491 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
491 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
492 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
492 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
493 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
493 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
494 abort: error: *unsupported protocol* (glob)
494 abort: error: *unsupported protocol* (glob)
495 [255]
495 [255]
496 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/
496 $ P="$CERTSDIR" hg --config hostsecurity.minimumprotocol=tls1.2 id https://localhost:$HGPORT1/
497 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
497 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
498 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
498 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
499 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
499 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
500 abort: error: *unsupported protocol* (glob)
500 abort: error: *unsupported protocol* (glob)
501 [255]
501 [255]
502
502
503 --insecure will allow TLS 1.0 connections and override configs
503 --insecure will allow TLS 1.0 connections and override configs
504
504
505 $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/
505 $ hg --config hostsecurity.minimumprotocol=tls1.2 id --insecure https://localhost:$HGPORT1/
506 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
506 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
507 5fed3813f7f5
507 5fed3813f7f5
508
508
509 The per-host config option overrides the default
509 The per-host config option overrides the default
510
510
511 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
511 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
512 > --config hostsecurity.minimumprotocol=tls1.2 \
512 > --config hostsecurity.minimumprotocol=tls1.2 \
513 > --config hostsecurity.localhost:minimumprotocol=tls1.0
513 > --config hostsecurity.localhost:minimumprotocol=tls1.0
514 5fed3813f7f5
514 5fed3813f7f5
515
515
516 The per-host config option by itself works
516 The per-host config option by itself works
517
517
518 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
518 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
519 > --config hostsecurity.localhost:minimumprotocol=tls1.2
519 > --config hostsecurity.localhost:minimumprotocol=tls1.2
520 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
520 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
521 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
521 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
522 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
522 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
523 abort: error: *unsupported protocol* (glob)
523 abort: error: *unsupported protocol* (glob)
524 [255]
524 [255]
525
525
526 .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305)
526 .hg/hgrc file [hostsecurity] settings are applied to remote ui instances (issue5305)
527
527
528 $ cat >> copy-pull/.hg/hgrc << EOF
528 $ cat >> copy-pull/.hg/hgrc << EOF
529 > [hostsecurity]
529 > [hostsecurity]
530 > localhost:minimumprotocol=tls1.2
530 > localhost:minimumprotocol=tls1.2
531 > EOF
531 > EOF
532 $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/
532 $ P="$CERTSDIR" hg -R copy-pull id https://localhost:$HGPORT/
533 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
533 (could not negotiate a common security protocol (tls1.2+) with localhost; the likely cause is Mercurial is configured to be more secure than the server can support)
534 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
534 (consider contacting the operator of this server and ask them to support modern TLS protocol versions; or, set hostsecurity.localhost:minimumprotocol=tls1.0 to allow use of legacy, less secure protocols when communicating with this server)
535 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
535 (see https://mercurial-scm.org/wiki/SecureConnections for more info)
536 abort: error: *unsupported protocol* (glob)
536 abort: error: *unsupported protocol* (glob)
537 [255]
537 [255]
538
538
539 $ killdaemons.py hg0.pid
539 $ killdaemons.py hg0.pid
540 $ killdaemons.py hg1.pid
540 $ killdaemons.py hg1.pid
541 $ killdaemons.py hg2.pid
541 $ killdaemons.py hg2.pid
542 #endif
542 #endif
543
543
544 Prepare for connecting through proxy
544 Prepare for connecting through proxy
545
545
546 $ hg serve -R test -p $HGPORT -d --pid-file=hg0.pid --certificate=$PRIV
546 $ hg serve -R test -p $HGPORT -d --pid-file=hg0.pid --certificate=$PRIV
547 $ cat hg0.pid >> $DAEMON_PIDS
547 $ cat hg0.pid >> $DAEMON_PIDS
548 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
548 $ hg serve -R test -p $HGPORT2 -d --pid-file=hg2.pid --certificate=server-expired.pem
549 $ cat hg2.pid >> $DAEMON_PIDS
549 $ cat hg2.pid >> $DAEMON_PIDS
550 tinyproxy.py doesn't fully detach, so killing it may result in extra output
550 tinyproxy.py doesn't fully detach, so killing it may result in extra output
551 from the shell. So don't kill it.
551 from the shell. So don't kill it.
552 $ tinyproxy.py $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
552 $ tinyproxy.py $HGPORT1 localhost >proxy.log </dev/null 2>&1 &
553 $ while [ ! -f proxy.pid ]; do sleep 0; done
553 $ while [ ! -f proxy.pid ]; do sleep 0; done
554 $ cat proxy.pid >> $DAEMON_PIDS
554 $ cat proxy.pid >> $DAEMON_PIDS
555
555
556 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
556 $ echo "[http_proxy]" >> copy-pull/.hg/hgrc
557 $ echo "always=True" >> copy-pull/.hg/hgrc
557 $ echo "always=True" >> copy-pull/.hg/hgrc
558 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
558 $ echo "[hostfingerprints]" >> copy-pull/.hg/hgrc
559 $ echo "localhost =" >> copy-pull/.hg/hgrc
559 $ echo "localhost =" >> copy-pull/.hg/hgrc
560
560
561 Test unvalidated https through proxy
561 Test unvalidated https through proxy
562
562
563 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure
563 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull --insecure
564 pulling from https://localhost:$HGPORT/
564 pulling from https://localhost:$HGPORT/
565 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
565 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
566 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
566 warning: connection security to localhost is disabled per current settings; communication is susceptible to eavesdropping and tampering
567 searching for changes
567 searching for changes
568 no changes found
568 no changes found
569
569
570 Test https with cacert and fingerprint through proxy
570 Test https with cacert and fingerprint through proxy
571
571
572 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
572 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
573 > --config web.cacerts="$CERTSDIR/pub.pem"
573 > --config web.cacerts="$CERTSDIR/pub.pem"
574 pulling from https://localhost:$HGPORT/
574 pulling from https://localhost:$HGPORT/
575 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
575 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
576 searching for changes
576 searching for changes
577 no changes found
577 no changes found
578 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://localhost:$HGPORT/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 --trace
578 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull https://localhost:$HGPORT/ --config hostfingerprints.localhost=ecd87cd6b386d04fc1b8b41c9d8f5e168eef1c03 --trace
579 pulling from https://*:$HGPORT/ (glob)
579 pulling from https://*:$HGPORT/ (glob)
580 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
580 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
581 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
581 (SHA-1 fingerprint for localhost found in legacy [hostfingerprints] section; if you trust this fingerprint, set the following config value in [hostsecurity] and remove the old one from [hostfingerprints] to upgrade to a more secure SHA-256 fingerprint: localhost.fingerprints=sha256:20:de:b3:ad:b4:cd:a5:42:f0:74:41:1c:a2:70:1e:da:6e:c0:5c:16:9e:e7:22:0f:f1:b7:e5:6e:e4:92:af:7e)
582 searching for changes
582 searching for changes
583 no changes found
583 no changes found
584
584
585 Test https with cert problems through proxy
585 Test https with cert problems through proxy
586
586
587 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
587 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
588 > --config web.cacerts="$CERTSDIR/pub-other.pem"
588 > --config web.cacerts="$CERTSDIR/pub-other.pem"
589 pulling from https://localhost:$HGPORT/
589 pulling from https://localhost:$HGPORT/
590 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
590 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
591 abort: error: *certificate verify failed* (glob)
591 abort: error: *certificate verify failed* (glob)
592 [255]
592 [255]
593 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
593 $ http_proxy=http://localhost:$HGPORT1/ hg -R copy-pull pull \
594 > --config web.cacerts="$CERTSDIR/pub-expired.pem" https://localhost:$HGPORT2/
594 > --config web.cacerts="$CERTSDIR/pub-expired.pem" https://localhost:$HGPORT2/
595 pulling from https://localhost:$HGPORT2/
595 pulling from https://localhost:$HGPORT2/
596 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
596 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
597 abort: error: *certificate verify failed* (glob)
597 abort: error: *certificate verify failed* (glob)
598 [255]
598 [255]
599
599
600
600
601 $ killdaemons.py hg0.pid
601 $ killdaemons.py hg0.pid
602
602
603 #if sslcontext
603 #if sslcontext
604
604
605 Start hgweb that requires client certificates:
605 Start hgweb that requires client certificates:
606
606
607 $ cd test
607 $ cd test
608 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
608 $ hg serve -p $HGPORT -d --pid-file=../hg0.pid --certificate=$PRIV \
609 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
609 > --config devel.servercafile=$PRIV --config devel.serverrequirecert=true
610 $ cat ../hg0.pid >> $DAEMON_PIDS
610 $ cat ../hg0.pid >> $DAEMON_PIDS
611 $ cd ..
611 $ cd ..
612
612
613 without client certificate:
613 without client certificate:
614
614
615 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
615 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/
616 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
616 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
617 abort: error: *handshake failure* (glob)
617 abort: error: *handshake failure* (glob)
618 [255]
618 [255]
619
619
620 with client certificate:
620 with client certificate:
621
621
622 $ cat << EOT >> $HGRCPATH
622 $ cat << EOT >> $HGRCPATH
623 > [auth]
623 > [auth]
624 > l.prefix = localhost
624 > l.prefix = localhost
625 > l.cert = $CERTSDIR/client-cert.pem
625 > l.cert = $CERTSDIR/client-cert.pem
626 > l.key = $CERTSDIR/client-key.pem
626 > l.key = $CERTSDIR/client-key.pem
627 > EOT
627 > EOT
628
628
629 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
629 $ P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
630 > --config auth.l.key="$CERTSDIR/client-key-decrypted.pem"
630 > --config auth.l.key="$CERTSDIR/client-key-decrypted.pem"
631 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
631 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
632 5fed3813f7f5
632 5fed3813f7f5
633
633
634 $ printf '1234\n' | env P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
634 $ printf '1234\n' | env P="$CERTSDIR" hg id https://localhost:$HGPORT/ \
635 > --config ui.interactive=True --config ui.nontty=True
635 > --config ui.interactive=True --config ui.nontty=True
636 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
636 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
637 passphrase for */client-key.pem: 5fed3813f7f5 (glob)
637 passphrase for */client-key.pem: 5fed3813f7f5 (glob)
638
638
639 $ env P="$CERTSDIR" hg id https://localhost:$HGPORT/
639 $ env P="$CERTSDIR" hg id https://localhost:$HGPORT/
640 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
640 warning: connecting to localhost using legacy security technology (TLS 1.0); see https://mercurial-scm.org/wiki/SecureConnections for more info (?)
641 abort: error: * (glob)
641 abort: error: * (glob)
642 [255]
642 [255]
643
643
644 #endif
644 #endif
@@ -1,203 +1,203 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 This test checks behavior related to bundle1 that changed or is likely
3 This test checks behavior related to bundle1 that changed or is likely
4 to change with bundle2. Feel free to factor out any part of the test
4 to change with bundle2. Feel free to factor out any part of the test
5 which does not need to exist to keep bundle1 working.
5 which does not need to exist to keep bundle1 working.
6
6
7 $ cat << EOF >> $HGRCPATH
7 $ cat << EOF >> $HGRCPATH
8 > [devel]
8 > [devel]
9 > # This test is dedicated to interaction through old bundle
9 > # This test is dedicated to interaction through old bundle
10 > legacy.exchange = bundle1
10 > legacy.exchange = bundle1
11 > EOF
11 > EOF
12
12
13 $ hg init test
13 $ hg init test
14 $ cd test
14 $ cd test
15 $ echo a > a
15 $ echo a > a
16 $ hg ci -Ama
16 $ hg ci -Ama
17 adding a
17 adding a
18 $ cd ..
18 $ cd ..
19 $ hg clone test test2
19 $ hg clone test test2
20 updating to branch default
20 updating to branch default
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
21 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
22 $ cd test2
22 $ cd test2
23 $ echo a >> a
23 $ echo a >> a
24 $ hg ci -mb
24 $ hg ci -mb
25 $ req() {
25 $ req() {
26 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
26 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
27 > cat hg.pid >> $DAEMON_PIDS
27 > cat hg.pid >> $DAEMON_PIDS
28 > hg --cwd ../test2 push http://localhost:$HGPORT/
28 > hg --cwd ../test2 push http://localhost:$HGPORT/
29 > exitstatus=$?
29 > exitstatus=$?
30 > killdaemons.py
30 > killdaemons.py
31 > echo % serve errors
31 > echo % serve errors
32 > cat errors.log
32 > cat errors.log
33 > return $exitstatus
33 > return $exitstatus
34 > }
34 > }
35 $ cd ../test
35 $ cd ../test
36
36
37 expect ssl error
37 expect ssl error
38
38
39 $ req
39 $ req
40 pushing to http://localhost:$HGPORT/
40 pushing to http://localhost:$HGPORT/
41 searching for changes
41 searching for changes
42 abort: HTTP Error 403: ssl required
42 abort: HTTP Error 403: ssl required
43 % serve errors
43 % serve errors
44 [255]
44 [255]
45
45
46 expect authorization error
46 expect authorization error
47
47
48 $ echo '[web]' > .hg/hgrc
48 $ echo '[web]' > .hg/hgrc
49 $ echo 'push_ssl = false' >> .hg/hgrc
49 $ echo 'push_ssl = false' >> .hg/hgrc
50 $ req
50 $ req
51 pushing to http://localhost:$HGPORT/
51 pushing to http://localhost:$HGPORT/
52 searching for changes
52 searching for changes
53 abort: authorization failed
53 abort: authorization failed
54 % serve errors
54 % serve errors
55 [255]
55 [255]
56
56
57 expect authorization error: must have authorized user
57 expect authorization error: must have authorized user
58
58
59 $ echo 'allow_push = unperson' >> .hg/hgrc
59 $ echo 'allow_push = unperson' >> .hg/hgrc
60 $ req
60 $ req
61 pushing to http://localhost:$HGPORT/
61 pushing to http://localhost:$HGPORT/
62 searching for changes
62 searching for changes
63 abort: authorization failed
63 abort: authorization failed
64 % serve errors
64 % serve errors
65 [255]
65 [255]
66
66
67 expect success
67 expect success
68
68
69 $ cat >> .hg/hgrc <<EOF
69 $ cat >> .hg/hgrc <<EOF
70 > allow_push = *
70 > allow_push = *
71 > [hooks]
71 > [hooks]
72 > changegroup = sh -c "printenv.py changegroup 0"
72 > changegroup = sh -c "printenv.py changegroup 0"
73 > pushkey = sh -c "printenv.py pushkey 0"
73 > pushkey = sh -c "printenv.py pushkey 0"
74 > EOF
74 > EOF
75 $ req
75 $ req
76 pushing to http://localhost:$HGPORT/
76 pushing to http://localhost:$HGPORT/
77 searching for changes
77 searching for changes
78 remote: adding changesets
78 remote: adding changesets
79 remote: adding manifests
79 remote: adding manifests
80 remote: adding file changes
80 remote: adding file changes
81 remote: added 1 changesets with 1 changes to 1 files
81 remote: added 1 changesets with 1 changes to 1 files
82 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
82 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
83 % serve errors
83 % serve errors
84 $ hg rollback
84 $ hg rollback
85 repository tip rolled back to revision 0 (undo serve)
85 repository tip rolled back to revision 0 (undo serve)
86
86
87 expect success, server lacks the httpheader capability
87 expect success, server lacks the httpheader capability
88
88
89 $ CAP=httpheader
89 $ CAP=httpheader
90 $ . "$TESTDIR/notcapable"
90 $ . "$TESTDIR/notcapable"
91 $ req
91 $ req
92 pushing to http://localhost:$HGPORT/
92 pushing to http://localhost:$HGPORT/
93 searching for changes
93 searching for changes
94 remote: adding changesets
94 remote: adding changesets
95 remote: adding manifests
95 remote: adding manifests
96 remote: adding file changes
96 remote: adding file changes
97 remote: added 1 changesets with 1 changes to 1 files
97 remote: added 1 changesets with 1 changes to 1 files
98 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
98 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
99 % serve errors
99 % serve errors
100 $ hg rollback
100 $ hg rollback
101 repository tip rolled back to revision 0 (undo serve)
101 repository tip rolled back to revision 0 (undo serve)
102
102
103 expect success, server lacks the unbundlehash capability
103 expect success, server lacks the unbundlehash capability
104
104
105 $ CAP=unbundlehash
105 $ CAP=unbundlehash
106 $ . "$TESTDIR/notcapable"
106 $ . "$TESTDIR/notcapable"
107 $ req
107 $ req
108 pushing to http://localhost:$HGPORT/
108 pushing to http://localhost:$HGPORT/
109 searching for changes
109 searching for changes
110 remote: adding changesets
110 remote: adding changesets
111 remote: adding manifests
111 remote: adding manifests
112 remote: adding file changes
112 remote: adding file changes
113 remote: added 1 changesets with 1 changes to 1 files
113 remote: added 1 changesets with 1 changes to 1 files
114 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
114 remote: changegroup hook: HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
115 % serve errors
115 % serve errors
116 $ hg rollback
116 $ hg rollback
117 repository tip rolled back to revision 0 (undo serve)
117 repository tip rolled back to revision 0 (undo serve)
118
118
119 expect success, pre-d1b16a746db6 server supports the unbundle capability, but
119 expect success, pre-d1b16a746db6 server supports the unbundle capability, but
120 has no parameter
120 has no parameter
121
121
122 $ cat <<EOF > notcapable-unbundleparam.py
122 $ cat <<EOF > notcapable-unbundleparam.py
123 > from mercurial import extensions, httppeer
123 > from mercurial import extensions, httppeer
124 > def capable(orig, self, name):
124 > def capable(orig, self, name):
125 > if name == 'unbundle':
125 > if name == 'unbundle':
126 > return True
126 > return True
127 > return orig(self, name)
127 > return orig(self, name)
128 > def uisetup(ui):
128 > def uisetup(ui):
129 > extensions.wrapfunction(httppeer.httppeer, 'capable', capable)
129 > extensions.wrapfunction(httppeer.httppeer, 'capable', capable)
130 > EOF
130 > EOF
131 $ cp $HGRCPATH $HGRCPATH.orig
131 $ cp $HGRCPATH $HGRCPATH.orig
132 $ cat <<EOF >> $HGRCPATH
132 $ cat <<EOF >> $HGRCPATH
133 > [extensions]
133 > [extensions]
134 > notcapable-unbundleparam = `pwd`/notcapable-unbundleparam.py
134 > notcapable-unbundleparam = `pwd`/notcapable-unbundleparam.py
135 > EOF
135 > EOF
136 $ req
136 $ req
137 pushing to http://localhost:$HGPORT/
137 pushing to http://localhost:$HGPORT/
138 searching for changes
138 searching for changes
139 remote: adding changesets
139 remote: adding changesets
140 remote: adding manifests
140 remote: adding manifests
141 remote: adding file changes
141 remote: adding file changes
142 remote: added 1 changesets with 1 changes to 1 files
142 remote: added 1 changesets with 1 changes to 1 files
143 remote: changegroup hook: * (glob)
143 remote: changegroup hook: * (glob)
144 % serve errors
144 % serve errors
145 $ hg rollback
145 $ hg rollback
146 repository tip rolled back to revision 0 (undo serve)
146 repository tip rolled back to revision 0 (undo serve)
147 $ mv $HGRCPATH.orig $HGRCPATH
147 $ mv $HGRCPATH.orig $HGRCPATH
148
148
149 expect push success, phase change failure
149 expect push success, phase change failure
150
150
151 $ cat > .hg/hgrc <<EOF
151 $ cat > .hg/hgrc <<EOF
152 > [web]
152 > [web]
153 > push_ssl = false
153 > push_ssl = false
154 > allow_push = *
154 > allow_push = *
155 > [hooks]
155 > [hooks]
156 > prepushkey = sh -c "printenv.py prepushkey 1"
156 > prepushkey = sh -c "printenv.py prepushkey 1"
157 > EOF
157 > EOF
158 $ req
158 $ req
159 pushing to http://localhost:$HGPORT/
159 pushing to http://localhost:$HGPORT/
160 searching for changes
160 searching for changes
161 remote: adding changesets
161 remote: adding changesets
162 remote: adding manifests
162 remote: adding manifests
163 remote: adding file changes
163 remote: adding file changes
164 remote: added 1 changesets with 1 changes to 1 files
164 remote: added 1 changesets with 1 changes to 1 files
165 % serve errors
165 % serve errors
166
166
167 expect phase change success
167 expect phase change success
168
168
169 $ cat >> .hg/hgrc <<EOF
169 $ cat >> .hg/hgrc <<EOF
170 > prepushkey = sh -c "printenv.py prepushkey 0"
170 > prepushkey = sh -c "printenv.py prepushkey 0"
171 > EOF
171 > EOF
172 $ req
172 $ req
173 pushing to http://localhost:$HGPORT/
173 pushing to http://localhost:$HGPORT/
174 searching for changes
174 searching for changes
175 no changes found
175 no changes found
176 % serve errors
176 % serve errors
177 [1]
177 [1]
178 $ hg rollback
178 $ hg rollback
179 repository tip rolled back to revision 0 (undo serve)
179 repository tip rolled back to revision 0 (undo serve)
180
180
181 expect authorization error: all users denied
181 expect authorization error: all users denied
182
182
183 $ echo '[web]' > .hg/hgrc
183 $ echo '[web]' > .hg/hgrc
184 $ echo 'push_ssl = false' >> .hg/hgrc
184 $ echo 'push_ssl = false' >> .hg/hgrc
185 $ echo 'deny_push = *' >> .hg/hgrc
185 $ echo 'deny_push = *' >> .hg/hgrc
186 $ req
186 $ req
187 pushing to http://localhost:$HGPORT/
187 pushing to http://localhost:$HGPORT/
188 searching for changes
188 searching for changes
189 abort: authorization failed
189 abort: authorization failed
190 % serve errors
190 % serve errors
191 [255]
191 [255]
192
192
193 expect authorization error: some users denied, users must be authenticated
193 expect authorization error: some users denied, users must be authenticated
194
194
195 $ echo 'deny_push = unperson' >> .hg/hgrc
195 $ echo 'deny_push = unperson' >> .hg/hgrc
196 $ req
196 $ req
197 pushing to http://localhost:$HGPORT/
197 pushing to http://localhost:$HGPORT/
198 searching for changes
198 searching for changes
199 abort: authorization failed
199 abort: authorization failed
200 % serve errors
200 % serve errors
201 [255]
201 [255]
202
202
203 $ cd ..
203 $ cd ..
@@ -1,175 +1,175 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ hg init test
3 $ hg init test
4 $ cd test
4 $ cd test
5 $ echo a > a
5 $ echo a > a
6 $ hg ci -Ama
6 $ hg ci -Ama
7 adding a
7 adding a
8 $ cd ..
8 $ cd ..
9 $ hg clone test test2
9 $ hg clone test test2
10 updating to branch default
10 updating to branch default
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
11 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
12 $ cd test2
12 $ cd test2
13 $ echo a >> a
13 $ echo a >> a
14 $ hg ci -mb
14 $ hg ci -mb
15 $ req() {
15 $ req() {
16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
16 > hg serve -p $HGPORT -d --pid-file=hg.pid -E errors.log
17 > cat hg.pid >> $DAEMON_PIDS
17 > cat hg.pid >> $DAEMON_PIDS
18 > hg --cwd ../test2 push http://localhost:$HGPORT/
18 > hg --cwd ../test2 push http://localhost:$HGPORT/
19 > exitstatus=$?
19 > exitstatus=$?
20 > killdaemons.py
20 > killdaemons.py
21 > echo % serve errors
21 > echo % serve errors
22 > cat errors.log
22 > cat errors.log
23 > return $exitstatus
23 > return $exitstatus
24 > }
24 > }
25 $ cd ../test
25 $ cd ../test
26
26
27 expect ssl error
27 expect ssl error
28
28
29 $ req
29 $ req
30 pushing to http://localhost:$HGPORT/
30 pushing to http://localhost:$HGPORT/
31 searching for changes
31 searching for changes
32 abort: HTTP Error 403: ssl required
32 abort: HTTP Error 403: ssl required
33 % serve errors
33 % serve errors
34 [255]
34 [255]
35
35
36 expect authorization error
36 expect authorization error
37
37
38 $ echo '[web]' > .hg/hgrc
38 $ echo '[web]' > .hg/hgrc
39 $ echo 'push_ssl = false' >> .hg/hgrc
39 $ echo 'push_ssl = false' >> .hg/hgrc
40 $ req
40 $ req
41 pushing to http://localhost:$HGPORT/
41 pushing to http://localhost:$HGPORT/
42 searching for changes
42 searching for changes
43 abort: authorization failed
43 abort: authorization failed
44 % serve errors
44 % serve errors
45 [255]
45 [255]
46
46
47 expect authorization error: must have authorized user
47 expect authorization error: must have authorized user
48
48
49 $ echo 'allow_push = unperson' >> .hg/hgrc
49 $ echo 'allow_push = unperson' >> .hg/hgrc
50 $ req
50 $ req
51 pushing to http://localhost:$HGPORT/
51 pushing to http://localhost:$HGPORT/
52 searching for changes
52 searching for changes
53 abort: authorization failed
53 abort: authorization failed
54 % serve errors
54 % serve errors
55 [255]
55 [255]
56
56
57 expect success
57 expect success
58
58
59 $ cat >> .hg/hgrc <<EOF
59 $ cat >> .hg/hgrc <<EOF
60 > allow_push = *
60 > allow_push = *
61 > [hooks]
61 > [hooks]
62 > changegroup = sh -c "printenv.py changegroup 0"
62 > changegroup = sh -c "printenv.py changegroup 0"
63 > pushkey = sh -c "printenv.py pushkey 0"
63 > pushkey = sh -c "printenv.py pushkey 0"
64 > EOF
64 > EOF
65 $ req
65 $ req
66 pushing to http://localhost:$HGPORT/
66 pushing to http://localhost:$HGPORT/
67 searching for changes
67 searching for changes
68 remote: adding changesets
68 remote: adding changesets
69 remote: adding manifests
69 remote: adding manifests
70 remote: adding file changes
70 remote: adding file changes
71 remote: added 1 changesets with 1 changes to 1 files
71 remote: added 1 changesets with 1 changes to 1 files
72 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
72 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
73 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
73 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
74 % serve errors
74 % serve errors
75 $ hg rollback
75 $ hg rollback
76 repository tip rolled back to revision 0 (undo serve)
76 repository tip rolled back to revision 0 (undo serve)
77
77
78 expect success, server lacks the httpheader capability
78 expect success, server lacks the httpheader capability
79
79
80 $ CAP=httpheader
80 $ CAP=httpheader
81 $ . "$TESTDIR/notcapable"
81 $ . "$TESTDIR/notcapable"
82 $ req
82 $ req
83 pushing to http://localhost:$HGPORT/
83 pushing to http://localhost:$HGPORT/
84 searching for changes
84 searching for changes
85 remote: adding changesets
85 remote: adding changesets
86 remote: adding manifests
86 remote: adding manifests
87 remote: adding file changes
87 remote: adding file changes
88 remote: added 1 changesets with 1 changes to 1 files
88 remote: added 1 changesets with 1 changes to 1 files
89 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
89 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
90 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
90 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
91 % serve errors
91 % serve errors
92 $ hg rollback
92 $ hg rollback
93 repository tip rolled back to revision 0 (undo serve)
93 repository tip rolled back to revision 0 (undo serve)
94
94
95 expect success, server lacks the unbundlehash capability
95 expect success, server lacks the unbundlehash capability
96
96
97 $ CAP=unbundlehash
97 $ CAP=unbundlehash
98 $ . "$TESTDIR/notcapable"
98 $ . "$TESTDIR/notcapable"
99 $ req
99 $ req
100 pushing to http://localhost:$HGPORT/
100 pushing to http://localhost:$HGPORT/
101 searching for changes
101 searching for changes
102 remote: adding changesets
102 remote: adding changesets
103 remote: adding manifests
103 remote: adding manifests
104 remote: adding file changes
104 remote: adding file changes
105 remote: added 1 changesets with 1 changes to 1 files
105 remote: added 1 changesets with 1 changes to 1 files
106 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
106 remote: pushkey hook: HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_OLD=1 HG_RET=1
107 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
107 remote: changegroup hook: HG_BUNDLE2=1 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
108 % serve errors
108 % serve errors
109 $ hg rollback
109 $ hg rollback
110 repository tip rolled back to revision 0 (undo serve)
110 repository tip rolled back to revision 0 (undo serve)
111
111
112 expect push success, phase change failure
112 expect push success, phase change failure
113
113
114 $ cat > .hg/hgrc <<EOF
114 $ cat > .hg/hgrc <<EOF
115 > [web]
115 > [web]
116 > push_ssl = false
116 > push_ssl = false
117 > allow_push = *
117 > allow_push = *
118 > [hooks]
118 > [hooks]
119 > prepushkey = sh -c "printenv.py prepushkey 1"
119 > prepushkey = sh -c "printenv.py prepushkey 1"
120 > EOF
120 > EOF
121 $ req
121 $ req
122 pushing to http://localhost:$HGPORT/
122 pushing to http://localhost:$HGPORT/
123 searching for changes
123 searching for changes
124 remote: adding changesets
124 remote: adding changesets
125 remote: adding manifests
125 remote: adding manifests
126 remote: adding file changes
126 remote: adding file changes
127 remote: added 1 changesets with 1 changes to 1 files
127 remote: added 1 changesets with 1 changes to 1 files
128 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
128 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
129 remote: pushkey-abort: prepushkey hook exited with status 1
129 remote: pushkey-abort: prepushkey hook exited with status 1
130 remote: transaction abort!
130 remote: transaction abort!
131 remote: rollback completed
131 remote: rollback completed
132 abort: updating ba677d0156c1 to public failed
132 abort: updating ba677d0156c1 to public failed
133 % serve errors
133 % serve errors
134 [255]
134 [255]
135
135
136 expect phase change success
136 expect phase change success
137
137
138 $ cat >> .hg/hgrc <<EOF
138 $ cat >> .hg/hgrc <<EOF
139 > prepushkey = sh -c "printenv.py prepushkey 0"
139 > prepushkey = sh -c "printenv.py prepushkey 0"
140 > EOF
140 > EOF
141 $ req
141 $ req
142 pushing to http://localhost:$HGPORT/
142 pushing to http://localhost:$HGPORT/
143 searching for changes
143 searching for changes
144 remote: adding changesets
144 remote: adding changesets
145 remote: adding manifests
145 remote: adding manifests
146 remote: adding file changes
146 remote: adding file changes
147 remote: added 1 changesets with 1 changes to 1 files
147 remote: added 1 changesets with 1 changes to 1 files
148 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:http:*: (glob)
148 remote: prepushkey hook: HG_BUNDLE2=1 HG_KEY=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NAMESPACE=phases HG_NEW=0 HG_NODE=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_NODE_LAST=ba677d0156c1196c1a699fa53f390dcfc3ce3872 HG_OLD=1 HG_PENDING=$TESTTMP/test HG_PHASES_MOVED=1 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:http:$LOCALIP:
149 % serve errors
149 % serve errors
150 $ hg rollback
150 $ hg rollback
151 repository tip rolled back to revision 0 (undo serve)
151 repository tip rolled back to revision 0 (undo serve)
152
152
153 expect authorization error: all users denied
153 expect authorization error: all users denied
154
154
155 $ echo '[web]' > .hg/hgrc
155 $ echo '[web]' > .hg/hgrc
156 $ echo 'push_ssl = false' >> .hg/hgrc
156 $ echo 'push_ssl = false' >> .hg/hgrc
157 $ echo 'deny_push = *' >> .hg/hgrc
157 $ echo 'deny_push = *' >> .hg/hgrc
158 $ req
158 $ req
159 pushing to http://localhost:$HGPORT/
159 pushing to http://localhost:$HGPORT/
160 searching for changes
160 searching for changes
161 abort: authorization failed
161 abort: authorization failed
162 % serve errors
162 % serve errors
163 [255]
163 [255]
164
164
165 expect authorization error: some users denied, users must be authenticated
165 expect authorization error: some users denied, users must be authenticated
166
166
167 $ echo 'deny_push = unperson' >> .hg/hgrc
167 $ echo 'deny_push = unperson' >> .hg/hgrc
168 $ req
168 $ req
169 pushing to http://localhost:$HGPORT/
169 pushing to http://localhost:$HGPORT/
170 searching for changes
170 searching for changes
171 abort: authorization failed
171 abort: authorization failed
172 % serve errors
172 % serve errors
173 [255]
173 [255]
174
174
175 $ cd ..
175 $ cd ..
@@ -1,562 +1,562 b''
1 This test is a duplicate of 'test-http.t' feel free to factor out
1 This test is a duplicate of 'test-http.t' feel free to factor out
2 parts that are not bundle1/bundle2 specific.
2 parts that are not bundle1/bundle2 specific.
3
3
4 $ cat << EOF >> $HGRCPATH
4 $ cat << EOF >> $HGRCPATH
5 > [devel]
5 > [devel]
6 > # This test is dedicated to interaction through old bundle
6 > # This test is dedicated to interaction through old bundle
7 > legacy.exchange = bundle1
7 > legacy.exchange = bundle1
8 > [format] # temporary settings
8 > [format] # temporary settings
9 > usegeneraldelta=yes
9 > usegeneraldelta=yes
10 > EOF
10 > EOF
11
11
12
12
13 This test tries to exercise the ssh functionality with a dummy script
13 This test tries to exercise the ssh functionality with a dummy script
14
14
15 creating 'remote' repo
15 creating 'remote' repo
16
16
17 $ hg init remote
17 $ hg init remote
18 $ cd remote
18 $ cd remote
19 $ echo this > foo
19 $ echo this > foo
20 $ echo this > fooO
20 $ echo this > fooO
21 $ hg ci -A -m "init" foo fooO
21 $ hg ci -A -m "init" foo fooO
22
22
23 insert a closed branch (issue4428)
23 insert a closed branch (issue4428)
24
24
25 $ hg up null
25 $ hg up null
26 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
26 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
27 $ hg branch closed
27 $ hg branch closed
28 marked working directory as branch closed
28 marked working directory as branch closed
29 (branches are permanent and global, did you want a bookmark?)
29 (branches are permanent and global, did you want a bookmark?)
30 $ hg ci -mc0
30 $ hg ci -mc0
31 $ hg ci --close-branch -mc1
31 $ hg ci --close-branch -mc1
32 $ hg up -q default
32 $ hg up -q default
33
33
34 configure for serving
34 configure for serving
35
35
36 $ cat <<EOF > .hg/hgrc
36 $ cat <<EOF > .hg/hgrc
37 > [server]
37 > [server]
38 > uncompressed = True
38 > uncompressed = True
39 >
39 >
40 > [hooks]
40 > [hooks]
41 > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
41 > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
42 > EOF
42 > EOF
43 $ cd ..
43 $ cd ..
44
44
45 repo not found error
45 repo not found error
46
46
47 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
47 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
48 remote: abort: repository nonexistent not found!
48 remote: abort: repository nonexistent not found!
49 abort: no suitable response from remote hg!
49 abort: no suitable response from remote hg!
50 [255]
50 [255]
51
51
52 non-existent absolute path
52 non-existent absolute path
53
53
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
54 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy//`pwd`/nonexistent local
55 remote: abort: repository /$TESTTMP/nonexistent not found!
55 remote: abort: repository /$TESTTMP/nonexistent not found!
56 abort: no suitable response from remote hg!
56 abort: no suitable response from remote hg!
57 [255]
57 [255]
58
58
59 clone remote via stream
59 clone remote via stream
60
60
61 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
61 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
62 streaming all changes
62 streaming all changes
63 4 files to transfer, 602 bytes of data
63 4 files to transfer, 602 bytes of data
64 transferred 602 bytes in * seconds (*) (glob)
64 transferred 602 bytes in * seconds (*) (glob)
65 searching for changes
65 searching for changes
66 no changes found
66 no changes found
67 updating to branch default
67 updating to branch default
68 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
69 $ cd local-stream
69 $ cd local-stream
70 $ hg verify
70 $ hg verify
71 checking changesets
71 checking changesets
72 checking manifests
72 checking manifests
73 crosschecking files in changesets and manifests
73 crosschecking files in changesets and manifests
74 checking files
74 checking files
75 2 files, 3 changesets, 2 total revisions
75 2 files, 3 changesets, 2 total revisions
76 $ hg branches
76 $ hg branches
77 default 0:1160648e36ce
77 default 0:1160648e36ce
78 $ cd ..
78 $ cd ..
79
79
80 clone bookmarks via stream
80 clone bookmarks via stream
81
81
82 $ hg -R local-stream book mybook
82 $ hg -R local-stream book mybook
83 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
83 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
84 streaming all changes
84 streaming all changes
85 4 files to transfer, 602 bytes of data
85 4 files to transfer, 602 bytes of data
86 transferred 602 bytes in * seconds (*) (glob)
86 transferred 602 bytes in * seconds (*) (glob)
87 searching for changes
87 searching for changes
88 no changes found
88 no changes found
89 updating to branch default
89 updating to branch default
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
91 $ cd stream2
91 $ cd stream2
92 $ hg book
92 $ hg book
93 mybook 0:1160648e36ce
93 mybook 0:1160648e36ce
94 $ cd ..
94 $ cd ..
95 $ rm -rf local-stream stream2
95 $ rm -rf local-stream stream2
96
96
97 clone remote via pull
97 clone remote via pull
98
98
99 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
99 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
100 requesting all changes
100 requesting all changes
101 adding changesets
101 adding changesets
102 adding manifests
102 adding manifests
103 adding file changes
103 adding file changes
104 added 3 changesets with 2 changes to 2 files
104 added 3 changesets with 2 changes to 2 files
105 updating to branch default
105 updating to branch default
106 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
107
107
108 verify
108 verify
109
109
110 $ cd local
110 $ cd local
111 $ hg verify
111 $ hg verify
112 checking changesets
112 checking changesets
113 checking manifests
113 checking manifests
114 crosschecking files in changesets and manifests
114 crosschecking files in changesets and manifests
115 checking files
115 checking files
116 2 files, 3 changesets, 2 total revisions
116 2 files, 3 changesets, 2 total revisions
117 $ cat >> .hg/hgrc <<EOF
117 $ cat >> .hg/hgrc <<EOF
118 > [hooks]
118 > [hooks]
119 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
119 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
120 > EOF
120 > EOF
121
121
122 empty default pull
122 empty default pull
123
123
124 $ hg paths
124 $ hg paths
125 default = ssh://user@dummy/remote
125 default = ssh://user@dummy/remote
126 $ hg pull -e "python \"$TESTDIR/dummyssh\""
126 $ hg pull -e "python \"$TESTDIR/dummyssh\""
127 pulling from ssh://user@dummy/remote
127 pulling from ssh://user@dummy/remote
128 searching for changes
128 searching for changes
129 no changes found
129 no changes found
130
130
131 pull from wrong ssh URL
131 pull from wrong ssh URL
132
132
133 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
133 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
134 pulling from ssh://user@dummy/doesnotexist
134 pulling from ssh://user@dummy/doesnotexist
135 remote: abort: repository doesnotexist not found!
135 remote: abort: repository doesnotexist not found!
136 abort: no suitable response from remote hg!
136 abort: no suitable response from remote hg!
137 [255]
137 [255]
138
138
139 local change
139 local change
140
140
141 $ echo bleah > foo
141 $ echo bleah > foo
142 $ hg ci -m "add"
142 $ hg ci -m "add"
143
143
144 updating rc
144 updating rc
145
145
146 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
146 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
147 $ echo "[ui]" >> .hg/hgrc
147 $ echo "[ui]" >> .hg/hgrc
148 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
148 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
149
149
150 find outgoing
150 find outgoing
151
151
152 $ hg out ssh://user@dummy/remote
152 $ hg out ssh://user@dummy/remote
153 comparing with ssh://user@dummy/remote
153 comparing with ssh://user@dummy/remote
154 searching for changes
154 searching for changes
155 changeset: 3:a28a9d1a809c
155 changeset: 3:a28a9d1a809c
156 tag: tip
156 tag: tip
157 parent: 0:1160648e36ce
157 parent: 0:1160648e36ce
158 user: test
158 user: test
159 date: Thu Jan 01 00:00:00 1970 +0000
159 date: Thu Jan 01 00:00:00 1970 +0000
160 summary: add
160 summary: add
161
161
162
162
163 find incoming on the remote side
163 find incoming on the remote side
164
164
165 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
165 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
166 comparing with ssh://user@dummy/local
166 comparing with ssh://user@dummy/local
167 searching for changes
167 searching for changes
168 changeset: 3:a28a9d1a809c
168 changeset: 3:a28a9d1a809c
169 tag: tip
169 tag: tip
170 parent: 0:1160648e36ce
170 parent: 0:1160648e36ce
171 user: test
171 user: test
172 date: Thu Jan 01 00:00:00 1970 +0000
172 date: Thu Jan 01 00:00:00 1970 +0000
173 summary: add
173 summary: add
174
174
175
175
176 find incoming on the remote side (using absolute path)
176 find incoming on the remote side (using absolute path)
177
177
178 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
178 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
179 comparing with ssh://user@dummy/$TESTTMP/local
179 comparing with ssh://user@dummy/$TESTTMP/local
180 searching for changes
180 searching for changes
181 changeset: 3:a28a9d1a809c
181 changeset: 3:a28a9d1a809c
182 tag: tip
182 tag: tip
183 parent: 0:1160648e36ce
183 parent: 0:1160648e36ce
184 user: test
184 user: test
185 date: Thu Jan 01 00:00:00 1970 +0000
185 date: Thu Jan 01 00:00:00 1970 +0000
186 summary: add
186 summary: add
187
187
188
188
189 push
189 push
190
190
191 $ hg push
191 $ hg push
192 pushing to ssh://user@dummy/remote
192 pushing to ssh://user@dummy/remote
193 searching for changes
193 searching for changes
194 remote: adding changesets
194 remote: adding changesets
195 remote: adding manifests
195 remote: adding manifests
196 remote: adding file changes
196 remote: adding file changes
197 remote: added 1 changesets with 1 changes to 1 files
197 remote: added 1 changesets with 1 changes to 1 files
198 $ cd ../remote
198 $ cd ../remote
199
199
200 check remote tip
200 check remote tip
201
201
202 $ hg tip
202 $ hg tip
203 changeset: 3:a28a9d1a809c
203 changeset: 3:a28a9d1a809c
204 tag: tip
204 tag: tip
205 parent: 0:1160648e36ce
205 parent: 0:1160648e36ce
206 user: test
206 user: test
207 date: Thu Jan 01 00:00:00 1970 +0000
207 date: Thu Jan 01 00:00:00 1970 +0000
208 summary: add
208 summary: add
209
209
210 $ hg verify
210 $ hg verify
211 checking changesets
211 checking changesets
212 checking manifests
212 checking manifests
213 crosschecking files in changesets and manifests
213 crosschecking files in changesets and manifests
214 checking files
214 checking files
215 2 files, 4 changesets, 3 total revisions
215 2 files, 4 changesets, 3 total revisions
216 $ hg cat -r tip foo
216 $ hg cat -r tip foo
217 bleah
217 bleah
218 $ echo z > z
218 $ echo z > z
219 $ hg ci -A -m z z
219 $ hg ci -A -m z z
220 created new head
220 created new head
221
221
222 test pushkeys and bookmarks
222 test pushkeys and bookmarks
223
223
224 $ cd ../local
224 $ cd ../local
225 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
225 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
226 bookmarks
226 bookmarks
227 namespaces
227 namespaces
228 phases
228 phases
229 $ hg book foo -r 0
229 $ hg book foo -r 0
230 $ hg out -B
230 $ hg out -B
231 comparing with ssh://user@dummy/remote
231 comparing with ssh://user@dummy/remote
232 searching for changed bookmarks
232 searching for changed bookmarks
233 foo 1160648e36ce
233 foo 1160648e36ce
234 $ hg push -B foo
234 $ hg push -B foo
235 pushing to ssh://user@dummy/remote
235 pushing to ssh://user@dummy/remote
236 searching for changes
236 searching for changes
237 no changes found
237 no changes found
238 exporting bookmark foo
238 exporting bookmark foo
239 [1]
239 [1]
240 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
240 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
241 foo 1160648e36cec0054048a7edc4110c6f84fde594
241 foo 1160648e36cec0054048a7edc4110c6f84fde594
242 $ hg book -f foo
242 $ hg book -f foo
243 $ hg push --traceback
243 $ hg push --traceback
244 pushing to ssh://user@dummy/remote
244 pushing to ssh://user@dummy/remote
245 searching for changes
245 searching for changes
246 no changes found
246 no changes found
247 updating bookmark foo
247 updating bookmark foo
248 [1]
248 [1]
249 $ hg book -d foo
249 $ hg book -d foo
250 $ hg in -B
250 $ hg in -B
251 comparing with ssh://user@dummy/remote
251 comparing with ssh://user@dummy/remote
252 searching for changed bookmarks
252 searching for changed bookmarks
253 foo a28a9d1a809c
253 foo a28a9d1a809c
254 $ hg book -f -r 0 foo
254 $ hg book -f -r 0 foo
255 $ hg pull -B foo
255 $ hg pull -B foo
256 pulling from ssh://user@dummy/remote
256 pulling from ssh://user@dummy/remote
257 no changes found
257 no changes found
258 updating bookmark foo
258 updating bookmark foo
259 $ hg book -d foo
259 $ hg book -d foo
260 $ hg push -B foo
260 $ hg push -B foo
261 pushing to ssh://user@dummy/remote
261 pushing to ssh://user@dummy/remote
262 searching for changes
262 searching for changes
263 no changes found
263 no changes found
264 deleting remote bookmark foo
264 deleting remote bookmark foo
265 [1]
265 [1]
266
266
267 a bad, evil hook that prints to stdout
267 a bad, evil hook that prints to stdout
268
268
269 $ cat <<EOF > $TESTTMP/badhook
269 $ cat <<EOF > $TESTTMP/badhook
270 > import sys
270 > import sys
271 > sys.stdout.write("KABOOM\n")
271 > sys.stdout.write("KABOOM\n")
272 > EOF
272 > EOF
273
273
274 $ echo '[hooks]' >> ../remote/.hg/hgrc
274 $ echo '[hooks]' >> ../remote/.hg/hgrc
275 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
275 $ echo "changegroup.stdout = python $TESTTMP/badhook" >> ../remote/.hg/hgrc
276 $ echo r > r
276 $ echo r > r
277 $ hg ci -A -m z r
277 $ hg ci -A -m z r
278
278
279 push should succeed even though it has an unexpected response
279 push should succeed even though it has an unexpected response
280
280
281 $ hg push
281 $ hg push
282 pushing to ssh://user@dummy/remote
282 pushing to ssh://user@dummy/remote
283 searching for changes
283 searching for changes
284 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
284 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
285 remote: adding changesets
285 remote: adding changesets
286 remote: adding manifests
286 remote: adding manifests
287 remote: adding file changes
287 remote: adding file changes
288 remote: added 1 changesets with 1 changes to 1 files
288 remote: added 1 changesets with 1 changes to 1 files
289 remote: KABOOM
289 remote: KABOOM
290 $ hg -R ../remote heads
290 $ hg -R ../remote heads
291 changeset: 5:1383141674ec
291 changeset: 5:1383141674ec
292 tag: tip
292 tag: tip
293 parent: 3:a28a9d1a809c
293 parent: 3:a28a9d1a809c
294 user: test
294 user: test
295 date: Thu Jan 01 00:00:00 1970 +0000
295 date: Thu Jan 01 00:00:00 1970 +0000
296 summary: z
296 summary: z
297
297
298 changeset: 4:6c0482d977a3
298 changeset: 4:6c0482d977a3
299 parent: 0:1160648e36ce
299 parent: 0:1160648e36ce
300 user: test
300 user: test
301 date: Thu Jan 01 00:00:00 1970 +0000
301 date: Thu Jan 01 00:00:00 1970 +0000
302 summary: z
302 summary: z
303
303
304
304
305 clone bookmarks
305 clone bookmarks
306
306
307 $ hg -R ../remote bookmark test
307 $ hg -R ../remote bookmark test
308 $ hg -R ../remote bookmarks
308 $ hg -R ../remote bookmarks
309 * test 4:6c0482d977a3
309 * test 4:6c0482d977a3
310 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
310 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
311 requesting all changes
311 requesting all changes
312 adding changesets
312 adding changesets
313 adding manifests
313 adding manifests
314 adding file changes
314 adding file changes
315 added 6 changesets with 5 changes to 4 files (+1 heads)
315 added 6 changesets with 5 changes to 4 files (+1 heads)
316 updating to branch default
316 updating to branch default
317 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
317 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
318 $ hg -R local-bookmarks bookmarks
318 $ hg -R local-bookmarks bookmarks
319 test 4:6c0482d977a3
319 test 4:6c0482d977a3
320
320
321 passwords in ssh urls are not supported
321 passwords in ssh urls are not supported
322 (we use a glob here because different Python versions give different
322 (we use a glob here because different Python versions give different
323 results here)
323 results here)
324
324
325 $ hg push ssh://user:erroneouspwd@dummy/remote
325 $ hg push ssh://user:erroneouspwd@dummy/remote
326 pushing to ssh://user:*@dummy/remote (glob)
326 pushing to ssh://user:*@dummy/remote (glob)
327 abort: password in URL not supported!
327 abort: password in URL not supported!
328 [255]
328 [255]
329
329
330 $ cd ..
330 $ cd ..
331
331
332 hide outer repo
332 hide outer repo
333 $ hg init
333 $ hg init
334
334
335 Test remote paths with spaces (issue2983):
335 Test remote paths with spaces (issue2983):
336
336
337 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
337 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
338 $ touch "$TESTTMP/a repo/test"
338 $ touch "$TESTTMP/a repo/test"
339 $ hg -R 'a repo' commit -A -m "test"
339 $ hg -R 'a repo' commit -A -m "test"
340 adding test
340 adding test
341 $ hg -R 'a repo' tag tag
341 $ hg -R 'a repo' tag tag
342 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
342 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
343 73649e48688a
343 73649e48688a
344
344
345 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
345 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
346 abort: unknown revision 'noNoNO'!
346 abort: unknown revision 'noNoNO'!
347 [255]
347 [255]
348
348
349 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
349 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
350
350
351 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
351 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
352 destination directory: a repo
352 destination directory: a repo
353 abort: destination 'a repo' is not empty
353 abort: destination 'a repo' is not empty
354 [255]
354 [255]
355
355
356 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
356 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
357 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
357 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
358 parameters:
358 parameters:
359
359
360 $ cat > ssh.sh << EOF
360 $ cat > ssh.sh << EOF
361 > userhost="\$1"
361 > userhost="\$1"
362 > SSH_ORIGINAL_COMMAND="\$2"
362 > SSH_ORIGINAL_COMMAND="\$2"
363 > export SSH_ORIGINAL_COMMAND
363 > export SSH_ORIGINAL_COMMAND
364 > PYTHONPATH="$PYTHONPATH"
364 > PYTHONPATH="$PYTHONPATH"
365 > export PYTHONPATH
365 > export PYTHONPATH
366 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
366 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
367 > EOF
367 > EOF
368
368
369 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
369 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
370 73649e48688a
370 73649e48688a
371
371
372 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
372 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
373 remote: Illegal repository "$TESTTMP/a'repo" (glob)
373 remote: Illegal repository "$TESTTMP/a'repo" (glob)
374 abort: no suitable response from remote hg!
374 abort: no suitable response from remote hg!
375 [255]
375 [255]
376
376
377 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
377 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
378 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
378 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
379 abort: no suitable response from remote hg!
379 abort: no suitable response from remote hg!
380 [255]
380 [255]
381
381
382 $ SSH_ORIGINAL_COMMAND="'hg' serve -R 'a'repo' --stdio" python "$TESTDIR/../contrib/hg-ssh"
382 $ SSH_ORIGINAL_COMMAND="'hg' serve -R 'a'repo' --stdio" python "$TESTDIR/../contrib/hg-ssh"
383 Illegal command "'hg' serve -R 'a'repo' --stdio": No closing quotation
383 Illegal command "'hg' serve -R 'a'repo' --stdio": No closing quotation
384 [255]
384 [255]
385
385
386 Test hg-ssh in read-only mode:
386 Test hg-ssh in read-only mode:
387
387
388 $ cat > ssh.sh << EOF
388 $ cat > ssh.sh << EOF
389 > userhost="\$1"
389 > userhost="\$1"
390 > SSH_ORIGINAL_COMMAND="\$2"
390 > SSH_ORIGINAL_COMMAND="\$2"
391 > export SSH_ORIGINAL_COMMAND
391 > export SSH_ORIGINAL_COMMAND
392 > PYTHONPATH="$PYTHONPATH"
392 > PYTHONPATH="$PYTHONPATH"
393 > export PYTHONPATH
393 > export PYTHONPATH
394 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
394 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
395 > EOF
395 > EOF
396
396
397 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
397 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
398 requesting all changes
398 requesting all changes
399 adding changesets
399 adding changesets
400 adding manifests
400 adding manifests
401 adding file changes
401 adding file changes
402 added 6 changesets with 5 changes to 4 files (+1 heads)
402 added 6 changesets with 5 changes to 4 files (+1 heads)
403 updating to branch default
403 updating to branch default
404 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
404 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
405
405
406 $ cd read-only-local
406 $ cd read-only-local
407 $ echo "baz" > bar
407 $ echo "baz" > bar
408 $ hg ci -A -m "unpushable commit" bar
408 $ hg ci -A -m "unpushable commit" bar
409 $ hg push --ssh "sh ../ssh.sh"
409 $ hg push --ssh "sh ../ssh.sh"
410 pushing to ssh://user@dummy/*/remote (glob)
410 pushing to ssh://user@dummy/*/remote (glob)
411 searching for changes
411 searching for changes
412 remote: Permission denied
412 remote: Permission denied
413 remote: abort: pretxnopen.hg-ssh hook failed
413 remote: abort: pretxnopen.hg-ssh hook failed
414 remote: Permission denied
414 remote: Permission denied
415 remote: pushkey-abort: prepushkey.hg-ssh hook failed
415 remote: pushkey-abort: prepushkey.hg-ssh hook failed
416 updating 6c0482d977a3 to public failed!
416 updating 6c0482d977a3 to public failed!
417 [1]
417 [1]
418
418
419 $ cd ..
419 $ cd ..
420
420
421 stderr from remote commands should be printed before stdout from local code (issue4336)
421 stderr from remote commands should be printed before stdout from local code (issue4336)
422
422
423 $ hg clone remote stderr-ordering
423 $ hg clone remote stderr-ordering
424 updating to branch default
424 updating to branch default
425 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
425 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
426 $ cd stderr-ordering
426 $ cd stderr-ordering
427 $ cat >> localwrite.py << EOF
427 $ cat >> localwrite.py << EOF
428 > from mercurial import exchange, extensions
428 > from mercurial import exchange, extensions
429 >
429 >
430 > def wrappedpush(orig, repo, *args, **kwargs):
430 > def wrappedpush(orig, repo, *args, **kwargs):
431 > res = orig(repo, *args, **kwargs)
431 > res = orig(repo, *args, **kwargs)
432 > repo.ui.write('local stdout\n')
432 > repo.ui.write('local stdout\n')
433 > return res
433 > return res
434 >
434 >
435 > def extsetup(ui):
435 > def extsetup(ui):
436 > extensions.wrapfunction(exchange, 'push', wrappedpush)
436 > extensions.wrapfunction(exchange, 'push', wrappedpush)
437 > EOF
437 > EOF
438
438
439 $ cat >> .hg/hgrc << EOF
439 $ cat >> .hg/hgrc << EOF
440 > [paths]
440 > [paths]
441 > default-push = ssh://user@dummy/remote
441 > default-push = ssh://user@dummy/remote
442 > [ui]
442 > [ui]
443 > ssh = python "$TESTDIR/dummyssh"
443 > ssh = python "$TESTDIR/dummyssh"
444 > [extensions]
444 > [extensions]
445 > localwrite = localwrite.py
445 > localwrite = localwrite.py
446 > EOF
446 > EOF
447
447
448 $ echo localwrite > foo
448 $ echo localwrite > foo
449 $ hg commit -m 'testing localwrite'
449 $ hg commit -m 'testing localwrite'
450 $ hg push
450 $ hg push
451 pushing to ssh://user@dummy/remote
451 pushing to ssh://user@dummy/remote
452 searching for changes
452 searching for changes
453 remote: adding changesets
453 remote: adding changesets
454 remote: adding manifests
454 remote: adding manifests
455 remote: adding file changes
455 remote: adding file changes
456 remote: added 1 changesets with 1 changes to 1 files
456 remote: added 1 changesets with 1 changes to 1 files
457 remote: KABOOM
457 remote: KABOOM
458 local stdout
458 local stdout
459
459
460 debug output
460 debug output
461
461
462 $ hg pull --debug ssh://user@dummy/remote
462 $ hg pull --debug ssh://user@dummy/remote
463 pulling from ssh://user@dummy/remote
463 pulling from ssh://user@dummy/remote
464 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
464 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
465 sending hello command
465 sending hello command
466 sending between command
466 sending between command
467 remote: 355
467 remote: 355
468 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN
468 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN
469 remote: 1
469 remote: 1
470 preparing listkeys for "bookmarks"
470 preparing listkeys for "bookmarks"
471 sending listkeys command
471 sending listkeys command
472 received listkey for "bookmarks": 45 bytes
472 received listkey for "bookmarks": 45 bytes
473 query 1; heads
473 query 1; heads
474 sending batch command
474 sending batch command
475 searching for changes
475 searching for changes
476 all remote heads known locally
476 all remote heads known locally
477 no changes found
477 no changes found
478 preparing listkeys for "phases"
478 preparing listkeys for "phases"
479 sending listkeys command
479 sending listkeys command
480 received listkey for "phases": 15 bytes
480 received listkey for "phases": 15 bytes
481 checking for updated bookmarks
481 checking for updated bookmarks
482
482
483 $ cd ..
483 $ cd ..
484
484
485 $ cat dummylog
485 $ cat dummylog
486 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
486 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
487 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
487 Got arguments 1:user@dummy 2:hg -R /$TESTTMP/nonexistent serve --stdio
488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
488 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
489 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
489 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
490 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
491 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
492 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 Got arguments 1:user@dummy 2:hg -R local serve --stdio
494 Got arguments 1:user@dummy 2:hg -R local serve --stdio
495 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
495 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
497 changegroup-in-remote hook: HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
499 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
506 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
506 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
507 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
507 changegroup-in-remote hook: HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
509 Got arguments 1:user@dummy 2:hg init 'a repo'
509 Got arguments 1:user@dummy 2:hg init 'a repo'
510 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
510 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
511 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
511 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
512 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
512 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
513 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
513 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
514 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
514 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
515 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
515 changegroup-in-remote hook: HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
516 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
516 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
517
517
518 remote hook failure is attributed to remote
518 remote hook failure is attributed to remote
519
519
520 $ cat > $TESTTMP/failhook << EOF
520 $ cat > $TESTTMP/failhook << EOF
521 > def hook(ui, repo, **kwargs):
521 > def hook(ui, repo, **kwargs):
522 > ui.write('hook failure!\n')
522 > ui.write('hook failure!\n')
523 > ui.flush()
523 > ui.flush()
524 > return 1
524 > return 1
525 > EOF
525 > EOF
526
526
527 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
527 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
528
528
529 $ hg -q --config ui.ssh="python $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
529 $ hg -q --config ui.ssh="python $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
530 $ cd hookout
530 $ cd hookout
531 $ touch hookfailure
531 $ touch hookfailure
532 $ hg -q commit -A -m 'remote hook failure'
532 $ hg -q commit -A -m 'remote hook failure'
533 $ hg --config ui.ssh="python $TESTDIR/dummyssh" push
533 $ hg --config ui.ssh="python $TESTDIR/dummyssh" push
534 pushing to ssh://user@dummy/remote
534 pushing to ssh://user@dummy/remote
535 searching for changes
535 searching for changes
536 remote: adding changesets
536 remote: adding changesets
537 remote: adding manifests
537 remote: adding manifests
538 remote: adding file changes
538 remote: adding file changes
539 remote: added 1 changesets with 1 changes to 1 files
539 remote: added 1 changesets with 1 changes to 1 files
540 remote: hook failure!
540 remote: hook failure!
541 remote: transaction abort!
541 remote: transaction abort!
542 remote: rollback completed
542 remote: rollback completed
543 remote: abort: pretxnchangegroup.fail hook failed
543 remote: abort: pretxnchangegroup.fail hook failed
544 [1]
544 [1]
545
545
546 abort during pull is properly reported as such
546 abort during pull is properly reported as such
547
547
548 $ echo morefoo >> ../remote/foo
548 $ echo morefoo >> ../remote/foo
549 $ hg -R ../remote commit --message "more foo to be pulled"
549 $ hg -R ../remote commit --message "more foo to be pulled"
550 $ cat >> ../remote/.hg/hgrc << EOF
550 $ cat >> ../remote/.hg/hgrc << EOF
551 > [extensions]
551 > [extensions]
552 > crash = ${TESTDIR}/crashgetbundler.py
552 > crash = ${TESTDIR}/crashgetbundler.py
553 > EOF
553 > EOF
554 $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
554 $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
555 pulling from ssh://user@dummy/remote
555 pulling from ssh://user@dummy/remote
556 searching for changes
556 searching for changes
557 adding changesets
557 adding changesets
558 remote: abort: this is an exercise
558 remote: abort: this is an exercise
559 transaction abort!
559 transaction abort!
560 rollback completed
560 rollback completed
561 abort: stream ended unexpectedly (got 0 bytes, expected 4)
561 abort: stream ended unexpectedly (got 0 bytes, expected 4)
562 [255]
562 [255]
@@ -1,564 +1,564 b''
1
1
2 This test tries to exercise the ssh functionality with a dummy script
2 This test tries to exercise the ssh functionality with a dummy script
3
3
4 $ cat <<EOF >> $HGRCPATH
4 $ cat <<EOF >> $HGRCPATH
5 > [format]
5 > [format]
6 > usegeneraldelta=yes
6 > usegeneraldelta=yes
7 > EOF
7 > EOF
8
8
9 creating 'remote' repo
9 creating 'remote' repo
10
10
11 $ hg init remote
11 $ hg init remote
12 $ cd remote
12 $ cd remote
13 $ echo this > foo
13 $ echo this > foo
14 $ echo this > fooO
14 $ echo this > fooO
15 $ hg ci -A -m "init" foo fooO
15 $ hg ci -A -m "init" foo fooO
16
16
17 insert a closed branch (issue4428)
17 insert a closed branch (issue4428)
18
18
19 $ hg up null
19 $ hg up null
20 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
20 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
21 $ hg branch closed
21 $ hg branch closed
22 marked working directory as branch closed
22 marked working directory as branch closed
23 (branches are permanent and global, did you want a bookmark?)
23 (branches are permanent and global, did you want a bookmark?)
24 $ hg ci -mc0
24 $ hg ci -mc0
25 $ hg ci --close-branch -mc1
25 $ hg ci --close-branch -mc1
26 $ hg up -q default
26 $ hg up -q default
27
27
28 configure for serving
28 configure for serving
29
29
30 $ cat <<EOF > .hg/hgrc
30 $ cat <<EOF > .hg/hgrc
31 > [server]
31 > [server]
32 > uncompressed = True
32 > uncompressed = True
33 >
33 >
34 > [hooks]
34 > [hooks]
35 > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
35 > changegroup = sh -c "printenv.py changegroup-in-remote 0 ../dummylog"
36 > EOF
36 > EOF
37 $ cd ..
37 $ cd ..
38
38
39 repo not found error
39 repo not found error
40
40
41 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
41 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/nonexistent local
42 remote: abort: repository nonexistent not found!
42 remote: abort: repository nonexistent not found!
43 abort: no suitable response from remote hg!
43 abort: no suitable response from remote hg!
44 [255]
44 [255]
45
45
46 non-existent absolute path
46 non-existent absolute path
47
47
48 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
48 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/`pwd`/nonexistent local
49 remote: abort: repository $TESTTMP/nonexistent not found!
49 remote: abort: repository $TESTTMP/nonexistent not found!
50 abort: no suitable response from remote hg!
50 abort: no suitable response from remote hg!
51 [255]
51 [255]
52
52
53 clone remote via stream
53 clone remote via stream
54
54
55 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
55 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/remote local-stream
56 streaming all changes
56 streaming all changes
57 4 files to transfer, 602 bytes of data
57 4 files to transfer, 602 bytes of data
58 transferred 602 bytes in * seconds (*) (glob)
58 transferred 602 bytes in * seconds (*) (glob)
59 searching for changes
59 searching for changes
60 no changes found
60 no changes found
61 updating to branch default
61 updating to branch default
62 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
62 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
63 $ cd local-stream
63 $ cd local-stream
64 $ hg verify
64 $ hg verify
65 checking changesets
65 checking changesets
66 checking manifests
66 checking manifests
67 crosschecking files in changesets and manifests
67 crosschecking files in changesets and manifests
68 checking files
68 checking files
69 2 files, 3 changesets, 2 total revisions
69 2 files, 3 changesets, 2 total revisions
70 $ hg branches
70 $ hg branches
71 default 0:1160648e36ce
71 default 0:1160648e36ce
72 $ cd ..
72 $ cd ..
73
73
74 clone bookmarks via stream
74 clone bookmarks via stream
75
75
76 $ hg -R local-stream book mybook
76 $ hg -R local-stream book mybook
77 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
77 $ hg clone -e "python \"$TESTDIR/dummyssh\"" --uncompressed ssh://user@dummy/local-stream stream2
78 streaming all changes
78 streaming all changes
79 4 files to transfer, 602 bytes of data
79 4 files to transfer, 602 bytes of data
80 transferred 602 bytes in * seconds (*) (glob)
80 transferred 602 bytes in * seconds (*) (glob)
81 searching for changes
81 searching for changes
82 no changes found
82 no changes found
83 updating to branch default
83 updating to branch default
84 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
85 $ cd stream2
85 $ cd stream2
86 $ hg book
86 $ hg book
87 mybook 0:1160648e36ce
87 mybook 0:1160648e36ce
88 $ cd ..
88 $ cd ..
89 $ rm -rf local-stream stream2
89 $ rm -rf local-stream stream2
90
90
91 clone remote via pull
91 clone remote via pull
92
92
93 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
93 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local
94 requesting all changes
94 requesting all changes
95 adding changesets
95 adding changesets
96 adding manifests
96 adding manifests
97 adding file changes
97 adding file changes
98 added 3 changesets with 2 changes to 2 files
98 added 3 changesets with 2 changes to 2 files
99 updating to branch default
99 updating to branch default
100 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
100 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
101
101
102 verify
102 verify
103
103
104 $ cd local
104 $ cd local
105 $ hg verify
105 $ hg verify
106 checking changesets
106 checking changesets
107 checking manifests
107 checking manifests
108 crosschecking files in changesets and manifests
108 crosschecking files in changesets and manifests
109 checking files
109 checking files
110 2 files, 3 changesets, 2 total revisions
110 2 files, 3 changesets, 2 total revisions
111 $ cat >> .hg/hgrc <<EOF
111 $ cat >> .hg/hgrc <<EOF
112 > [hooks]
112 > [hooks]
113 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
113 > changegroup = sh -c "printenv.py changegroup-in-local 0 ../dummylog"
114 > EOF
114 > EOF
115
115
116 empty default pull
116 empty default pull
117
117
118 $ hg paths
118 $ hg paths
119 default = ssh://user@dummy/remote
119 default = ssh://user@dummy/remote
120 $ hg pull -e "python \"$TESTDIR/dummyssh\""
120 $ hg pull -e "python \"$TESTDIR/dummyssh\""
121 pulling from ssh://user@dummy/remote
121 pulling from ssh://user@dummy/remote
122 searching for changes
122 searching for changes
123 no changes found
123 no changes found
124
124
125 pull from wrong ssh URL
125 pull from wrong ssh URL
126
126
127 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
127 $ hg pull -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/doesnotexist
128 pulling from ssh://user@dummy/doesnotexist
128 pulling from ssh://user@dummy/doesnotexist
129 remote: abort: repository doesnotexist not found!
129 remote: abort: repository doesnotexist not found!
130 abort: no suitable response from remote hg!
130 abort: no suitable response from remote hg!
131 [255]
131 [255]
132
132
133 local change
133 local change
134
134
135 $ echo bleah > foo
135 $ echo bleah > foo
136 $ hg ci -m "add"
136 $ hg ci -m "add"
137
137
138 updating rc
138 updating rc
139
139
140 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
140 $ echo "default-push = ssh://user@dummy/remote" >> .hg/hgrc
141 $ echo "[ui]" >> .hg/hgrc
141 $ echo "[ui]" >> .hg/hgrc
142 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
142 $ echo "ssh = python \"$TESTDIR/dummyssh\"" >> .hg/hgrc
143
143
144 find outgoing
144 find outgoing
145
145
146 $ hg out ssh://user@dummy/remote
146 $ hg out ssh://user@dummy/remote
147 comparing with ssh://user@dummy/remote
147 comparing with ssh://user@dummy/remote
148 searching for changes
148 searching for changes
149 changeset: 3:a28a9d1a809c
149 changeset: 3:a28a9d1a809c
150 tag: tip
150 tag: tip
151 parent: 0:1160648e36ce
151 parent: 0:1160648e36ce
152 user: test
152 user: test
153 date: Thu Jan 01 00:00:00 1970 +0000
153 date: Thu Jan 01 00:00:00 1970 +0000
154 summary: add
154 summary: add
155
155
156
156
157 find incoming on the remote side
157 find incoming on the remote side
158
158
159 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
159 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/local
160 comparing with ssh://user@dummy/local
160 comparing with ssh://user@dummy/local
161 searching for changes
161 searching for changes
162 changeset: 3:a28a9d1a809c
162 changeset: 3:a28a9d1a809c
163 tag: tip
163 tag: tip
164 parent: 0:1160648e36ce
164 parent: 0:1160648e36ce
165 user: test
165 user: test
166 date: Thu Jan 01 00:00:00 1970 +0000
166 date: Thu Jan 01 00:00:00 1970 +0000
167 summary: add
167 summary: add
168
168
169
169
170 find incoming on the remote side (using absolute path)
170 find incoming on the remote side (using absolute path)
171
171
172 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
172 $ hg incoming -R ../remote -e "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/`pwd`"
173 comparing with ssh://user@dummy/$TESTTMP/local
173 comparing with ssh://user@dummy/$TESTTMP/local
174 searching for changes
174 searching for changes
175 changeset: 3:a28a9d1a809c
175 changeset: 3:a28a9d1a809c
176 tag: tip
176 tag: tip
177 parent: 0:1160648e36ce
177 parent: 0:1160648e36ce
178 user: test
178 user: test
179 date: Thu Jan 01 00:00:00 1970 +0000
179 date: Thu Jan 01 00:00:00 1970 +0000
180 summary: add
180 summary: add
181
181
182
182
183 push
183 push
184
184
185 $ hg push
185 $ hg push
186 pushing to ssh://user@dummy/remote
186 pushing to ssh://user@dummy/remote
187 searching for changes
187 searching for changes
188 remote: adding changesets
188 remote: adding changesets
189 remote: adding manifests
189 remote: adding manifests
190 remote: adding file changes
190 remote: adding file changes
191 remote: added 1 changesets with 1 changes to 1 files
191 remote: added 1 changesets with 1 changes to 1 files
192 $ cd ../remote
192 $ cd ../remote
193
193
194 check remote tip
194 check remote tip
195
195
196 $ hg tip
196 $ hg tip
197 changeset: 3:a28a9d1a809c
197 changeset: 3:a28a9d1a809c
198 tag: tip
198 tag: tip
199 parent: 0:1160648e36ce
199 parent: 0:1160648e36ce
200 user: test
200 user: test
201 date: Thu Jan 01 00:00:00 1970 +0000
201 date: Thu Jan 01 00:00:00 1970 +0000
202 summary: add
202 summary: add
203
203
204 $ hg verify
204 $ hg verify
205 checking changesets
205 checking changesets
206 checking manifests
206 checking manifests
207 crosschecking files in changesets and manifests
207 crosschecking files in changesets and manifests
208 checking files
208 checking files
209 2 files, 4 changesets, 3 total revisions
209 2 files, 4 changesets, 3 total revisions
210 $ hg cat -r tip foo
210 $ hg cat -r tip foo
211 bleah
211 bleah
212 $ echo z > z
212 $ echo z > z
213 $ hg ci -A -m z z
213 $ hg ci -A -m z z
214 created new head
214 created new head
215
215
216 test pushkeys and bookmarks
216 test pushkeys and bookmarks
217
217
218 $ cd ../local
218 $ cd ../local
219 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
219 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote namespaces
220 bookmarks
220 bookmarks
221 namespaces
221 namespaces
222 phases
222 phases
223 $ hg book foo -r 0
223 $ hg book foo -r 0
224 $ hg out -B
224 $ hg out -B
225 comparing with ssh://user@dummy/remote
225 comparing with ssh://user@dummy/remote
226 searching for changed bookmarks
226 searching for changed bookmarks
227 foo 1160648e36ce
227 foo 1160648e36ce
228 $ hg push -B foo
228 $ hg push -B foo
229 pushing to ssh://user@dummy/remote
229 pushing to ssh://user@dummy/remote
230 searching for changes
230 searching for changes
231 no changes found
231 no changes found
232 exporting bookmark foo
232 exporting bookmark foo
233 [1]
233 [1]
234 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
234 $ hg debugpushkey --config ui.ssh="python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote bookmarks
235 foo 1160648e36cec0054048a7edc4110c6f84fde594
235 foo 1160648e36cec0054048a7edc4110c6f84fde594
236 $ hg book -f foo
236 $ hg book -f foo
237 $ hg push --traceback
237 $ hg push --traceback
238 pushing to ssh://user@dummy/remote
238 pushing to ssh://user@dummy/remote
239 searching for changes
239 searching for changes
240 no changes found
240 no changes found
241 updating bookmark foo
241 updating bookmark foo
242 [1]
242 [1]
243 $ hg book -d foo
243 $ hg book -d foo
244 $ hg in -B
244 $ hg in -B
245 comparing with ssh://user@dummy/remote
245 comparing with ssh://user@dummy/remote
246 searching for changed bookmarks
246 searching for changed bookmarks
247 foo a28a9d1a809c
247 foo a28a9d1a809c
248 $ hg book -f -r 0 foo
248 $ hg book -f -r 0 foo
249 $ hg pull -B foo
249 $ hg pull -B foo
250 pulling from ssh://user@dummy/remote
250 pulling from ssh://user@dummy/remote
251 no changes found
251 no changes found
252 updating bookmark foo
252 updating bookmark foo
253 $ hg book -d foo
253 $ hg book -d foo
254 $ hg push -B foo
254 $ hg push -B foo
255 pushing to ssh://user@dummy/remote
255 pushing to ssh://user@dummy/remote
256 searching for changes
256 searching for changes
257 no changes found
257 no changes found
258 deleting remote bookmark foo
258 deleting remote bookmark foo
259 [1]
259 [1]
260
260
261 a bad, evil hook that prints to stdout
261 a bad, evil hook that prints to stdout
262
262
263 $ cat <<EOF > $TESTTMP/badhook
263 $ cat <<EOF > $TESTTMP/badhook
264 > import sys
264 > import sys
265 > sys.stdout.write("KABOOM\n")
265 > sys.stdout.write("KABOOM\n")
266 > EOF
266 > EOF
267
267
268 $ cat <<EOF > $TESTTMP/badpyhook.py
268 $ cat <<EOF > $TESTTMP/badpyhook.py
269 > import sys
269 > import sys
270 > def hook(ui, repo, hooktype, **kwargs):
270 > def hook(ui, repo, hooktype, **kwargs):
271 > sys.stdout.write("KABOOM IN PROCESS\n")
271 > sys.stdout.write("KABOOM IN PROCESS\n")
272 > EOF
272 > EOF
273
273
274 $ cat <<EOF >> ../remote/.hg/hgrc
274 $ cat <<EOF >> ../remote/.hg/hgrc
275 > [hooks]
275 > [hooks]
276 > changegroup.stdout = python $TESTTMP/badhook
276 > changegroup.stdout = python $TESTTMP/badhook
277 > changegroup.pystdout = python:$TESTTMP/badpyhook.py:hook
277 > changegroup.pystdout = python:$TESTTMP/badpyhook.py:hook
278 > EOF
278 > EOF
279 $ echo r > r
279 $ echo r > r
280 $ hg ci -A -m z r
280 $ hg ci -A -m z r
281
281
282 push should succeed even though it has an unexpected response
282 push should succeed even though it has an unexpected response
283
283
284 $ hg push
284 $ hg push
285 pushing to ssh://user@dummy/remote
285 pushing to ssh://user@dummy/remote
286 searching for changes
286 searching for changes
287 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
287 remote has heads on branch 'default' that are not known locally: 6c0482d977a3
288 remote: adding changesets
288 remote: adding changesets
289 remote: adding manifests
289 remote: adding manifests
290 remote: adding file changes
290 remote: adding file changes
291 remote: added 1 changesets with 1 changes to 1 files
291 remote: added 1 changesets with 1 changes to 1 files
292 remote: KABOOM
292 remote: KABOOM
293 remote: KABOOM IN PROCESS
293 remote: KABOOM IN PROCESS
294 $ hg -R ../remote heads
294 $ hg -R ../remote heads
295 changeset: 5:1383141674ec
295 changeset: 5:1383141674ec
296 tag: tip
296 tag: tip
297 parent: 3:a28a9d1a809c
297 parent: 3:a28a9d1a809c
298 user: test
298 user: test
299 date: Thu Jan 01 00:00:00 1970 +0000
299 date: Thu Jan 01 00:00:00 1970 +0000
300 summary: z
300 summary: z
301
301
302 changeset: 4:6c0482d977a3
302 changeset: 4:6c0482d977a3
303 parent: 0:1160648e36ce
303 parent: 0:1160648e36ce
304 user: test
304 user: test
305 date: Thu Jan 01 00:00:00 1970 +0000
305 date: Thu Jan 01 00:00:00 1970 +0000
306 summary: z
306 summary: z
307
307
308
308
309 clone bookmarks
309 clone bookmarks
310
310
311 $ hg -R ../remote bookmark test
311 $ hg -R ../remote bookmark test
312 $ hg -R ../remote bookmarks
312 $ hg -R ../remote bookmarks
313 * test 4:6c0482d977a3
313 * test 4:6c0482d977a3
314 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
314 $ hg clone -e "python \"$TESTDIR/dummyssh\"" ssh://user@dummy/remote local-bookmarks
315 requesting all changes
315 requesting all changes
316 adding changesets
316 adding changesets
317 adding manifests
317 adding manifests
318 adding file changes
318 adding file changes
319 added 6 changesets with 5 changes to 4 files (+1 heads)
319 added 6 changesets with 5 changes to 4 files (+1 heads)
320 updating to branch default
320 updating to branch default
321 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
321 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 $ hg -R local-bookmarks bookmarks
322 $ hg -R local-bookmarks bookmarks
323 test 4:6c0482d977a3
323 test 4:6c0482d977a3
324
324
325 passwords in ssh urls are not supported
325 passwords in ssh urls are not supported
326 (we use a glob here because different Python versions give different
326 (we use a glob here because different Python versions give different
327 results here)
327 results here)
328
328
329 $ hg push ssh://user:erroneouspwd@dummy/remote
329 $ hg push ssh://user:erroneouspwd@dummy/remote
330 pushing to ssh://user:*@dummy/remote (glob)
330 pushing to ssh://user:*@dummy/remote (glob)
331 abort: password in URL not supported!
331 abort: password in URL not supported!
332 [255]
332 [255]
333
333
334 $ cd ..
334 $ cd ..
335
335
336 hide outer repo
336 hide outer repo
337 $ hg init
337 $ hg init
338
338
339 Test remote paths with spaces (issue2983):
339 Test remote paths with spaces (issue2983):
340
340
341 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
341 $ hg init --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
342 $ touch "$TESTTMP/a repo/test"
342 $ touch "$TESTTMP/a repo/test"
343 $ hg -R 'a repo' commit -A -m "test"
343 $ hg -R 'a repo' commit -A -m "test"
344 adding test
344 adding test
345 $ hg -R 'a repo' tag tag
345 $ hg -R 'a repo' tag tag
346 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
346 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
347 73649e48688a
347 73649e48688a
348
348
349 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
349 $ hg id --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo#noNoNO"
350 abort: unknown revision 'noNoNO'!
350 abort: unknown revision 'noNoNO'!
351 [255]
351 [255]
352
352
353 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
353 Test (non-)escaping of remote paths with spaces when cloning (issue3145):
354
354
355 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
355 $ hg clone --ssh "python \"$TESTDIR/dummyssh\"" "ssh://user@dummy/a repo"
356 destination directory: a repo
356 destination directory: a repo
357 abort: destination 'a repo' is not empty
357 abort: destination 'a repo' is not empty
358 [255]
358 [255]
359
359
360 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
360 Test hg-ssh using a helper script that will restore PYTHONPATH (which might
361 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
361 have been cleared by a hg.exe wrapper) and invoke hg-ssh with the right
362 parameters:
362 parameters:
363
363
364 $ cat > ssh.sh << EOF
364 $ cat > ssh.sh << EOF
365 > userhost="\$1"
365 > userhost="\$1"
366 > SSH_ORIGINAL_COMMAND="\$2"
366 > SSH_ORIGINAL_COMMAND="\$2"
367 > export SSH_ORIGINAL_COMMAND
367 > export SSH_ORIGINAL_COMMAND
368 > PYTHONPATH="$PYTHONPATH"
368 > PYTHONPATH="$PYTHONPATH"
369 > export PYTHONPATH
369 > export PYTHONPATH
370 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
370 > python "$TESTDIR/../contrib/hg-ssh" "$TESTTMP/a repo"
371 > EOF
371 > EOF
372
372
373 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
373 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a repo"
374 73649e48688a
374 73649e48688a
375
375
376 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
376 $ hg id --ssh "sh ssh.sh" "ssh://user@dummy/a'repo"
377 remote: Illegal repository "$TESTTMP/a'repo" (glob)
377 remote: Illegal repository "$TESTTMP/a'repo" (glob)
378 abort: no suitable response from remote hg!
378 abort: no suitable response from remote hg!
379 [255]
379 [255]
380
380
381 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
381 $ hg id --ssh "sh ssh.sh" --remotecmd hacking "ssh://user@dummy/a'repo"
382 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
382 remote: Illegal command "hacking -R 'a'\''repo' serve --stdio"
383 abort: no suitable response from remote hg!
383 abort: no suitable response from remote hg!
384 [255]
384 [255]
385
385
386 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
386 $ SSH_ORIGINAL_COMMAND="'hg' -R 'a'repo' serve --stdio" python "$TESTDIR/../contrib/hg-ssh"
387 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
387 Illegal command "'hg' -R 'a'repo' serve --stdio": No closing quotation
388 [255]
388 [255]
389
389
390 Test hg-ssh in read-only mode:
390 Test hg-ssh in read-only mode:
391
391
392 $ cat > ssh.sh << EOF
392 $ cat > ssh.sh << EOF
393 > userhost="\$1"
393 > userhost="\$1"
394 > SSH_ORIGINAL_COMMAND="\$2"
394 > SSH_ORIGINAL_COMMAND="\$2"
395 > export SSH_ORIGINAL_COMMAND
395 > export SSH_ORIGINAL_COMMAND
396 > PYTHONPATH="$PYTHONPATH"
396 > PYTHONPATH="$PYTHONPATH"
397 > export PYTHONPATH
397 > export PYTHONPATH
398 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
398 > python "$TESTDIR/../contrib/hg-ssh" --read-only "$TESTTMP/remote"
399 > EOF
399 > EOF
400
400
401 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
401 $ hg clone --ssh "sh ssh.sh" "ssh://user@dummy/$TESTTMP/remote" read-only-local
402 requesting all changes
402 requesting all changes
403 adding changesets
403 adding changesets
404 adding manifests
404 adding manifests
405 adding file changes
405 adding file changes
406 added 6 changesets with 5 changes to 4 files (+1 heads)
406 added 6 changesets with 5 changes to 4 files (+1 heads)
407 updating to branch default
407 updating to branch default
408 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
408 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
409
409
410 $ cd read-only-local
410 $ cd read-only-local
411 $ echo "baz" > bar
411 $ echo "baz" > bar
412 $ hg ci -A -m "unpushable commit" bar
412 $ hg ci -A -m "unpushable commit" bar
413 $ hg push --ssh "sh ../ssh.sh"
413 $ hg push --ssh "sh ../ssh.sh"
414 pushing to ssh://user@dummy/*/remote (glob)
414 pushing to ssh://user@dummy/*/remote (glob)
415 searching for changes
415 searching for changes
416 remote: Permission denied
416 remote: Permission denied
417 remote: pretxnopen.hg-ssh hook failed
417 remote: pretxnopen.hg-ssh hook failed
418 abort: push failed on remote
418 abort: push failed on remote
419 [255]
419 [255]
420
420
421 $ cd ..
421 $ cd ..
422
422
423 stderr from remote commands should be printed before stdout from local code (issue4336)
423 stderr from remote commands should be printed before stdout from local code (issue4336)
424
424
425 $ hg clone remote stderr-ordering
425 $ hg clone remote stderr-ordering
426 updating to branch default
426 updating to branch default
427 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
427 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
428 $ cd stderr-ordering
428 $ cd stderr-ordering
429 $ cat >> localwrite.py << EOF
429 $ cat >> localwrite.py << EOF
430 > from mercurial import exchange, extensions
430 > from mercurial import exchange, extensions
431 >
431 >
432 > def wrappedpush(orig, repo, *args, **kwargs):
432 > def wrappedpush(orig, repo, *args, **kwargs):
433 > res = orig(repo, *args, **kwargs)
433 > res = orig(repo, *args, **kwargs)
434 > repo.ui.write('local stdout\n')
434 > repo.ui.write('local stdout\n')
435 > return res
435 > return res
436 >
436 >
437 > def extsetup(ui):
437 > def extsetup(ui):
438 > extensions.wrapfunction(exchange, 'push', wrappedpush)
438 > extensions.wrapfunction(exchange, 'push', wrappedpush)
439 > EOF
439 > EOF
440
440
441 $ cat >> .hg/hgrc << EOF
441 $ cat >> .hg/hgrc << EOF
442 > [paths]
442 > [paths]
443 > default-push = ssh://user@dummy/remote
443 > default-push = ssh://user@dummy/remote
444 > [ui]
444 > [ui]
445 > ssh = python "$TESTDIR/dummyssh"
445 > ssh = python "$TESTDIR/dummyssh"
446 > [extensions]
446 > [extensions]
447 > localwrite = localwrite.py
447 > localwrite = localwrite.py
448 > EOF
448 > EOF
449
449
450 $ echo localwrite > foo
450 $ echo localwrite > foo
451 $ hg commit -m 'testing localwrite'
451 $ hg commit -m 'testing localwrite'
452 $ hg push
452 $ hg push
453 pushing to ssh://user@dummy/remote
453 pushing to ssh://user@dummy/remote
454 searching for changes
454 searching for changes
455 remote: adding changesets
455 remote: adding changesets
456 remote: adding manifests
456 remote: adding manifests
457 remote: adding file changes
457 remote: adding file changes
458 remote: added 1 changesets with 1 changes to 1 files
458 remote: added 1 changesets with 1 changes to 1 files
459 remote: KABOOM
459 remote: KABOOM
460 remote: KABOOM IN PROCESS
460 remote: KABOOM IN PROCESS
461 local stdout
461 local stdout
462
462
463 debug output
463 debug output
464
464
465 $ hg pull --debug ssh://user@dummy/remote
465 $ hg pull --debug ssh://user@dummy/remote
466 pulling from ssh://user@dummy/remote
466 pulling from ssh://user@dummy/remote
467 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
467 running python ".*/dummyssh" user@dummy ('|")hg -R remote serve --stdio('|") (re)
468 sending hello command
468 sending hello command
469 sending between command
469 sending between command
470 remote: 355
470 remote: 355
471 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN
471 remote: capabilities: lookup changegroupsubset branchmap pushkey known getbundle unbundlehash batch streamreqs=generaldelta,revlogv1 bundle2=HG20%0Achangegroup%3D01%2C02%0Adigests%3Dmd5%2Csha1%2Csha512%0Aerror%3Dabort%2Cunsupportedcontent%2Cpushraced%2Cpushkey%0Ahgtagsfnodes%0Alistkeys%0Apushkey%0Aremote-changegroup%3Dhttp%2Chttps unbundle=HG10GZ,HG10BZ,HG10UN
472 remote: 1
472 remote: 1
473 query 1; heads
473 query 1; heads
474 sending batch command
474 sending batch command
475 searching for changes
475 searching for changes
476 all remote heads known locally
476 all remote heads known locally
477 no changes found
477 no changes found
478 sending getbundle command
478 sending getbundle command
479 bundle2-input-bundle: with-transaction
479 bundle2-input-bundle: with-transaction
480 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
480 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
481 bundle2-input-part: total payload size 15
481 bundle2-input-part: total payload size 15
482 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
482 bundle2-input-part: "listkeys" (params: 1 mandatory) supported
483 bundle2-input-part: total payload size 45
483 bundle2-input-part: total payload size 45
484 bundle2-input-bundle: 1 parts total
484 bundle2-input-bundle: 1 parts total
485 checking for updated bookmarks
485 checking for updated bookmarks
486
486
487 $ cd ..
487 $ cd ..
488
488
489 $ cat dummylog
489 $ cat dummylog
490 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
490 Got arguments 1:user@dummy 2:hg -R nonexistent serve --stdio
491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
491 Got arguments 1:user@dummy 2:hg -R $TESTTMP/nonexistent serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
492 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
493 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
493 Got arguments 1:user@dummy 2:hg -R local-stream serve --stdio
494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
494 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
495 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
496 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
496 Got arguments 1:user@dummy 2:hg -R doesnotexist serve --stdio
497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
497 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
498 Got arguments 1:user@dummy 2:hg -R local serve --stdio
498 Got arguments 1:user@dummy 2:hg -R local serve --stdio
499 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
499 Got arguments 1:user@dummy 2:hg -R $TESTTMP/local serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
500 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
501 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
501 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_NODE_LAST=a28a9d1a809cab7d4e2fde4bee738a9ede948b60 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
502 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
503 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
504 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
505 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
506 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
506 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
507 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
507 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
508 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
509 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
509 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
510 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
511 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
511 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=1383141674ec756a6056f6a9097618482fe0f4a6 HG_NODE_LAST=1383141674ec756a6056f6a9097618482fe0f4a6 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
512 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
513 Got arguments 1:user@dummy 2:hg init 'a repo'
513 Got arguments 1:user@dummy 2:hg init 'a repo'
514 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
514 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
515 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
515 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
516 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
516 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
517 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
517 Got arguments 1:user@dummy 2:hg -R 'a repo' serve --stdio
518 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
518 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
519 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:* HG_URL=remote:ssh:$LOCALIP (glob)
519 changegroup-in-remote hook: HG_BUNDLE2=1 HG_NODE=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_NODE_LAST=65c38f4125f9602c8db4af56530cc221d93b8ef8 HG_SOURCE=serve HG_TXNID=TXN:$ID$ HG_URL=remote:ssh:$LOCALIP
520 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
520 Got arguments 1:user@dummy 2:hg -R remote serve --stdio
521
521
522 remote hook failure is attributed to remote
522 remote hook failure is attributed to remote
523
523
524 $ cat > $TESTTMP/failhook << EOF
524 $ cat > $TESTTMP/failhook << EOF
525 > def hook(ui, repo, **kwargs):
525 > def hook(ui, repo, **kwargs):
526 > ui.write('hook failure!\n')
526 > ui.write('hook failure!\n')
527 > ui.flush()
527 > ui.flush()
528 > return 1
528 > return 1
529 > EOF
529 > EOF
530
530
531 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
531 $ echo "pretxnchangegroup.fail = python:$TESTTMP/failhook:hook" >> remote/.hg/hgrc
532
532
533 $ hg -q --config ui.ssh="python $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
533 $ hg -q --config ui.ssh="python $TESTDIR/dummyssh" clone ssh://user@dummy/remote hookout
534 $ cd hookout
534 $ cd hookout
535 $ touch hookfailure
535 $ touch hookfailure
536 $ hg -q commit -A -m 'remote hook failure'
536 $ hg -q commit -A -m 'remote hook failure'
537 $ hg --config ui.ssh="python $TESTDIR/dummyssh" push
537 $ hg --config ui.ssh="python $TESTDIR/dummyssh" push
538 pushing to ssh://user@dummy/remote
538 pushing to ssh://user@dummy/remote
539 searching for changes
539 searching for changes
540 remote: adding changesets
540 remote: adding changesets
541 remote: adding manifests
541 remote: adding manifests
542 remote: adding file changes
542 remote: adding file changes
543 remote: added 1 changesets with 1 changes to 1 files
543 remote: added 1 changesets with 1 changes to 1 files
544 remote: hook failure!
544 remote: hook failure!
545 remote: transaction abort!
545 remote: transaction abort!
546 remote: rollback completed
546 remote: rollback completed
547 remote: pretxnchangegroup.fail hook failed
547 remote: pretxnchangegroup.fail hook failed
548 abort: push failed on remote
548 abort: push failed on remote
549 [255]
549 [255]
550
550
551 abort during pull is properly reported as such
551 abort during pull is properly reported as such
552
552
553 $ echo morefoo >> ../remote/foo
553 $ echo morefoo >> ../remote/foo
554 $ hg -R ../remote commit --message "more foo to be pulled"
554 $ hg -R ../remote commit --message "more foo to be pulled"
555 $ cat >> ../remote/.hg/hgrc << EOF
555 $ cat >> ../remote/.hg/hgrc << EOF
556 > [extensions]
556 > [extensions]
557 > crash = ${TESTDIR}/crashgetbundler.py
557 > crash = ${TESTDIR}/crashgetbundler.py
558 > EOF
558 > EOF
559 $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
559 $ hg --config ui.ssh="python $TESTDIR/dummyssh" pull
560 pulling from ssh://user@dummy/remote
560 pulling from ssh://user@dummy/remote
561 searching for changes
561 searching for changes
562 remote: abort: this is an exercise
562 remote: abort: this is an exercise
563 abort: pull failed on remote
563 abort: pull failed on remote
564 [255]
564 [255]
@@ -1,159 +1,159 b''
1 #require killdaemons
1 #require killdaemons
2
2
3 $ hg clone http://localhost:$HGPORT/ copy
3 $ hg clone http://localhost:$HGPORT/ copy
4 abort: * (glob)
4 abort: * (glob)
5 [255]
5 [255]
6 $ test -d copy
6 $ test -d copy
7 [1]
7 [1]
8
8
9 This server doesn't do range requests so it's basically only good for
9 This server doesn't do range requests so it's basically only good for
10 one pull
10 one pull
11
11
12 $ python "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
12 $ python "$TESTDIR/dumbhttp.py" -p $HGPORT --pid dumb.pid
13 $ cat dumb.pid >> $DAEMON_PIDS
13 $ cat dumb.pid >> $DAEMON_PIDS
14 $ hg init remote
14 $ hg init remote
15 $ cd remote
15 $ cd remote
16 $ echo foo > bar
16 $ echo foo > bar
17 $ echo c2 > '.dotfile with spaces'
17 $ echo c2 > '.dotfile with spaces'
18 $ hg add
18 $ hg add
19 adding .dotfile with spaces
19 adding .dotfile with spaces
20 adding bar
20 adding bar
21 $ hg commit -m"test"
21 $ hg commit -m"test"
22 $ hg tip
22 $ hg tip
23 changeset: 0:02770d679fb8
23 changeset: 0:02770d679fb8
24 tag: tip
24 tag: tip
25 user: test
25 user: test
26 date: Thu Jan 01 00:00:00 1970 +0000
26 date: Thu Jan 01 00:00:00 1970 +0000
27 summary: test
27 summary: test
28
28
29 $ cd ..
29 $ cd ..
30 $ hg clone static-http://localhost:$HGPORT/remote local
30 $ hg clone static-http://localhost:$HGPORT/remote local
31 requesting all changes
31 requesting all changes
32 adding changesets
32 adding changesets
33 adding manifests
33 adding manifests
34 adding file changes
34 adding file changes
35 added 1 changesets with 2 changes to 2 files
35 added 1 changesets with 2 changes to 2 files
36 updating to branch default
36 updating to branch default
37 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
37 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
38 $ cd local
38 $ cd local
39 $ hg verify
39 $ hg verify
40 checking changesets
40 checking changesets
41 checking manifests
41 checking manifests
42 crosschecking files in changesets and manifests
42 crosschecking files in changesets and manifests
43 checking files
43 checking files
44 2 files, 1 changesets, 2 total revisions
44 2 files, 1 changesets, 2 total revisions
45 $ cat bar
45 $ cat bar
46 foo
46 foo
47 $ cd ../remote
47 $ cd ../remote
48 $ echo baz > quux
48 $ echo baz > quux
49 $ hg commit -A -mtest2
49 $ hg commit -A -mtest2
50 adding quux
50 adding quux
51
51
52 check for HTTP opener failures when cachefile does not exist
52 check for HTTP opener failures when cachefile does not exist
53
53
54 $ rm .hg/cache/*
54 $ rm .hg/cache/*
55 $ cd ../local
55 $ cd ../local
56 $ cat >> .hg/hgrc <<EOF
56 $ cat >> .hg/hgrc <<EOF
57 > [hooks]
57 > [hooks]
58 > changegroup = sh -c "printenv.py changegroup"
58 > changegroup = sh -c "printenv.py changegroup"
59 > EOF
59 > EOF
60 $ hg pull
60 $ hg pull
61 pulling from static-http://localhost:$HGPORT/remote
61 pulling from static-http://localhost:$HGPORT/remote
62 searching for changes
62 searching for changes
63 adding changesets
63 adding changesets
64 adding manifests
64 adding manifests
65 adding file changes
65 adding file changes
66 added 1 changesets with 1 changes to 1 files
66 added 1 changesets with 1 changes to 1 files
67 changegroup hook: HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_NODE_LAST=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_SOURCE=pull HG_TXNID=TXN:* HG_URL=http://localhost:$HGPORT/remote (glob)
67 changegroup hook: HG_NODE=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_NODE_LAST=4ac2e3648604439c580c69b09ec9d93a88d93432 HG_SOURCE=pull HG_TXNID=TXN:$ID$ HG_URL=http://localhost:$HGPORT/remote
68 (run 'hg update' to get a working copy)
68 (run 'hg update' to get a working copy)
69
69
70 trying to push
70 trying to push
71
71
72 $ hg update
72 $ hg update
73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
73 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
74 $ echo more foo >> bar
74 $ echo more foo >> bar
75 $ hg commit -m"test"
75 $ hg commit -m"test"
76 $ hg push
76 $ hg push
77 pushing to static-http://localhost:$HGPORT/remote
77 pushing to static-http://localhost:$HGPORT/remote
78 abort: destination does not support push
78 abort: destination does not support push
79 [255]
79 [255]
80
80
81 trying clone -r
81 trying clone -r
82
82
83 $ cd ..
83 $ cd ..
84 $ hg clone -r doesnotexist static-http://localhost:$HGPORT/remote local0
84 $ hg clone -r doesnotexist static-http://localhost:$HGPORT/remote local0
85 abort: unknown revision 'doesnotexist'!
85 abort: unknown revision 'doesnotexist'!
86 [255]
86 [255]
87 $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
87 $ hg clone -r 0 static-http://localhost:$HGPORT/remote local0
88 adding changesets
88 adding changesets
89 adding manifests
89 adding manifests
90 adding file changes
90 adding file changes
91 added 1 changesets with 2 changes to 2 files
91 added 1 changesets with 2 changes to 2 files
92 updating to branch default
92 updating to branch default
93 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
93 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
94
94
95 test with "/" URI (issue747) and subrepo
95 test with "/" URI (issue747) and subrepo
96
96
97 $ hg init
97 $ hg init
98 $ hg init sub
98 $ hg init sub
99 $ touch sub/test
99 $ touch sub/test
100 $ hg -R sub commit -A -m "test"
100 $ hg -R sub commit -A -m "test"
101 adding test
101 adding test
102 $ hg -R sub tag not-empty
102 $ hg -R sub tag not-empty
103 $ echo sub=sub > .hgsub
103 $ echo sub=sub > .hgsub
104 $ echo a > a
104 $ echo a > a
105 $ hg add a .hgsub
105 $ hg add a .hgsub
106 $ hg -q ci -ma
106 $ hg -q ci -ma
107 $ hg clone static-http://localhost:$HGPORT/ local2
107 $ hg clone static-http://localhost:$HGPORT/ local2
108 requesting all changes
108 requesting all changes
109 adding changesets
109 adding changesets
110 adding manifests
110 adding manifests
111 adding file changes
111 adding file changes
112 added 1 changesets with 3 changes to 3 files
112 added 1 changesets with 3 changes to 3 files
113 updating to branch default
113 updating to branch default
114 cloning subrepo sub from static-http://localhost:$HGPORT/sub
114 cloning subrepo sub from static-http://localhost:$HGPORT/sub
115 requesting all changes
115 requesting all changes
116 adding changesets
116 adding changesets
117 adding manifests
117 adding manifests
118 adding file changes
118 adding file changes
119 added 2 changesets with 2 changes to 2 files
119 added 2 changesets with 2 changes to 2 files
120 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
120 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 $ cd local2
121 $ cd local2
122 $ hg verify
122 $ hg verify
123 checking changesets
123 checking changesets
124 checking manifests
124 checking manifests
125 crosschecking files in changesets and manifests
125 crosschecking files in changesets and manifests
126 checking files
126 checking files
127 3 files, 1 changesets, 3 total revisions
127 3 files, 1 changesets, 3 total revisions
128 checking subrepo links
128 checking subrepo links
129 $ cat a
129 $ cat a
130 a
130 a
131 $ hg paths
131 $ hg paths
132 default = static-http://localhost:$HGPORT/
132 default = static-http://localhost:$HGPORT/
133
133
134 test with empty repo (issue965)
134 test with empty repo (issue965)
135
135
136 $ cd ..
136 $ cd ..
137 $ hg init remotempty
137 $ hg init remotempty
138 $ hg clone static-http://localhost:$HGPORT/remotempty local3
138 $ hg clone static-http://localhost:$HGPORT/remotempty local3
139 no changes found
139 no changes found
140 updating to branch default
140 updating to branch default
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
141 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 $ cd local3
142 $ cd local3
143 $ hg verify
143 $ hg verify
144 checking changesets
144 checking changesets
145 checking manifests
145 checking manifests
146 crosschecking files in changesets and manifests
146 crosschecking files in changesets and manifests
147 checking files
147 checking files
148 0 files, 0 changesets, 0 total revisions
148 0 files, 0 changesets, 0 total revisions
149 $ hg paths
149 $ hg paths
150 default = static-http://localhost:$HGPORT/remotempty
150 default = static-http://localhost:$HGPORT/remotempty
151
151
152 test with non-repo
152 test with non-repo
153
153
154 $ cd ..
154 $ cd ..
155 $ mkdir notarepo
155 $ mkdir notarepo
156 $ hg clone static-http://localhost:$HGPORT/notarepo local3
156 $ hg clone static-http://localhost:$HGPORT/notarepo local3
157 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
157 abort: 'http://localhost:$HGPORT/notarepo' does not appear to be an hg repository!
158 [255]
158 [255]
159 $ killdaemons.py
159 $ killdaemons.py
General Comments 0
You need to be logged in to leave comments. Login now