##// END OF EJS Templates
test: replace a many occurence of `python` with `$PYTHON`...
marmoute -
r46843:0826d684 default
parent child Browse files
Show More
@@ -1,49 +1,49 b''
1 scratchnodes() {
1 scratchnodes() {
2 for node in `find ../repo/.hg/scratchbranches/index/nodemap/* | sort`; do
2 for node in `find ../repo/.hg/scratchbranches/index/nodemap/* | sort`; do
3 echo ${node##*/} `cat $node`
3 echo ${node##*/} `cat $node`
4 done
4 done
5 }
5 }
6
6
7 scratchbookmarks() {
7 scratchbookmarks() {
8 for bookmark in `find ../repo/.hg/scratchbranches/index/bookmarkmap/* -type f | sort`; do
8 for bookmark in `find ../repo/.hg/scratchbranches/index/bookmarkmap/* -type f | sort`; do
9 echo "${bookmark##*/bookmarkmap/} `cat $bookmark`"
9 echo "${bookmark##*/bookmarkmap/} `cat $bookmark`"
10 done
10 done
11 }
11 }
12
12
13 setupcommon() {
13 setupcommon() {
14 cat >> $HGRCPATH << EOF
14 cat >> $HGRCPATH << EOF
15 [extensions]
15 [extensions]
16 infinitepush=
16 infinitepush=
17 [ui]
17 [ui]
18 ssh = python "$TESTDIR/dummyssh"
18 ssh = $PYTHON "$TESTDIR/dummyssh"
19 [infinitepush]
19 [infinitepush]
20 branchpattern=re:scratch/.*
20 branchpattern=re:scratch/.*
21 EOF
21 EOF
22 }
22 }
23
23
24 setupserver() {
24 setupserver() {
25 cat >> .hg/hgrc << EOF
25 cat >> .hg/hgrc << EOF
26 [infinitepush]
26 [infinitepush]
27 server=yes
27 server=yes
28 indextype=disk
28 indextype=disk
29 storetype=disk
29 storetype=disk
30 reponame=babar
30 reponame=babar
31 EOF
31 EOF
32 }
32 }
33
33
34 waitbgbackup() {
34 waitbgbackup() {
35 sleep 1
35 sleep 1
36 hg debugwaitbackup
36 hg debugwaitbackup
37 }
37 }
38
38
39 mkcommitautobackup() {
39 mkcommitautobackup() {
40 echo $1 > $1
40 echo $1 > $1
41 hg add $1
41 hg add $1
42 hg ci -m $1 --config infinitepushbackup.autobackup=True
42 hg ci -m $1 --config infinitepushbackup.autobackup=True
43 }
43 }
44
44
45 setuplogdir() {
45 setuplogdir() {
46 mkdir $TESTTMP/logs
46 mkdir $TESTTMP/logs
47 chmod 0755 $TESTTMP/logs
47 chmod 0755 $TESTTMP/logs
48 chmod +t $TESTTMP/logs
48 chmod +t $TESTTMP/logs
49 }
49 }
@@ -1,75 +1,75 b''
1 CACHEDIR=$PWD/hgcache
1 CACHEDIR=$PWD/hgcache
2 cat >> $HGRCPATH <<EOF
2 cat >> $HGRCPATH <<EOF
3 [remotefilelog]
3 [remotefilelog]
4 cachepath=$CACHEDIR
4 cachepath=$CACHEDIR
5 debug=True
5 debug=True
6 [extensions]
6 [extensions]
7 remotefilelog=
7 remotefilelog=
8 rebase=
8 rebase=
9 strip=
9 strip=
10 [ui]
10 [ui]
11 ssh=python "$TESTDIR/dummyssh"
11 ssh=$PYTHON "$TESTDIR/dummyssh"
12 [server]
12 [server]
13 preferuncompressed=True
13 preferuncompressed=True
14 [experimental]
14 [experimental]
15 changegroup3=True
15 changegroup3=True
16 [rebase]
16 [rebase]
17 singletransaction=True
17 singletransaction=True
18 EOF
18 EOF
19
19
20 hgcloneshallow() {
20 hgcloneshallow() {
21 local name
21 local name
22 local dest
22 local dest
23 orig=$1
23 orig=$1
24 shift
24 shift
25 dest=$1
25 dest=$1
26 shift
26 shift
27 hg clone --shallow --config remotefilelog.reponame=master $orig $dest $@
27 hg clone --shallow --config remotefilelog.reponame=master $orig $dest $@
28 cat >> $dest/.hg/hgrc <<EOF
28 cat >> $dest/.hg/hgrc <<EOF
29 [remotefilelog]
29 [remotefilelog]
30 reponame=master
30 reponame=master
31 [phases]
31 [phases]
32 publish=False
32 publish=False
33 EOF
33 EOF
34 }
34 }
35
35
36 hgcloneshallowlfs() {
36 hgcloneshallowlfs() {
37 local name
37 local name
38 local dest
38 local dest
39 local lfsdir
39 local lfsdir
40 orig=$1
40 orig=$1
41 shift
41 shift
42 dest=$1
42 dest=$1
43 shift
43 shift
44 lfsdir=$1
44 lfsdir=$1
45 shift
45 shift
46 hg clone --shallow --config "extensions.lfs=" --config "lfs.url=$lfsdir" --config remotefilelog.reponame=master $orig $dest $@
46 hg clone --shallow --config "extensions.lfs=" --config "lfs.url=$lfsdir" --config remotefilelog.reponame=master $orig $dest $@
47 cat >> $dest/.hg/hgrc <<EOF
47 cat >> $dest/.hg/hgrc <<EOF
48 [extensions]
48 [extensions]
49 lfs=
49 lfs=
50 [lfs]
50 [lfs]
51 url=$lfsdir
51 url=$lfsdir
52 [remotefilelog]
52 [remotefilelog]
53 reponame=master
53 reponame=master
54 [phases]
54 [phases]
55 publish=False
55 publish=False
56 EOF
56 EOF
57 }
57 }
58
58
59 clearcache() {
59 clearcache() {
60 rm -rf $CACHEDIR/*
60 rm -rf $CACHEDIR/*
61 }
61 }
62
62
63 mkcommit() {
63 mkcommit() {
64 echo "$1" > "$1"
64 echo "$1" > "$1"
65 hg add "$1"
65 hg add "$1"
66 hg ci -m "$1"
66 hg ci -m "$1"
67 }
67 }
68
68
69 ls_l() {
69 ls_l() {
70 $PYTHON $TESTDIR/ls-l.py "$@"
70 $PYTHON $TESTDIR/ls-l.py "$@"
71 }
71 }
72
72
73 identifyrflcaps() {
73 identifyrflcaps() {
74 xargs -n 1 echo | egrep '(remotefilelog|getflogheads|getfile)' | sort
74 xargs -n 1 echo | egrep '(remotefilelog|getflogheads|getfile)' | sort
75 }
75 }
@@ -1,238 +1,238 b''
1 from __future__ import absolute_import, print_function
1 from __future__ import absolute_import, print_function
2
2
3 from mercurial import demandimport
3 from mercurial import demandimport
4
4
5 demandimport.enable()
5 demandimport.enable()
6
6
7 import os
7 import os
8 import subprocess
8 import subprocess
9 import sys
9 import sys
10 import types
10 import types
11
11
12 # Don't import pycompat because it has too many side-effects.
12 # Don't import pycompat because it has too many side-effects.
13 ispy3 = sys.version_info[0] >= 3
13 ispy3 = sys.version_info[0] >= 3
14
14
15 # Only run if demandimport is allowed
15 # Only run if demandimport is allowed
16 if subprocess.call(
16 if subprocess.call(
17 ['python', '%s/hghave' % os.environ['TESTDIR'], 'demandimport']
17 [os.environ['PYTHON'], '%s/hghave' % os.environ['TESTDIR'], 'demandimport']
18 ):
18 ):
19 sys.exit(80)
19 sys.exit(80)
20
20
21 # We rely on assert, which gets optimized out.
21 # We rely on assert, which gets optimized out.
22 if sys.flags.optimize:
22 if sys.flags.optimize:
23 sys.exit(80)
23 sys.exit(80)
24
24
25 # The demand importer doesn't work on Python 3.5.
25 # The demand importer doesn't work on Python 3.5.
26 if sys.version_info[0:2] == (3, 5):
26 if sys.version_info[0:2] == (3, 5):
27 sys.exit(80)
27 sys.exit(80)
28
28
29 if ispy3:
29 if ispy3:
30 from importlib.util import _LazyModule
30 from importlib.util import _LazyModule
31
31
32 try:
32 try:
33 from importlib.util import _Module as moduletype
33 from importlib.util import _Module as moduletype
34 except ImportError:
34 except ImportError:
35 moduletype = types.ModuleType
35 moduletype = types.ModuleType
36 else:
36 else:
37 moduletype = types.ModuleType
37 moduletype = types.ModuleType
38
38
39 if os.name != 'nt':
39 if os.name != 'nt':
40 try:
40 try:
41 import distutils.msvc9compiler
41 import distutils.msvc9compiler
42
42
43 print(
43 print(
44 'distutils.msvc9compiler needs to be an immediate '
44 'distutils.msvc9compiler needs to be an immediate '
45 'importerror on non-windows platforms'
45 'importerror on non-windows platforms'
46 )
46 )
47 distutils.msvc9compiler
47 distutils.msvc9compiler
48 except ImportError:
48 except ImportError:
49 pass
49 pass
50
50
51 import re
51 import re
52
52
53 rsub = re.sub
53 rsub = re.sub
54
54
55
55
56 def f(obj):
56 def f(obj):
57 l = repr(obj)
57 l = repr(obj)
58 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
58 l = rsub("0x[0-9a-fA-F]+", "0x?", l)
59 l = rsub("from '.*'", "from '?'", l)
59 l = rsub("from '.*'", "from '?'", l)
60 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
60 l = rsub("'<[a-z]*>'", "'<whatever>'", l)
61 return l
61 return l
62
62
63
63
64 demandimport.disable()
64 demandimport.disable()
65 os.environ['HGDEMANDIMPORT'] = 'disable'
65 os.environ['HGDEMANDIMPORT'] = 'disable'
66 # this enable call should not actually enable demandimport!
66 # this enable call should not actually enable demandimport!
67 demandimport.enable()
67 demandimport.enable()
68 from mercurial import node
68 from mercurial import node
69
69
70 # We use assert instead of a unittest test case because having imports inside
70 # We use assert instead of a unittest test case because having imports inside
71 # functions changes behavior of the demand importer.
71 # functions changes behavior of the demand importer.
72 if ispy3:
72 if ispy3:
73 assert not isinstance(node, _LazyModule)
73 assert not isinstance(node, _LazyModule)
74 else:
74 else:
75 assert f(node) == "<module 'mercurial.node' from '?'>", f(node)
75 assert f(node) == "<module 'mercurial.node' from '?'>", f(node)
76
76
77 # now enable it for real
77 # now enable it for real
78 del os.environ['HGDEMANDIMPORT']
78 del os.environ['HGDEMANDIMPORT']
79 demandimport.enable()
79 demandimport.enable()
80
80
81 # Test access to special attributes through demandmod proxy
81 # Test access to special attributes through demandmod proxy
82 assert 'mercurial.error' not in sys.modules
82 assert 'mercurial.error' not in sys.modules
83 from mercurial import error as errorproxy
83 from mercurial import error as errorproxy
84
84
85 if ispy3:
85 if ispy3:
86 # unsure why this isn't lazy.
86 # unsure why this isn't lazy.
87 assert not isinstance(f, _LazyModule)
87 assert not isinstance(f, _LazyModule)
88 assert f(errorproxy) == "<module 'mercurial.error' from '?'>", f(errorproxy)
88 assert f(errorproxy) == "<module 'mercurial.error' from '?'>", f(errorproxy)
89 else:
89 else:
90 assert f(errorproxy) == "<unloaded module 'error'>", f(errorproxy)
90 assert f(errorproxy) == "<unloaded module 'error'>", f(errorproxy)
91
91
92 doc = ' '.join(errorproxy.__doc__.split()[:3])
92 doc = ' '.join(errorproxy.__doc__.split()[:3])
93 assert doc == 'Mercurial exceptions. This', doc
93 assert doc == 'Mercurial exceptions. This', doc
94 assert errorproxy.__name__ == 'mercurial.error', errorproxy.__name__
94 assert errorproxy.__name__ == 'mercurial.error', errorproxy.__name__
95
95
96 # __name__ must be accessible via __dict__ so the relative imports can be
96 # __name__ must be accessible via __dict__ so the relative imports can be
97 # resolved
97 # resolved
98 name = errorproxy.__dict__['__name__']
98 name = errorproxy.__dict__['__name__']
99 assert name == 'mercurial.error', name
99 assert name == 'mercurial.error', name
100
100
101 if ispy3:
101 if ispy3:
102 assert not isinstance(errorproxy, _LazyModule)
102 assert not isinstance(errorproxy, _LazyModule)
103 assert f(errorproxy) == "<module 'mercurial.error' from '?'>", f(errorproxy)
103 assert f(errorproxy) == "<module 'mercurial.error' from '?'>", f(errorproxy)
104 else:
104 else:
105 assert f(errorproxy) == "<proxied module 'error'>", f(errorproxy)
105 assert f(errorproxy) == "<proxied module 'error'>", f(errorproxy)
106
106
107 import os
107 import os
108
108
109 if ispy3:
109 if ispy3:
110 assert not isinstance(os, _LazyModule)
110 assert not isinstance(os, _LazyModule)
111 assert f(os) == "<module 'os' from '?'>", f(os)
111 assert f(os) == "<module 'os' from '?'>", f(os)
112 else:
112 else:
113 assert f(os) == "<unloaded module 'os'>", f(os)
113 assert f(os) == "<unloaded module 'os'>", f(os)
114
114
115 assert f(os.system) == '<built-in function system>', f(os.system)
115 assert f(os.system) == '<built-in function system>', f(os.system)
116 assert f(os) == "<module 'os' from '?'>", f(os)
116 assert f(os) == "<module 'os' from '?'>", f(os)
117
117
118 assert 'mercurial.utils.procutil' not in sys.modules
118 assert 'mercurial.utils.procutil' not in sys.modules
119 from mercurial.utils import procutil
119 from mercurial.utils import procutil
120
120
121 if ispy3:
121 if ispy3:
122 assert isinstance(procutil, _LazyModule)
122 assert isinstance(procutil, _LazyModule)
123 assert f(procutil) == "<module 'mercurial.utils.procutil' from '?'>", f(
123 assert f(procutil) == "<module 'mercurial.utils.procutil' from '?'>", f(
124 procutil
124 procutil
125 )
125 )
126 else:
126 else:
127 assert f(procutil) == "<unloaded module 'procutil'>", f(procutil)
127 assert f(procutil) == "<unloaded module 'procutil'>", f(procutil)
128
128
129 assert f(procutil.system) == '<function system at 0x?>', f(procutil.system)
129 assert f(procutil.system) == '<function system at 0x?>', f(procutil.system)
130 assert procutil.__class__ == moduletype, procutil.__class__
130 assert procutil.__class__ == moduletype, procutil.__class__
131 assert f(procutil) == "<module 'mercurial.utils.procutil' from '?'>", f(
131 assert f(procutil) == "<module 'mercurial.utils.procutil' from '?'>", f(
132 procutil
132 procutil
133 )
133 )
134 assert f(procutil.system) == '<function system at 0x?>', f(procutil.system)
134 assert f(procutil.system) == '<function system at 0x?>', f(procutil.system)
135
135
136 assert 'mercurial.hgweb' not in sys.modules
136 assert 'mercurial.hgweb' not in sys.modules
137 from mercurial import hgweb
137 from mercurial import hgweb
138
138
139 if ispy3:
139 if ispy3:
140 assert isinstance(hgweb, _LazyModule)
140 assert isinstance(hgweb, _LazyModule)
141 assert f(hgweb) == "<module 'mercurial.hgweb' from '?'>", f(hgweb)
141 assert f(hgweb) == "<module 'mercurial.hgweb' from '?'>", f(hgweb)
142 assert isinstance(hgweb.hgweb_mod, _LazyModule)
142 assert isinstance(hgweb.hgweb_mod, _LazyModule)
143 assert (
143 assert (
144 f(hgweb.hgweb_mod) == "<module 'mercurial.hgweb.hgweb_mod' from '?'>"
144 f(hgweb.hgweb_mod) == "<module 'mercurial.hgweb.hgweb_mod' from '?'>"
145 ), f(hgweb.hgweb_mod)
145 ), f(hgweb.hgweb_mod)
146 else:
146 else:
147 assert f(hgweb) == "<unloaded module 'hgweb'>", f(hgweb)
147 assert f(hgweb) == "<unloaded module 'hgweb'>", f(hgweb)
148 assert f(hgweb.hgweb_mod) == "<unloaded module 'hgweb_mod'>", f(
148 assert f(hgweb.hgweb_mod) == "<unloaded module 'hgweb_mod'>", f(
149 hgweb.hgweb_mod
149 hgweb.hgweb_mod
150 )
150 )
151
151
152 assert f(hgweb) == "<module 'mercurial.hgweb' from '?'>", f(hgweb)
152 assert f(hgweb) == "<module 'mercurial.hgweb' from '?'>", f(hgweb)
153
153
154 import re as fred
154 import re as fred
155
155
156 if ispy3:
156 if ispy3:
157 assert not isinstance(fred, _LazyModule)
157 assert not isinstance(fred, _LazyModule)
158 assert f(fred) == "<module 're' from '?'>"
158 assert f(fred) == "<module 're' from '?'>"
159 else:
159 else:
160 assert f(fred) == "<unloaded module 're'>", f(fred)
160 assert f(fred) == "<unloaded module 're'>", f(fred)
161
161
162 import re as remod
162 import re as remod
163
163
164 if ispy3:
164 if ispy3:
165 assert not isinstance(remod, _LazyModule)
165 assert not isinstance(remod, _LazyModule)
166 assert f(remod) == "<module 're' from '?'>"
166 assert f(remod) == "<module 're' from '?'>"
167 else:
167 else:
168 assert f(remod) == "<unloaded module 're'>", f(remod)
168 assert f(remod) == "<unloaded module 're'>", f(remod)
169
169
170 import sys as re
170 import sys as re
171
171
172 if ispy3:
172 if ispy3:
173 assert not isinstance(re, _LazyModule)
173 assert not isinstance(re, _LazyModule)
174 assert f(re) == "<module 'sys' (built-in)>"
174 assert f(re) == "<module 'sys' (built-in)>"
175 else:
175 else:
176 assert f(re) == "<unloaded module 'sys'>", f(re)
176 assert f(re) == "<unloaded module 'sys'>", f(re)
177
177
178 if ispy3:
178 if ispy3:
179 assert not isinstance(fred, _LazyModule)
179 assert not isinstance(fred, _LazyModule)
180 assert f(fred) == "<module 're' from '?'>", f(fred)
180 assert f(fred) == "<module 're' from '?'>", f(fred)
181 else:
181 else:
182 assert f(fred) == "<unloaded module 're'>", f(fred)
182 assert f(fred) == "<unloaded module 're'>", f(fred)
183
183
184 assert f(fred.sub) == '<function sub at 0x?>', f(fred.sub)
184 assert f(fred.sub) == '<function sub at 0x?>', f(fred.sub)
185
185
186 if ispy3:
186 if ispy3:
187 assert not isinstance(fred, _LazyModule)
187 assert not isinstance(fred, _LazyModule)
188 assert f(fred) == "<module 're' from '?'>", f(fred)
188 assert f(fred) == "<module 're' from '?'>", f(fred)
189 else:
189 else:
190 assert f(fred) == "<proxied module 're'>", f(fred)
190 assert f(fred) == "<proxied module 're'>", f(fred)
191
191
192 remod.escape # use remod
192 remod.escape # use remod
193 assert f(remod) == "<module 're' from '?'>", f(remod)
193 assert f(remod) == "<module 're' from '?'>", f(remod)
194
194
195 if ispy3:
195 if ispy3:
196 assert not isinstance(re, _LazyModule)
196 assert not isinstance(re, _LazyModule)
197 assert f(re) == "<module 'sys' (built-in)>"
197 assert f(re) == "<module 'sys' (built-in)>"
198 assert f(type(re.stderr)) == "<class '_io.TextIOWrapper'>", f(
198 assert f(type(re.stderr)) == "<class '_io.TextIOWrapper'>", f(
199 type(re.stderr)
199 type(re.stderr)
200 )
200 )
201 assert f(re) == "<module 'sys' (built-in)>"
201 assert f(re) == "<module 'sys' (built-in)>"
202 else:
202 else:
203 assert f(re) == "<unloaded module 'sys'>", f(re)
203 assert f(re) == "<unloaded module 'sys'>", f(re)
204 assert f(re.stderr) == "<open file '<whatever>', mode 'w' at 0x?>", f(
204 assert f(re.stderr) == "<open file '<whatever>', mode 'w' at 0x?>", f(
205 re.stderr
205 re.stderr
206 )
206 )
207 assert f(re) == "<proxied module 'sys'>", f(re)
207 assert f(re) == "<proxied module 'sys'>", f(re)
208
208
209 assert 'telnetlib' not in sys.modules
209 assert 'telnetlib' not in sys.modules
210 import telnetlib
210 import telnetlib
211
211
212 if ispy3:
212 if ispy3:
213 assert isinstance(telnetlib, _LazyModule)
213 assert isinstance(telnetlib, _LazyModule)
214 assert f(telnetlib) == "<module 'telnetlib' from '?'>"
214 assert f(telnetlib) == "<module 'telnetlib' from '?'>"
215 else:
215 else:
216 assert f(telnetlib) == "<unloaded module 'telnetlib'>", f(telnetlib)
216 assert f(telnetlib) == "<unloaded module 'telnetlib'>", f(telnetlib)
217
217
218 try:
218 try:
219 from telnetlib import unknownattr
219 from telnetlib import unknownattr
220
220
221 assert False, (
221 assert False, (
222 'no demandmod should be created for attribute of non-package '
222 'no demandmod should be created for attribute of non-package '
223 'module:\ntelnetlib.unknownattr = %s' % f(unknownattr)
223 'module:\ntelnetlib.unknownattr = %s' % f(unknownattr)
224 )
224 )
225 except ImportError as inst:
225 except ImportError as inst:
226 assert rsub(r"'", '', str(inst)).startswith(
226 assert rsub(r"'", '', str(inst)).startswith(
227 'cannot import name unknownattr'
227 'cannot import name unknownattr'
228 )
228 )
229
229
230 from mercurial import util
230 from mercurial import util
231
231
232 # Unlike the import statement, __import__() function should not raise
232 # Unlike the import statement, __import__() function should not raise
233 # ImportError even if fromlist has an unknown item
233 # ImportError even if fromlist has an unknown item
234 # (see Python/import.c:import_module_level() and ensure_fromlist())
234 # (see Python/import.c:import_module_level() and ensure_fromlist())
235 assert 'ftplib' not in sys.modules
235 assert 'ftplib' not in sys.modules
236 zipfileimp = __import__('ftplib', globals(), locals(), ['unknownattr'])
236 zipfileimp = __import__('ftplib', globals(), locals(), ['unknownattr'])
237 assert f(zipfileimp) == "<module 'ftplib' from '?'>", f(zipfileimp)
237 assert f(zipfileimp) == "<module 'ftplib' from '?'>", f(zipfileimp)
238 assert not util.safehasattr(zipfileimp, 'unknownattr')
238 assert not util.safehasattr(zipfileimp, 'unknownattr')
@@ -1,443 +1,443 b''
1 #require no-reposimplestore
1 #require no-reposimplestore
2
2
3 Testing the case when there is no infinitepush extension present on the client
3 Testing the case when there is no infinitepush extension present on the client
4 side and the server routes each push to bundlestore. This case is very much
4 side and the server routes each push to bundlestore. This case is very much
5 similar to CI use case.
5 similar to CI use case.
6
6
7 Setup
7 Setup
8 -----
8 -----
9
9
10 $ . "$TESTDIR/library-infinitepush.sh"
10 $ . "$TESTDIR/library-infinitepush.sh"
11 $ cat >> $HGRCPATH <<EOF
11 $ cat >> $HGRCPATH <<EOF
12 > [ui]
12 > [ui]
13 > ssh = python "$TESTDIR/dummyssh"
13 > ssh = $PYTHON "$TESTDIR/dummyssh"
14 > [alias]
14 > [alias]
15 > glog = log -GT "{rev}:{node|short} {desc}\n{phase}"
15 > glog = log -GT "{rev}:{node|short} {desc}\n{phase}"
16 > EOF
16 > EOF
17 $ cp $HGRCPATH $TESTTMP/defaulthgrc
17 $ cp $HGRCPATH $TESTTMP/defaulthgrc
18 $ hg init repo
18 $ hg init repo
19 $ cd repo
19 $ cd repo
20 $ setupserver
20 $ setupserver
21 $ echo "pushtobundlestore = True" >> .hg/hgrc
21 $ echo "pushtobundlestore = True" >> .hg/hgrc
22 $ echo "[extensions]" >> .hg/hgrc
22 $ echo "[extensions]" >> .hg/hgrc
23 $ echo "infinitepush=" >> .hg/hgrc
23 $ echo "infinitepush=" >> .hg/hgrc
24 $ echo initialcommit > initialcommit
24 $ echo initialcommit > initialcommit
25 $ hg ci -Aqm "initialcommit"
25 $ hg ci -Aqm "initialcommit"
26 $ hg phase --public .
26 $ hg phase --public .
27
27
28 $ cd ..
28 $ cd ..
29 $ hg clone repo client -q
29 $ hg clone repo client -q
30 $ hg clone repo client2 -q
30 $ hg clone repo client2 -q
31 $ hg clone ssh://user@dummy/repo client3 -q
31 $ hg clone ssh://user@dummy/repo client3 -q
32 $ cd client
32 $ cd client
33
33
34 Pushing a new commit from the client to the server
34 Pushing a new commit from the client to the server
35 -----------------------------------------------------
35 -----------------------------------------------------
36
36
37 $ echo foobar > a
37 $ echo foobar > a
38 $ hg ci -Aqm "added a"
38 $ hg ci -Aqm "added a"
39 $ hg glog
39 $ hg glog
40 @ 1:6cb0989601f1 added a
40 @ 1:6cb0989601f1 added a
41 | draft
41 | draft
42 o 0:67145f466344 initialcommit
42 o 0:67145f466344 initialcommit
43 public
43 public
44
44
45 $ hg push
45 $ hg push
46 pushing to $TESTTMP/repo
46 pushing to $TESTTMP/repo
47 searching for changes
47 searching for changes
48 storing changesets on the bundlestore
48 storing changesets on the bundlestore
49 pushing 1 commit:
49 pushing 1 commit:
50 6cb0989601f1 added a
50 6cb0989601f1 added a
51
51
52 $ scratchnodes
52 $ scratchnodes
53 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
53 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
54
54
55 Understanding how data is stored on the bundlestore in server
55 Understanding how data is stored on the bundlestore in server
56 -------------------------------------------------------------
56 -------------------------------------------------------------
57
57
58 There are two things, filebundlestore and index
58 There are two things, filebundlestore and index
59 $ ls ../repo/.hg/scratchbranches
59 $ ls ../repo/.hg/scratchbranches
60 filebundlestore
60 filebundlestore
61 index
61 index
62
62
63 filebundlestore stores the bundles
63 filebundlestore stores the bundles
64 $ ls ../repo/.hg/scratchbranches/filebundlestore/3b/41/
64 $ ls ../repo/.hg/scratchbranches/filebundlestore/3b/41/
65 3b414252ff8acab801318445d88ff48faf4a28c3
65 3b414252ff8acab801318445d88ff48faf4a28c3
66
66
67 index/nodemap stores a map of node id and file in which bundle is stored in filebundlestore
67 index/nodemap stores a map of node id and file in which bundle is stored in filebundlestore
68 $ ls ../repo/.hg/scratchbranches/index/
68 $ ls ../repo/.hg/scratchbranches/index/
69 nodemap
69 nodemap
70 $ ls ../repo/.hg/scratchbranches/index/nodemap/
70 $ ls ../repo/.hg/scratchbranches/index/nodemap/
71 6cb0989601f1fb5805238edfb16f3606713d9a0b
71 6cb0989601f1fb5805238edfb16f3606713d9a0b
72
72
73 $ cd ../repo
73 $ cd ../repo
74
74
75 Checking that the commit was not applied to revlog on the server
75 Checking that the commit was not applied to revlog on the server
76 ------------------------------------------------------------------
76 ------------------------------------------------------------------
77
77
78 $ hg glog
78 $ hg glog
79 @ 0:67145f466344 initialcommit
79 @ 0:67145f466344 initialcommit
80 public
80 public
81
81
82 Applying the changeset from the bundlestore
82 Applying the changeset from the bundlestore
83 --------------------------------------------
83 --------------------------------------------
84
84
85 $ hg unbundle .hg/scratchbranches/filebundlestore/3b/41/3b414252ff8acab801318445d88ff48faf4a28c3
85 $ hg unbundle .hg/scratchbranches/filebundlestore/3b/41/3b414252ff8acab801318445d88ff48faf4a28c3
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 new changesets 6cb0989601f1
90 new changesets 6cb0989601f1
91 (run 'hg update' to get a working copy)
91 (run 'hg update' to get a working copy)
92
92
93 $ hg glog
93 $ hg glog
94 o 1:6cb0989601f1 added a
94 o 1:6cb0989601f1 added a
95 | public
95 | public
96 @ 0:67145f466344 initialcommit
96 @ 0:67145f466344 initialcommit
97 public
97 public
98
98
99 Pushing more changesets from the local repo
99 Pushing more changesets from the local repo
100 --------------------------------------------
100 --------------------------------------------
101
101
102 $ cd ../client
102 $ cd ../client
103 $ echo b > b
103 $ echo b > b
104 $ hg ci -Aqm "added b"
104 $ hg ci -Aqm "added b"
105 $ echo c > c
105 $ echo c > c
106 $ hg ci -Aqm "added c"
106 $ hg ci -Aqm "added c"
107 $ hg glog
107 $ hg glog
108 @ 3:bf8a6e3011b3 added c
108 @ 3:bf8a6e3011b3 added c
109 | draft
109 | draft
110 o 2:eaba929e866c added b
110 o 2:eaba929e866c added b
111 | draft
111 | draft
112 o 1:6cb0989601f1 added a
112 o 1:6cb0989601f1 added a
113 | public
113 | public
114 o 0:67145f466344 initialcommit
114 o 0:67145f466344 initialcommit
115 public
115 public
116
116
117 $ hg push
117 $ hg push
118 pushing to $TESTTMP/repo
118 pushing to $TESTTMP/repo
119 searching for changes
119 searching for changes
120 storing changesets on the bundlestore
120 storing changesets on the bundlestore
121 pushing 2 commits:
121 pushing 2 commits:
122 eaba929e866c added b
122 eaba929e866c added b
123 bf8a6e3011b3 added c
123 bf8a6e3011b3 added c
124
124
125 Checking that changesets are not applied on the server
125 Checking that changesets are not applied on the server
126 ------------------------------------------------------
126 ------------------------------------------------------
127
127
128 $ hg glog -R ../repo
128 $ hg glog -R ../repo
129 o 1:6cb0989601f1 added a
129 o 1:6cb0989601f1 added a
130 | public
130 | public
131 @ 0:67145f466344 initialcommit
131 @ 0:67145f466344 initialcommit
132 public
132 public
133
133
134 Both of the new changesets are stored in a single bundle-file
134 Both of the new changesets are stored in a single bundle-file
135 $ scratchnodes
135 $ scratchnodes
136 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
136 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
137 bf8a6e3011b345146bbbedbcb1ebd4837571492a 239585f5e61f0c09ce7106bdc1097bff731738f4
137 bf8a6e3011b345146bbbedbcb1ebd4837571492a 239585f5e61f0c09ce7106bdc1097bff731738f4
138 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 239585f5e61f0c09ce7106bdc1097bff731738f4
138 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 239585f5e61f0c09ce7106bdc1097bff731738f4
139
139
140 Pushing more changesets to the server
140 Pushing more changesets to the server
141 -------------------------------------
141 -------------------------------------
142
142
143 $ echo d > d
143 $ echo d > d
144 $ hg ci -Aqm "added d"
144 $ hg ci -Aqm "added d"
145 $ echo e > e
145 $ echo e > e
146 $ hg ci -Aqm "added e"
146 $ hg ci -Aqm "added e"
147
147
148 XXX: we should have pushed only the parts which are not in bundlestore
148 XXX: we should have pushed only the parts which are not in bundlestore
149 $ hg push
149 $ hg push
150 pushing to $TESTTMP/repo
150 pushing to $TESTTMP/repo
151 searching for changes
151 searching for changes
152 storing changesets on the bundlestore
152 storing changesets on the bundlestore
153 pushing 4 commits:
153 pushing 4 commits:
154 eaba929e866c added b
154 eaba929e866c added b
155 bf8a6e3011b3 added c
155 bf8a6e3011b3 added c
156 1bb96358eda2 added d
156 1bb96358eda2 added d
157 b4e4bce66051 added e
157 b4e4bce66051 added e
158
158
159 Sneak peek into the bundlestore at the server
159 Sneak peek into the bundlestore at the server
160 $ scratchnodes
160 $ scratchnodes
161 1bb96358eda285b536c6d1c66846a7cdb2336cea 98fbae0016662521b0007da1b7bc349cd3caacd1
161 1bb96358eda285b536c6d1c66846a7cdb2336cea 98fbae0016662521b0007da1b7bc349cd3caacd1
162 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
162 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
163 b4e4bce660512ad3e71189e14588a70ac8e31fef 98fbae0016662521b0007da1b7bc349cd3caacd1
163 b4e4bce660512ad3e71189e14588a70ac8e31fef 98fbae0016662521b0007da1b7bc349cd3caacd1
164 bf8a6e3011b345146bbbedbcb1ebd4837571492a 98fbae0016662521b0007da1b7bc349cd3caacd1
164 bf8a6e3011b345146bbbedbcb1ebd4837571492a 98fbae0016662521b0007da1b7bc349cd3caacd1
165 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 98fbae0016662521b0007da1b7bc349cd3caacd1
165 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 98fbae0016662521b0007da1b7bc349cd3caacd1
166
166
167 Checking if `hg pull` pulls something or `hg incoming` shows something
167 Checking if `hg pull` pulls something or `hg incoming` shows something
168 -----------------------------------------------------------------------
168 -----------------------------------------------------------------------
169
169
170 $ hg incoming
170 $ hg incoming
171 comparing with $TESTTMP/repo
171 comparing with $TESTTMP/repo
172 searching for changes
172 searching for changes
173 no changes found
173 no changes found
174 [1]
174 [1]
175
175
176 $ hg pull
176 $ hg pull
177 pulling from $TESTTMP/repo
177 pulling from $TESTTMP/repo
178 searching for changes
178 searching for changes
179 no changes found
179 no changes found
180
180
181 Pulling from second client which is a localpeer to test `hg pull -r <rev>`
181 Pulling from second client which is a localpeer to test `hg pull -r <rev>`
182 --------------------------------------------------------------------------
182 --------------------------------------------------------------------------
183
183
184 Pulling the revision which is applied
184 Pulling the revision which is applied
185
185
186 $ cd ../client2
186 $ cd ../client2
187 $ hg pull -r 6cb0989601f1
187 $ hg pull -r 6cb0989601f1
188 pulling from $TESTTMP/repo
188 pulling from $TESTTMP/repo
189 searching for changes
189 searching for changes
190 adding changesets
190 adding changesets
191 adding manifests
191 adding manifests
192 adding file changes
192 adding file changes
193 added 1 changesets with 1 changes to 1 files
193 added 1 changesets with 1 changes to 1 files
194 new changesets 6cb0989601f1
194 new changesets 6cb0989601f1
195 (run 'hg update' to get a working copy)
195 (run 'hg update' to get a working copy)
196 $ hg glog
196 $ hg glog
197 o 1:6cb0989601f1 added a
197 o 1:6cb0989601f1 added a
198 | public
198 | public
199 @ 0:67145f466344 initialcommit
199 @ 0:67145f466344 initialcommit
200 public
200 public
201
201
202 Pulling the revision which is in bundlestore
202 Pulling the revision which is in bundlestore
203 XXX: we should support pulling revisions from a local peers bundlestore without
203 XXX: we should support pulling revisions from a local peers bundlestore without
204 client side wrapping
204 client side wrapping
205
205
206 $ hg pull -r b4e4bce660512ad3e71189e14588a70ac8e31fef
206 $ hg pull -r b4e4bce660512ad3e71189e14588a70ac8e31fef
207 pulling from $TESTTMP/repo
207 pulling from $TESTTMP/repo
208 abort: unknown revision 'b4e4bce660512ad3e71189e14588a70ac8e31fef'
208 abort: unknown revision 'b4e4bce660512ad3e71189e14588a70ac8e31fef'
209 [255]
209 [255]
210 $ hg glog
210 $ hg glog
211 o 1:6cb0989601f1 added a
211 o 1:6cb0989601f1 added a
212 | public
212 | public
213 @ 0:67145f466344 initialcommit
213 @ 0:67145f466344 initialcommit
214 public
214 public
215
215
216 $ cd ../client
216 $ cd ../client
217
217
218 Pulling from third client which is not a localpeer
218 Pulling from third client which is not a localpeer
219 ---------------------------------------------------
219 ---------------------------------------------------
220
220
221 Pulling the revision which is applied
221 Pulling the revision which is applied
222
222
223 $ cd ../client3
223 $ cd ../client3
224 $ hg pull -r 6cb0989601f1
224 $ hg pull -r 6cb0989601f1
225 pulling from ssh://user@dummy/repo
225 pulling from ssh://user@dummy/repo
226 searching for changes
226 searching for changes
227 adding changesets
227 adding changesets
228 adding manifests
228 adding manifests
229 adding file changes
229 adding file changes
230 added 1 changesets with 1 changes to 1 files
230 added 1 changesets with 1 changes to 1 files
231 new changesets 6cb0989601f1
231 new changesets 6cb0989601f1
232 (run 'hg update' to get a working copy)
232 (run 'hg update' to get a working copy)
233 $ hg glog
233 $ hg glog
234 o 1:6cb0989601f1 added a
234 o 1:6cb0989601f1 added a
235 | public
235 | public
236 @ 0:67145f466344 initialcommit
236 @ 0:67145f466344 initialcommit
237 public
237 public
238
238
239 Pulling the revision which is in bundlestore
239 Pulling the revision which is in bundlestore
240
240
241 Trying to specify short hash
241 Trying to specify short hash
242 XXX: we should support this
242 XXX: we should support this
243 $ hg pull -r b4e4bce660512
243 $ hg pull -r b4e4bce660512
244 pulling from ssh://user@dummy/repo
244 pulling from ssh://user@dummy/repo
245 abort: unknown revision 'b4e4bce660512'
245 abort: unknown revision 'b4e4bce660512'
246 [255]
246 [255]
247
247
248 XXX: we should show better message when the pull is happening from bundlestore
248 XXX: we should show better message when the pull is happening from bundlestore
249 $ hg pull -r b4e4bce660512ad3e71189e14588a70ac8e31fef
249 $ hg pull -r b4e4bce660512ad3e71189e14588a70ac8e31fef
250 pulling from ssh://user@dummy/repo
250 pulling from ssh://user@dummy/repo
251 searching for changes
251 searching for changes
252 adding changesets
252 adding changesets
253 adding manifests
253 adding manifests
254 adding file changes
254 adding file changes
255 added 4 changesets with 4 changes to 4 files
255 added 4 changesets with 4 changes to 4 files
256 new changesets eaba929e866c:b4e4bce66051
256 new changesets eaba929e866c:b4e4bce66051
257 (run 'hg update' to get a working copy)
257 (run 'hg update' to get a working copy)
258 $ hg glog
258 $ hg glog
259 o 5:b4e4bce66051 added e
259 o 5:b4e4bce66051 added e
260 | public
260 | public
261 o 4:1bb96358eda2 added d
261 o 4:1bb96358eda2 added d
262 | public
262 | public
263 o 3:bf8a6e3011b3 added c
263 o 3:bf8a6e3011b3 added c
264 | public
264 | public
265 o 2:eaba929e866c added b
265 o 2:eaba929e866c added b
266 | public
266 | public
267 o 1:6cb0989601f1 added a
267 o 1:6cb0989601f1 added a
268 | public
268 | public
269 @ 0:67145f466344 initialcommit
269 @ 0:67145f466344 initialcommit
270 public
270 public
271
271
272 $ cd ../client
272 $ cd ../client
273
273
274 Checking storage of phase information with the bundle on bundlestore
274 Checking storage of phase information with the bundle on bundlestore
275 ---------------------------------------------------------------------
275 ---------------------------------------------------------------------
276
276
277 creating a draft commit
277 creating a draft commit
278 $ cat >> $HGRCPATH <<EOF
278 $ cat >> $HGRCPATH <<EOF
279 > [phases]
279 > [phases]
280 > publish = False
280 > publish = False
281 > EOF
281 > EOF
282 $ echo f > f
282 $ echo f > f
283 $ hg ci -Aqm "added f"
283 $ hg ci -Aqm "added f"
284 $ hg glog -r '.^::'
284 $ hg glog -r '.^::'
285 @ 6:9b42578d4447 added f
285 @ 6:9b42578d4447 added f
286 | draft
286 | draft
287 o 5:b4e4bce66051 added e
287 o 5:b4e4bce66051 added e
288 | public
288 | public
289 ~
289 ~
290
290
291 $ hg push
291 $ hg push
292 pushing to $TESTTMP/repo
292 pushing to $TESTTMP/repo
293 searching for changes
293 searching for changes
294 storing changesets on the bundlestore
294 storing changesets on the bundlestore
295 pushing 5 commits:
295 pushing 5 commits:
296 eaba929e866c added b
296 eaba929e866c added b
297 bf8a6e3011b3 added c
297 bf8a6e3011b3 added c
298 1bb96358eda2 added d
298 1bb96358eda2 added d
299 b4e4bce66051 added e
299 b4e4bce66051 added e
300 9b42578d4447 added f
300 9b42578d4447 added f
301
301
302 XXX: the phase of 9b42578d4447 should not be changed here
302 XXX: the phase of 9b42578d4447 should not be changed here
303 $ hg glog -r .
303 $ hg glog -r .
304 @ 6:9b42578d4447 added f
304 @ 6:9b42578d4447 added f
305 | public
305 | public
306 ~
306 ~
307
307
308 applying the bundle on the server to check preservation of phase-information
308 applying the bundle on the server to check preservation of phase-information
309
309
310 $ cd ../repo
310 $ cd ../repo
311 $ scratchnodes
311 $ scratchnodes
312 1bb96358eda285b536c6d1c66846a7cdb2336cea 280a46a259a268f0e740c81c5a7751bdbfaec85f
312 1bb96358eda285b536c6d1c66846a7cdb2336cea 280a46a259a268f0e740c81c5a7751bdbfaec85f
313 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
313 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
314 9b42578d44473575994109161430d65dd147d16d 280a46a259a268f0e740c81c5a7751bdbfaec85f
314 9b42578d44473575994109161430d65dd147d16d 280a46a259a268f0e740c81c5a7751bdbfaec85f
315 b4e4bce660512ad3e71189e14588a70ac8e31fef 280a46a259a268f0e740c81c5a7751bdbfaec85f
315 b4e4bce660512ad3e71189e14588a70ac8e31fef 280a46a259a268f0e740c81c5a7751bdbfaec85f
316 bf8a6e3011b345146bbbedbcb1ebd4837571492a 280a46a259a268f0e740c81c5a7751bdbfaec85f
316 bf8a6e3011b345146bbbedbcb1ebd4837571492a 280a46a259a268f0e740c81c5a7751bdbfaec85f
317 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 280a46a259a268f0e740c81c5a7751bdbfaec85f
317 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 280a46a259a268f0e740c81c5a7751bdbfaec85f
318
318
319 $ hg unbundle .hg/scratchbranches/filebundlestore/28/0a/280a46a259a268f0e740c81c5a7751bdbfaec85f
319 $ hg unbundle .hg/scratchbranches/filebundlestore/28/0a/280a46a259a268f0e740c81c5a7751bdbfaec85f
320 adding changesets
320 adding changesets
321 adding manifests
321 adding manifests
322 adding file changes
322 adding file changes
323 added 5 changesets with 5 changes to 5 files
323 added 5 changesets with 5 changes to 5 files
324 new changesets eaba929e866c:9b42578d4447 (1 drafts)
324 new changesets eaba929e866c:9b42578d4447 (1 drafts)
325 (run 'hg update' to get a working copy)
325 (run 'hg update' to get a working copy)
326
326
327 $ hg glog
327 $ hg glog
328 o 6:9b42578d4447 added f
328 o 6:9b42578d4447 added f
329 | draft
329 | draft
330 o 5:b4e4bce66051 added e
330 o 5:b4e4bce66051 added e
331 | public
331 | public
332 o 4:1bb96358eda2 added d
332 o 4:1bb96358eda2 added d
333 | public
333 | public
334 o 3:bf8a6e3011b3 added c
334 o 3:bf8a6e3011b3 added c
335 | public
335 | public
336 o 2:eaba929e866c added b
336 o 2:eaba929e866c added b
337 | public
337 | public
338 o 1:6cb0989601f1 added a
338 o 1:6cb0989601f1 added a
339 | public
339 | public
340 @ 0:67145f466344 initialcommit
340 @ 0:67145f466344 initialcommit
341 public
341 public
342
342
343 Checking storage of obsmarkers in the bundlestore
343 Checking storage of obsmarkers in the bundlestore
344 --------------------------------------------------
344 --------------------------------------------------
345
345
346 enabling obsmarkers and rebase extension
346 enabling obsmarkers and rebase extension
347
347
348 $ cat >> $HGRCPATH << EOF
348 $ cat >> $HGRCPATH << EOF
349 > [experimental]
349 > [experimental]
350 > evolution = all
350 > evolution = all
351 > [extensions]
351 > [extensions]
352 > rebase =
352 > rebase =
353 > EOF
353 > EOF
354
354
355 $ cd ../client
355 $ cd ../client
356
356
357 $ hg phase -r . --draft --force
357 $ hg phase -r . --draft --force
358 $ hg rebase -r 6 -d 3
358 $ hg rebase -r 6 -d 3
359 rebasing 6:9b42578d4447 tip "added f"
359 rebasing 6:9b42578d4447 tip "added f"
360
360
361 $ hg glog
361 $ hg glog
362 @ 7:99949238d9ac added f
362 @ 7:99949238d9ac added f
363 | draft
363 | draft
364 | o 5:b4e4bce66051 added e
364 | o 5:b4e4bce66051 added e
365 | | public
365 | | public
366 | o 4:1bb96358eda2 added d
366 | o 4:1bb96358eda2 added d
367 |/ public
367 |/ public
368 o 3:bf8a6e3011b3 added c
368 o 3:bf8a6e3011b3 added c
369 | public
369 | public
370 o 2:eaba929e866c added b
370 o 2:eaba929e866c added b
371 | public
371 | public
372 o 1:6cb0989601f1 added a
372 o 1:6cb0989601f1 added a
373 | public
373 | public
374 o 0:67145f466344 initialcommit
374 o 0:67145f466344 initialcommit
375 public
375 public
376
376
377 $ hg push -f
377 $ hg push -f
378 pushing to $TESTTMP/repo
378 pushing to $TESTTMP/repo
379 searching for changes
379 searching for changes
380 storing changesets on the bundlestore
380 storing changesets on the bundlestore
381 pushing 1 commit:
381 pushing 1 commit:
382 99949238d9ac added f
382 99949238d9ac added f
383
383
384 XXX: the phase should not have changed here
384 XXX: the phase should not have changed here
385 $ hg glog -r .
385 $ hg glog -r .
386 @ 7:99949238d9ac added f
386 @ 7:99949238d9ac added f
387 | public
387 | public
388 ~
388 ~
389
389
390 Unbundling on server to see obsmarkers being applied
390 Unbundling on server to see obsmarkers being applied
391
391
392 $ cd ../repo
392 $ cd ../repo
393
393
394 $ scratchnodes
394 $ scratchnodes
395 1bb96358eda285b536c6d1c66846a7cdb2336cea 280a46a259a268f0e740c81c5a7751bdbfaec85f
395 1bb96358eda285b536c6d1c66846a7cdb2336cea 280a46a259a268f0e740c81c5a7751bdbfaec85f
396 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
396 6cb0989601f1fb5805238edfb16f3606713d9a0b 3b414252ff8acab801318445d88ff48faf4a28c3
397 99949238d9ac7f2424a33a46dface6f866afd059 090a24fe63f31d3b4bee714447f835c8c362ff57
397 99949238d9ac7f2424a33a46dface6f866afd059 090a24fe63f31d3b4bee714447f835c8c362ff57
398 9b42578d44473575994109161430d65dd147d16d 280a46a259a268f0e740c81c5a7751bdbfaec85f
398 9b42578d44473575994109161430d65dd147d16d 280a46a259a268f0e740c81c5a7751bdbfaec85f
399 b4e4bce660512ad3e71189e14588a70ac8e31fef 280a46a259a268f0e740c81c5a7751bdbfaec85f
399 b4e4bce660512ad3e71189e14588a70ac8e31fef 280a46a259a268f0e740c81c5a7751bdbfaec85f
400 bf8a6e3011b345146bbbedbcb1ebd4837571492a 280a46a259a268f0e740c81c5a7751bdbfaec85f
400 bf8a6e3011b345146bbbedbcb1ebd4837571492a 280a46a259a268f0e740c81c5a7751bdbfaec85f
401 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 280a46a259a268f0e740c81c5a7751bdbfaec85f
401 eaba929e866c59bc9a6aada5a9dd2f6990db83c0 280a46a259a268f0e740c81c5a7751bdbfaec85f
402
402
403 $ hg glog
403 $ hg glog
404 o 6:9b42578d4447 added f
404 o 6:9b42578d4447 added f
405 | draft
405 | draft
406 o 5:b4e4bce66051 added e
406 o 5:b4e4bce66051 added e
407 | public
407 | public
408 o 4:1bb96358eda2 added d
408 o 4:1bb96358eda2 added d
409 | public
409 | public
410 o 3:bf8a6e3011b3 added c
410 o 3:bf8a6e3011b3 added c
411 | public
411 | public
412 o 2:eaba929e866c added b
412 o 2:eaba929e866c added b
413 | public
413 | public
414 o 1:6cb0989601f1 added a
414 o 1:6cb0989601f1 added a
415 | public
415 | public
416 @ 0:67145f466344 initialcommit
416 @ 0:67145f466344 initialcommit
417 public
417 public
418
418
419 $ hg unbundle .hg/scratchbranches/filebundlestore/09/0a/090a24fe63f31d3b4bee714447f835c8c362ff57
419 $ hg unbundle .hg/scratchbranches/filebundlestore/09/0a/090a24fe63f31d3b4bee714447f835c8c362ff57
420 adding changesets
420 adding changesets
421 adding manifests
421 adding manifests
422 adding file changes
422 adding file changes
423 added 1 changesets with 0 changes to 1 files (+1 heads)
423 added 1 changesets with 0 changes to 1 files (+1 heads)
424 1 new obsolescence markers
424 1 new obsolescence markers
425 obsoleted 1 changesets
425 obsoleted 1 changesets
426 new changesets 99949238d9ac (1 drafts)
426 new changesets 99949238d9ac (1 drafts)
427 (run 'hg heads' to see heads, 'hg merge' to merge)
427 (run 'hg heads' to see heads, 'hg merge' to merge)
428
428
429 $ hg glog
429 $ hg glog
430 o 7:99949238d9ac added f
430 o 7:99949238d9ac added f
431 | draft
431 | draft
432 | o 5:b4e4bce66051 added e
432 | o 5:b4e4bce66051 added e
433 | | public
433 | | public
434 | o 4:1bb96358eda2 added d
434 | o 4:1bb96358eda2 added d
435 |/ public
435 |/ public
436 o 3:bf8a6e3011b3 added c
436 o 3:bf8a6e3011b3 added c
437 | public
437 | public
438 o 2:eaba929e866c added b
438 o 2:eaba929e866c added b
439 | public
439 | public
440 o 1:6cb0989601f1 added a
440 o 1:6cb0989601f1 added a
441 | public
441 | public
442 @ 0:67145f466344 initialcommit
442 @ 0:67145f466344 initialcommit
443 public
443 public
@@ -1,85 +1,85 b''
1 #require no-windows
1 #require no-windows
2
2
3 Dummy extension simulating unsafe long running command
3 Dummy extension simulating unsafe long running command
4 $ cat > sleepext.py <<EOF
4 $ cat > sleepext.py <<EOF
5 > import itertools
5 > import itertools
6 > import time
6 > import time
7 >
7 >
8 > from mercurial.i18n import _
8 > from mercurial.i18n import _
9 > from mercurial import registrar
9 > from mercurial import registrar
10 >
10 >
11 > cmdtable = {}
11 > cmdtable = {}
12 > command = registrar.command(cmdtable)
12 > command = registrar.command(cmdtable)
13 >
13 >
14 > @command(b'sleep', [], _(b'TIME'), norepo=True)
14 > @command(b'sleep', [], _(b'TIME'), norepo=True)
15 > def sleep(ui, sleeptime=b"1", **opts):
15 > def sleep(ui, sleeptime=b"1", **opts):
16 > with ui.uninterruptible():
16 > with ui.uninterruptible():
17 > for _i in itertools.repeat(None, int(sleeptime)):
17 > for _i in itertools.repeat(None, int(sleeptime)):
18 > time.sleep(1)
18 > time.sleep(1)
19 > ui.warn(b"end of unsafe operation\n")
19 > ui.warn(b"end of unsafe operation\n")
20 > ui.warn(b"%s second(s) passed\n" % sleeptime)
20 > ui.warn(b"%s second(s) passed\n" % sleeptime)
21 > EOF
21 > EOF
22
22
23 Kludge to emulate timeout(1) which is not generally available.
23 Kludge to emulate timeout(1) which is not generally available.
24 $ cat > timeout.py <<EOF
24 $ cat > timeout.py <<EOF
25 > from __future__ import print_function
25 > from __future__ import print_function
26 > import argparse
26 > import argparse
27 > import signal
27 > import signal
28 > import subprocess
28 > import subprocess
29 > import sys
29 > import sys
30 > import time
30 > import time
31 >
31 >
32 > ap = argparse.ArgumentParser()
32 > ap = argparse.ArgumentParser()
33 > ap.add_argument('-s', nargs=1, default='SIGTERM')
33 > ap.add_argument('-s', nargs=1, default='SIGTERM')
34 > ap.add_argument('duration', nargs=1, type=int)
34 > ap.add_argument('duration', nargs=1, type=int)
35 > ap.add_argument('argv', nargs='*')
35 > ap.add_argument('argv', nargs='*')
36 > opts = ap.parse_args()
36 > opts = ap.parse_args()
37 > try:
37 > try:
38 > sig = int(opts.s[0])
38 > sig = int(opts.s[0])
39 > except ValueError:
39 > except ValueError:
40 > sname = opts.s[0]
40 > sname = opts.s[0]
41 > if not sname.startswith('SIG'):
41 > if not sname.startswith('SIG'):
42 > sname = 'SIG' + sname
42 > sname = 'SIG' + sname
43 > sig = getattr(signal, sname)
43 > sig = getattr(signal, sname)
44 > proc = subprocess.Popen(opts.argv)
44 > proc = subprocess.Popen(opts.argv)
45 > time.sleep(opts.duration[0])
45 > time.sleep(opts.duration[0])
46 > proc.poll()
46 > proc.poll()
47 > if proc.returncode is None:
47 > if proc.returncode is None:
48 > proc.send_signal(sig)
48 > proc.send_signal(sig)
49 > proc.wait()
49 > proc.wait()
50 > sys.exit(124)
50 > sys.exit(124)
51 > EOF
51 > EOF
52
52
53 Set up repository
53 Set up repository
54 $ hg init repo
54 $ hg init repo
55 $ cd repo
55 $ cd repo
56 $ cat >> $HGRCPATH << EOF
56 $ cat >> $HGRCPATH << EOF
57 > [extensions]
57 > [extensions]
58 > sleepext = ../sleepext.py
58 > sleepext = ../sleepext.py
59 > EOF
59 > EOF
60
60
61 Test ctrl-c
61 Test ctrl-c
62 $ python $TESTTMP/timeout.py -s INT 1 hg sleep 2
62 $ $PYTHON $TESTTMP/timeout.py -s INT 1 hg sleep 2
63 interrupted!
63 interrupted!
64 [124]
64 [124]
65
65
66 $ cat >> $HGRCPATH << EOF
66 $ cat >> $HGRCPATH << EOF
67 > [experimental]
67 > [experimental]
68 > nointerrupt = yes
68 > nointerrupt = yes
69 > EOF
69 > EOF
70
70
71 $ python $TESTTMP/timeout.py -s INT 1 hg sleep 2
71 $ $PYTHON $TESTTMP/timeout.py -s INT 1 hg sleep 2
72 interrupted!
72 interrupted!
73 [124]
73 [124]
74
74
75 $ cat >> $HGRCPATH << EOF
75 $ cat >> $HGRCPATH << EOF
76 > [experimental]
76 > [experimental]
77 > nointerrupt-interactiveonly = False
77 > nointerrupt-interactiveonly = False
78 > EOF
78 > EOF
79
79
80 $ python $TESTTMP/timeout.py -s INT 1 hg sleep 2
80 $ $PYTHON $TESTTMP/timeout.py -s INT 1 hg sleep 2
81 shutting down cleanly
81 shutting down cleanly
82 press ^C again to terminate immediately (dangerous)
82 press ^C again to terminate immediately (dangerous)
83 end of unsafe operation
83 end of unsafe operation
84 interrupted!
84 interrupted!
85 [124]
85 [124]
@@ -1,125 +1,125 b''
1 #require no-windows
1 #require no-windows
2
2
3 $ . "$TESTDIR/remotefilelog-library.sh"
3 $ . "$TESTDIR/remotefilelog-library.sh"
4
4
5 $ hg init repo
5 $ hg init repo
6 $ cd repo
6 $ cd repo
7 $ cat >> .hg/hgrc <<EOF
7 $ cat >> .hg/hgrc <<EOF
8 > [remotefilelog]
8 > [remotefilelog]
9 > server=True
9 > server=True
10 > EOF
10 > EOF
11 $ echo x > x
11 $ echo x > x
12 $ echo y > y
12 $ echo y > y
13 $ echo z > z
13 $ echo z > z
14 $ hg commit -qAm xy
14 $ hg commit -qAm xy
15 $ cd ..
15 $ cd ..
16
16
17 $ cat > cacheprocess-logger.py <<EOF
17 $ cat > cacheprocess-logger.py <<EOF
18 > import os
18 > import os
19 > import shutil
19 > import shutil
20 > import sys
20 > import sys
21 > if sys.version_info[0] > 2:
21 > if sys.version_info[0] > 2:
22 > xrange = range
22 > xrange = range
23 > f = open('$TESTTMP/cachelog.log', 'w')
23 > f = open('$TESTTMP/cachelog.log', 'w')
24 > srccache = os.path.join('$TESTTMP', 'oldhgcache')
24 > srccache = os.path.join('$TESTTMP', 'oldhgcache')
25 > def log(message):
25 > def log(message):
26 > f.write(message)
26 > f.write(message)
27 > f.flush()
27 > f.flush()
28 > destcache = sys.argv[-1]
28 > destcache = sys.argv[-1]
29 > try:
29 > try:
30 > while True:
30 > while True:
31 > cmd = sys.stdin.readline().strip()
31 > cmd = sys.stdin.readline().strip()
32 > log('got command %r\n' % cmd)
32 > log('got command %r\n' % cmd)
33 > if cmd == 'exit':
33 > if cmd == 'exit':
34 > sys.exit(0)
34 > sys.exit(0)
35 > elif cmd == 'get':
35 > elif cmd == 'get':
36 > count = int(sys.stdin.readline())
36 > count = int(sys.stdin.readline())
37 > log('client wants %r blobs\n' % count)
37 > log('client wants %r blobs\n' % count)
38 > wants = []
38 > wants = []
39 > for _ in xrange(count):
39 > for _ in xrange(count):
40 > key = sys.stdin.readline()[:-1]
40 > key = sys.stdin.readline()[:-1]
41 > wants.append(key)
41 > wants.append(key)
42 > if '\0' in key:
42 > if '\0' in key:
43 > _, key = key.split('\0')
43 > _, key = key.split('\0')
44 > srcpath = os.path.join(srccache, key)
44 > srcpath = os.path.join(srccache, key)
45 > if os.path.exists(srcpath):
45 > if os.path.exists(srcpath):
46 > dest = os.path.join(destcache, key)
46 > dest = os.path.join(destcache, key)
47 > destdir = os.path.dirname(dest)
47 > destdir = os.path.dirname(dest)
48 > if not os.path.exists(destdir):
48 > if not os.path.exists(destdir):
49 > os.makedirs(destdir)
49 > os.makedirs(destdir)
50 > shutil.copyfile(srcpath, dest)
50 > shutil.copyfile(srcpath, dest)
51 > else:
51 > else:
52 > # report a cache miss
52 > # report a cache miss
53 > sys.stdout.write(key + '\n')
53 > sys.stdout.write(key + '\n')
54 > sys.stdout.write('0\n')
54 > sys.stdout.write('0\n')
55 > for key in sorted(wants):
55 > for key in sorted(wants):
56 > log('requested %r\n' % key)
56 > log('requested %r\n' % key)
57 > sys.stdout.flush()
57 > sys.stdout.flush()
58 > elif cmd == 'set':
58 > elif cmd == 'set':
59 > raise Exception('todo writing')
59 > raise Exception('todo writing')
60 > else:
60 > else:
61 > raise Exception('unknown command! %r' % cmd)
61 > raise Exception('unknown command! %r' % cmd)
62 > except Exception as e:
62 > except Exception as e:
63 > log('Exception! %s\n' % e)
63 > log('Exception! %s\n' % e)
64 > raise
64 > raise
65 > EOF
65 > EOF
66
66
67 $ cat >> $HGRCPATH <<EOF
67 $ cat >> $HGRCPATH <<EOF
68 > [remotefilelog]
68 > [remotefilelog]
69 > cacheprocess = python $TESTTMP/cacheprocess-logger.py
69 > cacheprocess = $PYTHON $TESTTMP/cacheprocess-logger.py
70 > EOF
70 > EOF
71
71
72 Test cache keys and cache misses.
72 Test cache keys and cache misses.
73 $ hgcloneshallow ssh://user@dummy/repo clone -q
73 $ hgcloneshallow ssh://user@dummy/repo clone -q
74 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
74 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
75 $ cat cachelog.log
75 $ cat cachelog.log
76 got command 'get'
76 got command 'get'
77 client wants 3 blobs
77 client wants 3 blobs
78 requested 'master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
78 requested 'master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
79 requested 'master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
79 requested 'master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
80 requested 'master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
80 requested 'master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
81 got command 'set'
81 got command 'set'
82 Exception! todo writing
82 Exception! todo writing
83
83
84 Test cache hits.
84 Test cache hits.
85 $ mv hgcache oldhgcache
85 $ mv hgcache oldhgcache
86 $ rm cachelog.log
86 $ rm cachelog.log
87 $ hgcloneshallow ssh://user@dummy/repo clone-cachehit -q
87 $ hgcloneshallow ssh://user@dummy/repo clone-cachehit -q
88 3 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over *s (glob)
88 3 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over *s (glob)
89 $ cat cachelog.log | grep -v exit
89 $ cat cachelog.log | grep -v exit
90 got command 'get'
90 got command 'get'
91 client wants 3 blobs
91 client wants 3 blobs
92 requested 'master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
92 requested 'master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
93 requested 'master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
93 requested 'master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
94 requested 'master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
94 requested 'master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
95
95
96 $ cat >> $HGRCPATH <<EOF
96 $ cat >> $HGRCPATH <<EOF
97 > [remotefilelog]
97 > [remotefilelog]
98 > cacheprocess.includepath = yes
98 > cacheprocess.includepath = yes
99 > EOF
99 > EOF
100
100
101 Test cache keys and cache misses with includepath.
101 Test cache keys and cache misses with includepath.
102 $ rm -r hgcache oldhgcache
102 $ rm -r hgcache oldhgcache
103 $ rm cachelog.log
103 $ rm cachelog.log
104 $ hgcloneshallow ssh://user@dummy/repo clone-withpath -q
104 $ hgcloneshallow ssh://user@dummy/repo clone-withpath -q
105 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
105 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
106 $ cat cachelog.log
106 $ cat cachelog.log
107 got command 'get'
107 got command 'get'
108 client wants 3 blobs
108 client wants 3 blobs
109 requested 'x\x00master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
109 requested 'x\x00master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
110 requested 'y\x00master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
110 requested 'y\x00master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
111 requested 'z\x00master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
111 requested 'z\x00master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
112 got command 'set'
112 got command 'set'
113 Exception! todo writing
113 Exception! todo writing
114
114
115 Test cache hits with includepath.
115 Test cache hits with includepath.
116 $ mv hgcache oldhgcache
116 $ mv hgcache oldhgcache
117 $ rm cachelog.log
117 $ rm cachelog.log
118 $ hgcloneshallow ssh://user@dummy/repo clone-withpath-cachehit -q
118 $ hgcloneshallow ssh://user@dummy/repo clone-withpath-cachehit -q
119 3 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over *s (glob)
119 3 files fetched over 1 fetches - (0 misses, 100.00% hit ratio) over *s (glob)
120 $ cat cachelog.log | grep -v exit
120 $ cat cachelog.log | grep -v exit
121 got command 'get'
121 got command 'get'
122 client wants 3 blobs
122 client wants 3 blobs
123 requested 'x\x00master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
123 requested 'x\x00master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0'
124 requested 'y\x00master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
124 requested 'y\x00master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca'
125 requested 'z\x00master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
125 requested 'z\x00master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a'
@@ -1,147 +1,147 b''
1 #require execbit unix-permissions no-chg
1 #require execbit unix-permissions no-chg
2
2
3 Checking that experimental.atomic-file works.
3 Checking that experimental.atomic-file works.
4
4
5 $ cat > $TESTTMP/show_mode.py <<EOF
5 $ cat > $TESTTMP/show_mode.py <<EOF
6 > from __future__ import print_function
6 > from __future__ import print_function
7 > import os
7 > import os
8 > import stat
8 > import stat
9 > import sys
9 > import sys
10 > ST_MODE = stat.ST_MODE
10 > ST_MODE = stat.ST_MODE
11 >
11 >
12 > for file_path in sys.argv[1:]:
12 > for file_path in sys.argv[1:]:
13 > file_stat = os.stat(file_path)
13 > file_stat = os.stat(file_path)
14 > octal_mode = oct(file_stat[ST_MODE] & 0o777).replace('o', '')
14 > octal_mode = oct(file_stat[ST_MODE] & 0o777).replace('o', '')
15 > print("%s:%s" % (file_path, octal_mode))
15 > print("%s:%s" % (file_path, octal_mode))
16 >
16 >
17 > EOF
17 > EOF
18
18
19 $ hg init repo
19 $ hg init repo
20 $ cd repo
20 $ cd repo
21
21
22 $ cat > .hg/showwrites.py <<EOF
22 $ cat > .hg/showwrites.py <<EOF
23 > from __future__ import print_function
23 > from __future__ import print_function
24 > from mercurial import pycompat
24 > from mercurial import pycompat
25 > from mercurial.utils import stringutil
25 > from mercurial.utils import stringutil
26 > def uisetup(ui):
26 > def uisetup(ui):
27 > from mercurial import vfs
27 > from mercurial import vfs
28 > class newvfs(vfs.vfs):
28 > class newvfs(vfs.vfs):
29 > def __call__(self, *args, **kwargs):
29 > def __call__(self, *args, **kwargs):
30 > print(pycompat.sysstr(stringutil.pprint(
30 > print(pycompat.sysstr(stringutil.pprint(
31 > ('vfs open', args, sorted(list(kwargs.items()))))))
31 > ('vfs open', args, sorted(list(kwargs.items()))))))
32 > return super(newvfs, self).__call__(*args, **kwargs)
32 > return super(newvfs, self).__call__(*args, **kwargs)
33 > vfs.vfs = newvfs
33 > vfs.vfs = newvfs
34 > EOF
34 > EOF
35
35
36 $ for v in a1 a2 b1 b2 c ro; do echo $v > $v; done
36 $ for v in a1 a2 b1 b2 c ro; do echo $v > $v; done
37 $ chmod +x b*
37 $ chmod +x b*
38 $ hg commit -Aqm _
38 $ hg commit -Aqm _
39
39
40 # We check that
40 # We check that
41 # - the changes are actually atomic
41 # - the changes are actually atomic
42 # - that permissions are correct (all 4 cases of (executable before) * (executable after))
42 # - that permissions are correct (all 4 cases of (executable before) * (executable after))
43 # - that renames work, though they should be atomic anyway
43 # - that renames work, though they should be atomic anyway
44 # - that it works when source files are read-only (but directories are read-write still)
44 # - that it works when source files are read-only (but directories are read-write still)
45
45
46 $ for v in a1 a2 b1 b2 ro; do echo changed-$v > $v; done
46 $ for v in a1 a2 b1 b2 ro; do echo changed-$v > $v; done
47 $ chmod -x *1; chmod +x *2
47 $ chmod -x *1; chmod +x *2
48 $ hg rename c d
48 $ hg rename c d
49 $ hg commit -qm _
49 $ hg commit -qm _
50
50
51 Check behavior without update.atomic-file
51 Check behavior without update.atomic-file
52
52
53 $ hg update -r 0 -q
53 $ hg update -r 0 -q
54 $ hg update -r 1 --config extensions.showwrites=.hg/showwrites.py 2>&1 | grep "a1'.*wb"
54 $ hg update -r 1 --config extensions.showwrites=.hg/showwrites.py 2>&1 | grep "a1'.*wb"
55 ('vfs open', ('a1', 'wb'), [('atomictemp', False), ('backgroundclose', True)])
55 ('vfs open', ('a1', 'wb'), [('atomictemp', False), ('backgroundclose', True)])
56
56
57 $ python $TESTTMP/show_mode.py *
57 $ $PYTHON $TESTTMP/show_mode.py *
58 a1:0644
58 a1:0644
59 a2:0755
59 a2:0755
60 b1:0644
60 b1:0644
61 b2:0755
61 b2:0755
62 d:0644
62 d:0644
63 ro:0644
63 ro:0644
64
64
65 Add a second revision for the ro file so we can test update when the file is
65 Add a second revision for the ro file so we can test update when the file is
66 present or not
66 present or not
67
67
68 $ echo "ro" > ro
68 $ echo "ro" > ro
69
69
70 $ hg commit -qm _
70 $ hg commit -qm _
71
71
72 Check behavior without update.atomic-file first
72 Check behavior without update.atomic-file first
73
73
74 $ hg update -C -r 0 -q
74 $ hg update -C -r 0 -q
75
75
76 $ hg update -r 1
76 $ hg update -r 1
77 6 files updated, 0 files merged, 1 files removed, 0 files unresolved
77 6 files updated, 0 files merged, 1 files removed, 0 files unresolved
78
78
79 $ python $TESTTMP/show_mode.py *
79 $ $PYTHON $TESTTMP/show_mode.py *
80 a1:0644
80 a1:0644
81 a2:0755
81 a2:0755
82 b1:0644
82 b1:0644
83 b2:0755
83 b2:0755
84 d:0644
84 d:0644
85 ro:0644
85 ro:0644
86
86
87 Manually reset the mode of the read-only file
87 Manually reset the mode of the read-only file
88
88
89 $ chmod a-w ro
89 $ chmod a-w ro
90
90
91 $ python $TESTTMP/show_mode.py ro
91 $ $PYTHON $TESTTMP/show_mode.py ro
92 ro:0444
92 ro:0444
93
93
94 Now the file is present, try to update and check the permissions of the file
94 Now the file is present, try to update and check the permissions of the file
95
95
96 $ hg up -r 2
96 $ hg up -r 2
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98
98
99 $ python $TESTTMP/show_mode.py ro
99 $ $PYTHON $TESTTMP/show_mode.py ro
100 ro:0644
100 ro:0644
101
101
102 # The file which was read-only is now writable in the default behavior
102 # The file which was read-only is now writable in the default behavior
103
103
104 Check behavior with update.atomic-files
104 Check behavior with update.atomic-files
105
105
106
106
107 $ cat >> .hg/hgrc <<EOF
107 $ cat >> .hg/hgrc <<EOF
108 > [experimental]
108 > [experimental]
109 > update.atomic-file = true
109 > update.atomic-file = true
110 > EOF
110 > EOF
111
111
112 $ hg update -C -r 0 -q
112 $ hg update -C -r 0 -q
113 $ hg update -r 1 --config extensions.showwrites=.hg/showwrites.py 2>&1 | grep "a1'.*wb"
113 $ hg update -r 1 --config extensions.showwrites=.hg/showwrites.py 2>&1 | grep "a1'.*wb"
114 ('vfs open', ('a1', 'wb'), [('atomictemp', True), ('backgroundclose', True)])
114 ('vfs open', ('a1', 'wb'), [('atomictemp', True), ('backgroundclose', True)])
115 $ hg st -A --rev 1
115 $ hg st -A --rev 1
116 C a1
116 C a1
117 C a2
117 C a2
118 C b1
118 C b1
119 C b2
119 C b2
120 C d
120 C d
121 C ro
121 C ro
122
122
123 Check the file permission after update
123 Check the file permission after update
124 $ python $TESTTMP/show_mode.py *
124 $ $PYTHON $TESTTMP/show_mode.py *
125 a1:0644
125 a1:0644
126 a2:0755
126 a2:0755
127 b1:0644
127 b1:0644
128 b2:0755
128 b2:0755
129 d:0644
129 d:0644
130 ro:0644
130 ro:0644
131
131
132 Manually reset the mode of the read-only file
132 Manually reset the mode of the read-only file
133
133
134 $ chmod a-w ro
134 $ chmod a-w ro
135
135
136 $ python $TESTTMP/show_mode.py ro
136 $ $PYTHON $TESTTMP/show_mode.py ro
137 ro:0444
137 ro:0444
138
138
139 Now the file is present, try to update and check the permissions of the file
139 Now the file is present, try to update and check the permissions of the file
140
140
141 $ hg update -r 2 --traceback
141 $ hg update -r 2 --traceback
142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
143
143
144 $ python $TESTTMP/show_mode.py ro
144 $ $PYTHON $TESTTMP/show_mode.py ro
145 ro:0644
145 ro:0644
146
146
147 # The behavior is the same as without atomic update
147 # The behavior is the same as without atomic update
@@ -1,640 +1,642 b''
1 from __future__ import print_function, absolute_import
1 from __future__ import print_function, absolute_import
2
2
3 """Fuzz testing for operations against a Mercurial repository
3 """Fuzz testing for operations against a Mercurial repository
4
4
5 This uses Hypothesis's stateful testing to generate random repository
5 This uses Hypothesis's stateful testing to generate random repository
6 operations and test Mercurial using them, both to see if there are any
6 operations and test Mercurial using them, both to see if there are any
7 unexpected errors and to compare different versions of it."""
7 unexpected errors and to compare different versions of it."""
8
8
9 import os
9 import os
10 import subprocess
10 import subprocess
11 import sys
11 import sys
12
12
13 # Only run if slow tests are allowed
13 # Only run if slow tests are allowed
14 if subprocess.call(['python', '%s/hghave' % os.environ['TESTDIR'], 'slow']):
14 if subprocess.call(
15 [os.environ['PYTHON'], '%s/hghave' % os.environ['TESTDIR'], 'slow']
16 ):
15 sys.exit(80)
17 sys.exit(80)
16
18
17 # These tests require Hypothesis and pytz to be installed.
19 # These tests require Hypothesis and pytz to be installed.
18 # Running 'pip install hypothesis pytz' will achieve that.
20 # Running 'pip install hypothesis pytz' will achieve that.
19 # Note: This won't work if you're running Python < 2.7.
21 # Note: This won't work if you're running Python < 2.7.
20 try:
22 try:
21 from hypothesis.extra.datetime import datetimes
23 from hypothesis.extra.datetime import datetimes
22 except ImportError:
24 except ImportError:
23 sys.stderr.write("skipped: hypothesis or pytz not installed" + os.linesep)
25 sys.stderr.write("skipped: hypothesis or pytz not installed" + os.linesep)
24 sys.exit(80)
26 sys.exit(80)
25
27
26 # If you are running an old version of pip you may find that the enum34
28 # If you are running an old version of pip you may find that the enum34
27 # backport is not installed automatically. If so 'pip install enum34' will
29 # backport is not installed automatically. If so 'pip install enum34' will
28 # fix this problem.
30 # fix this problem.
29 try:
31 try:
30 import enum
32 import enum
31
33
32 assert enum # Silence pyflakes
34 assert enum # Silence pyflakes
33 except ImportError:
35 except ImportError:
34 sys.stderr.write("skipped: enum34 not installed" + os.linesep)
36 sys.stderr.write("skipped: enum34 not installed" + os.linesep)
35 sys.exit(80)
37 sys.exit(80)
36
38
37 import binascii
39 import binascii
38 from contextlib import contextmanager
40 from contextlib import contextmanager
39 import errno
41 import errno
40 import pipes
42 import pipes
41 import shutil
43 import shutil
42 import silenttestrunner
44 import silenttestrunner
43 import subprocess
45 import subprocess
44
46
45 from hypothesis.errors import HypothesisException
47 from hypothesis.errors import HypothesisException
46 from hypothesis.stateful import (
48 from hypothesis.stateful import (
47 rule,
49 rule,
48 RuleBasedStateMachine,
50 RuleBasedStateMachine,
49 Bundle,
51 Bundle,
50 precondition,
52 precondition,
51 )
53 )
52 from hypothesis import settings, note, strategies as st
54 from hypothesis import settings, note, strategies as st
53 from hypothesis.configuration import set_hypothesis_home_dir
55 from hypothesis.configuration import set_hypothesis_home_dir
54 from hypothesis.database import ExampleDatabase
56 from hypothesis.database import ExampleDatabase
55
57
56 testdir = os.path.abspath(os.environ["TESTDIR"])
58 testdir = os.path.abspath(os.environ["TESTDIR"])
57
59
58 # We store Hypothesis examples here rather in the temporary test directory
60 # We store Hypothesis examples here rather in the temporary test directory
59 # so that when rerunning a failing test this always results in refinding the
61 # so that when rerunning a failing test this always results in refinding the
60 # previous failure. This directory is in .hgignore and should not be checked in
62 # previous failure. This directory is in .hgignore and should not be checked in
61 # but is useful to have for development.
63 # but is useful to have for development.
62 set_hypothesis_home_dir(os.path.join(testdir, ".hypothesis"))
64 set_hypothesis_home_dir(os.path.join(testdir, ".hypothesis"))
63
65
64 runtests = os.path.join(os.environ["RUNTESTDIR"], "run-tests.py")
66 runtests = os.path.join(os.environ["RUNTESTDIR"], "run-tests.py")
65 testtmp = os.environ["TESTTMP"]
67 testtmp = os.environ["TESTTMP"]
66 assert os.path.isdir(testtmp)
68 assert os.path.isdir(testtmp)
67
69
68 generatedtests = os.path.join(testdir, "hypothesis-generated")
70 generatedtests = os.path.join(testdir, "hypothesis-generated")
69
71
70 try:
72 try:
71 os.makedirs(generatedtests)
73 os.makedirs(generatedtests)
72 except OSError:
74 except OSError:
73 pass
75 pass
74
76
75 # We write out generated .t files to a file in order to ease debugging and to
77 # We write out generated .t files to a file in order to ease debugging and to
76 # give a starting point for turning failures Hypothesis finds into normal
78 # give a starting point for turning failures Hypothesis finds into normal
77 # tests. In order to ensure that multiple copies of this test can be run in
79 # tests. In order to ensure that multiple copies of this test can be run in
78 # parallel we use atomic file create to ensure that we always get a unique
80 # parallel we use atomic file create to ensure that we always get a unique
79 # name.
81 # name.
80 file_index = 0
82 file_index = 0
81 while True:
83 while True:
82 file_index += 1
84 file_index += 1
83 savefile = os.path.join(
85 savefile = os.path.join(
84 generatedtests, "test-generated-%d.t" % (file_index,)
86 generatedtests, "test-generated-%d.t" % (file_index,)
85 )
87 )
86 try:
88 try:
87 os.close(os.open(savefile, os.O_CREAT | os.O_EXCL | os.O_WRONLY))
89 os.close(os.open(savefile, os.O_CREAT | os.O_EXCL | os.O_WRONLY))
88 break
90 break
89 except OSError as e:
91 except OSError as e:
90 if e.errno != errno.EEXIST:
92 if e.errno != errno.EEXIST:
91 raise
93 raise
92 assert os.path.exists(savefile)
94 assert os.path.exists(savefile)
93
95
94 hgrc = os.path.join(".hg", "hgrc")
96 hgrc = os.path.join(".hg", "hgrc")
95
97
96 filecharacters = (
98 filecharacters = (
97 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
99 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
98 "[]^_`;=@{}~ !#$%&'()+,-"
100 "[]^_`;=@{}~ !#$%&'()+,-"
99 )
101 )
100
102
101 files = (
103 files = (
102 st.text(filecharacters, min_size=1)
104 st.text(filecharacters, min_size=1)
103 .map(lambda x: x.strip())
105 .map(lambda x: x.strip())
104 .filter(bool)
106 .filter(bool)
105 .map(lambda s: s.encode('ascii'))
107 .map(lambda s: s.encode('ascii'))
106 )
108 )
107
109
108 safetext = st.text(
110 safetext = st.text(
109 st.characters(
111 st.characters(
110 min_codepoint=1, max_codepoint=127, blacklist_categories=('Cc', 'Cs')
112 min_codepoint=1, max_codepoint=127, blacklist_categories=('Cc', 'Cs')
111 ),
113 ),
112 min_size=1,
114 min_size=1,
113 ).map(lambda s: s.encode('utf-8'))
115 ).map(lambda s: s.encode('utf-8'))
114
116
115 extensions = st.sampled_from(
117 extensions = st.sampled_from(
116 (
118 (
117 'shelve',
119 'shelve',
118 'mq',
120 'mq',
119 'blackbox',
121 'blackbox',
120 )
122 )
121 )
123 )
122
124
123
125
124 @contextmanager
126 @contextmanager
125 def acceptableerrors(*args):
127 def acceptableerrors(*args):
126 """Sometimes we know an operation we're about to perform might fail, and
128 """Sometimes we know an operation we're about to perform might fail, and
127 we're OK with some of the failures. In those cases this may be used as a
129 we're OK with some of the failures. In those cases this may be used as a
128 context manager and will swallow expected failures, as identified by
130 context manager and will swallow expected failures, as identified by
129 substrings of the error message Mercurial emits."""
131 substrings of the error message Mercurial emits."""
130 try:
132 try:
131 yield
133 yield
132 except subprocess.CalledProcessError as e:
134 except subprocess.CalledProcessError as e:
133 if not any(a in e.output for a in args):
135 if not any(a in e.output for a in args):
134 note(e.output)
136 note(e.output)
135 raise
137 raise
136
138
137
139
138 reponames = st.text("abcdefghijklmnopqrstuvwxyz01234556789", min_size=1).map(
140 reponames = st.text("abcdefghijklmnopqrstuvwxyz01234556789", min_size=1).map(
139 lambda s: s.encode('ascii')
141 lambda s: s.encode('ascii')
140 )
142 )
141
143
142
144
143 class verifyingstatemachine(RuleBasedStateMachine):
145 class verifyingstatemachine(RuleBasedStateMachine):
144 """This defines the set of acceptable operations on a Mercurial repository
146 """This defines the set of acceptable operations on a Mercurial repository
145 using Hypothesis's RuleBasedStateMachine.
147 using Hypothesis's RuleBasedStateMachine.
146
148
147 The general concept is that we manage multiple repositories inside a
149 The general concept is that we manage multiple repositories inside a
148 repos/ directory in our temporary test location. Some of these are freshly
150 repos/ directory in our temporary test location. Some of these are freshly
149 inited, some are clones of the others. Our current working directory is
151 inited, some are clones of the others. Our current working directory is
150 always inside one of these repositories while the tests are running.
152 always inside one of these repositories while the tests are running.
151
153
152 Hypothesis then performs a series of operations against these repositories,
154 Hypothesis then performs a series of operations against these repositories,
153 including hg commands, generating contents and editing the .hgrc file.
155 including hg commands, generating contents and editing the .hgrc file.
154 If these operations fail in unexpected ways or behave differently in
156 If these operations fail in unexpected ways or behave differently in
155 different configurations of Mercurial, the test will fail and a minimized
157 different configurations of Mercurial, the test will fail and a minimized
156 .t test file will be written to the hypothesis-generated directory to
158 .t test file will be written to the hypothesis-generated directory to
157 exhibit that failure.
159 exhibit that failure.
158
160
159 Operations are defined as methods with @rule() decorators. See the
161 Operations are defined as methods with @rule() decorators. See the
160 Hypothesis documentation at
162 Hypothesis documentation at
161 http://hypothesis.readthedocs.org/en/release/stateful.html for more
163 http://hypothesis.readthedocs.org/en/release/stateful.html for more
162 details."""
164 details."""
163
165
164 # A bundle is a reusable collection of previously generated data which may
166 # A bundle is a reusable collection of previously generated data which may
165 # be provided as arguments to future operations.
167 # be provided as arguments to future operations.
166 repos = Bundle('repos')
168 repos = Bundle('repos')
167 paths = Bundle('paths')
169 paths = Bundle('paths')
168 contents = Bundle('contents')
170 contents = Bundle('contents')
169 branches = Bundle('branches')
171 branches = Bundle('branches')
170 committimes = Bundle('committimes')
172 committimes = Bundle('committimes')
171
173
172 def __init__(self):
174 def __init__(self):
173 super(verifyingstatemachine, self).__init__()
175 super(verifyingstatemachine, self).__init__()
174 self.repodir = os.path.join(testtmp, "repos")
176 self.repodir = os.path.join(testtmp, "repos")
175 if os.path.exists(self.repodir):
177 if os.path.exists(self.repodir):
176 shutil.rmtree(self.repodir)
178 shutil.rmtree(self.repodir)
177 os.chdir(testtmp)
179 os.chdir(testtmp)
178 self.log = []
180 self.log = []
179 self.failed = False
181 self.failed = False
180 self.configperrepo = {}
182 self.configperrepo = {}
181 self.all_extensions = set()
183 self.all_extensions = set()
182 self.non_skippable_extensions = set()
184 self.non_skippable_extensions = set()
183
185
184 self.mkdirp("repos")
186 self.mkdirp("repos")
185 self.cd("repos")
187 self.cd("repos")
186 self.mkdirp("repo1")
188 self.mkdirp("repo1")
187 self.cd("repo1")
189 self.cd("repo1")
188 self.hg("init")
190 self.hg("init")
189
191
190 def teardown(self):
192 def teardown(self):
191 """On teardown we clean up after ourselves as usual, but we also
193 """On teardown we clean up after ourselves as usual, but we also
192 do some additional testing: We generate a .t file based on our test
194 do some additional testing: We generate a .t file based on our test
193 run using run-test.py -i to get the correct output.
195 run using run-test.py -i to get the correct output.
194
196
195 We then test it in a number of other configurations, verifying that
197 We then test it in a number of other configurations, verifying that
196 each passes the same test."""
198 each passes the same test."""
197 super(verifyingstatemachine, self).teardown()
199 super(verifyingstatemachine, self).teardown()
198 try:
200 try:
199 shutil.rmtree(self.repodir)
201 shutil.rmtree(self.repodir)
200 except OSError:
202 except OSError:
201 pass
203 pass
202 ttest = os.linesep.join(" " + l for l in self.log)
204 ttest = os.linesep.join(" " + l for l in self.log)
203 os.chdir(testtmp)
205 os.chdir(testtmp)
204 path = os.path.join(testtmp, "test-generated.t")
206 path = os.path.join(testtmp, "test-generated.t")
205 with open(path, 'w') as o:
207 with open(path, 'w') as o:
206 o.write(ttest + os.linesep)
208 o.write(ttest + os.linesep)
207 with open(os.devnull, "w") as devnull:
209 with open(os.devnull, "w") as devnull:
208 rewriter = subprocess.Popen(
210 rewriter = subprocess.Popen(
209 [runtests, "--local", "-i", path],
211 [runtests, "--local", "-i", path],
210 stdin=subprocess.PIPE,
212 stdin=subprocess.PIPE,
211 stdout=devnull,
213 stdout=devnull,
212 stderr=devnull,
214 stderr=devnull,
213 )
215 )
214 rewriter.communicate("yes")
216 rewriter.communicate("yes")
215 with open(path, 'r') as i:
217 with open(path, 'r') as i:
216 ttest = i.read()
218 ttest = i.read()
217
219
218 e = None
220 e = None
219 if not self.failed:
221 if not self.failed:
220 try:
222 try:
221 output = subprocess.check_output(
223 output = subprocess.check_output(
222 [runtests, path, "--local", "--pure"],
224 [runtests, path, "--local", "--pure"],
223 stderr=subprocess.STDOUT,
225 stderr=subprocess.STDOUT,
224 )
226 )
225 assert "Ran 1 test" in output, output
227 assert "Ran 1 test" in output, output
226 for ext in self.all_extensions - self.non_skippable_extensions:
228 for ext in self.all_extensions - self.non_skippable_extensions:
227 tf = os.path.join(
229 tf = os.path.join(
228 testtmp, "test-generated-no-%s.t" % (ext,)
230 testtmp, "test-generated-no-%s.t" % (ext,)
229 )
231 )
230 with open(tf, 'w') as o:
232 with open(tf, 'w') as o:
231 for l in ttest.splitlines():
233 for l in ttest.splitlines():
232 if l.startswith(" $ hg"):
234 if l.startswith(" $ hg"):
233 l = l.replace(
235 l = l.replace(
234 "--config %s=" % (extensionconfigkey(ext),),
236 "--config %s=" % (extensionconfigkey(ext),),
235 "",
237 "",
236 )
238 )
237 o.write(l + os.linesep)
239 o.write(l + os.linesep)
238 with open(tf, 'r') as r:
240 with open(tf, 'r') as r:
239 t = r.read()
241 t = r.read()
240 assert ext not in t, t
242 assert ext not in t, t
241 output = subprocess.check_output(
243 output = subprocess.check_output(
242 [
244 [
243 runtests,
245 runtests,
244 tf,
246 tf,
245 "--local",
247 "--local",
246 ],
248 ],
247 stderr=subprocess.STDOUT,
249 stderr=subprocess.STDOUT,
248 )
250 )
249 assert "Ran 1 test" in output, output
251 assert "Ran 1 test" in output, output
250 except subprocess.CalledProcessError as e:
252 except subprocess.CalledProcessError as e:
251 note(e.output)
253 note(e.output)
252 if self.failed or e is not None:
254 if self.failed or e is not None:
253 with open(savefile, "wb") as o:
255 with open(savefile, "wb") as o:
254 o.write(ttest)
256 o.write(ttest)
255 if e is not None:
257 if e is not None:
256 raise e
258 raise e
257
259
258 def execute_step(self, step):
260 def execute_step(self, step):
259 try:
261 try:
260 return super(verifyingstatemachine, self).execute_step(step)
262 return super(verifyingstatemachine, self).execute_step(step)
261 except (HypothesisException, KeyboardInterrupt):
263 except (HypothesisException, KeyboardInterrupt):
262 raise
264 raise
263 except Exception:
265 except Exception:
264 self.failed = True
266 self.failed = True
265 raise
267 raise
266
268
267 # Section: Basic commands.
269 # Section: Basic commands.
268 def mkdirp(self, path):
270 def mkdirp(self, path):
269 if os.path.exists(path):
271 if os.path.exists(path):
270 return
272 return
271 self.log.append(
273 self.log.append(
272 "$ mkdir -p -- %s" % (pipes.quote(os.path.relpath(path)),)
274 "$ mkdir -p -- %s" % (pipes.quote(os.path.relpath(path)),)
273 )
275 )
274 os.makedirs(path)
276 os.makedirs(path)
275
277
276 def cd(self, path):
278 def cd(self, path):
277 path = os.path.relpath(path)
279 path = os.path.relpath(path)
278 if path == ".":
280 if path == ".":
279 return
281 return
280 os.chdir(path)
282 os.chdir(path)
281 self.log.append("$ cd -- %s" % (pipes.quote(path),))
283 self.log.append("$ cd -- %s" % (pipes.quote(path),))
282
284
283 def hg(self, *args):
285 def hg(self, *args):
284 extra_flags = []
286 extra_flags = []
285 for key, value in self.config.items():
287 for key, value in self.config.items():
286 extra_flags.append("--config")
288 extra_flags.append("--config")
287 extra_flags.append("%s=%s" % (key, value))
289 extra_flags.append("%s=%s" % (key, value))
288 self.command("hg", *(tuple(extra_flags) + args))
290 self.command("hg", *(tuple(extra_flags) + args))
289
291
290 def command(self, *args):
292 def command(self, *args):
291 self.log.append("$ " + ' '.join(map(pipes.quote, args)))
293 self.log.append("$ " + ' '.join(map(pipes.quote, args)))
292 subprocess.check_output(args, stderr=subprocess.STDOUT)
294 subprocess.check_output(args, stderr=subprocess.STDOUT)
293
295
294 # Section: Set up basic data
296 # Section: Set up basic data
295 # This section has no side effects but generates data that we will want
297 # This section has no side effects but generates data that we will want
296 # to use later.
298 # to use later.
297 @rule(
299 @rule(
298 target=paths,
300 target=paths,
299 source=st.lists(files, min_size=1).map(lambda l: os.path.join(*l)),
301 source=st.lists(files, min_size=1).map(lambda l: os.path.join(*l)),
300 )
302 )
301 def genpath(self, source):
303 def genpath(self, source):
302 return source
304 return source
303
305
304 @rule(
306 @rule(
305 target=committimes,
307 target=committimes,
306 when=datetimes(min_year=1970, max_year=2038) | st.none(),
308 when=datetimes(min_year=1970, max_year=2038) | st.none(),
307 )
309 )
308 def gentime(self, when):
310 def gentime(self, when):
309 return when
311 return when
310
312
311 @rule(
313 @rule(
312 target=contents,
314 target=contents,
313 content=st.one_of(
315 content=st.one_of(
314 st.binary(), st.text().map(lambda x: x.encode('utf-8'))
316 st.binary(), st.text().map(lambda x: x.encode('utf-8'))
315 ),
317 ),
316 )
318 )
317 def gencontent(self, content):
319 def gencontent(self, content):
318 return content
320 return content
319
321
320 @rule(
322 @rule(
321 target=branches,
323 target=branches,
322 name=safetext,
324 name=safetext,
323 )
325 )
324 def genbranch(self, name):
326 def genbranch(self, name):
325 return name
327 return name
326
328
327 @rule(target=paths, source=paths)
329 @rule(target=paths, source=paths)
328 def lowerpath(self, source):
330 def lowerpath(self, source):
329 return source.lower()
331 return source.lower()
330
332
331 @rule(target=paths, source=paths)
333 @rule(target=paths, source=paths)
332 def upperpath(self, source):
334 def upperpath(self, source):
333 return source.upper()
335 return source.upper()
334
336
335 # Section: Basic path operations
337 # Section: Basic path operations
336 @rule(path=paths, content=contents)
338 @rule(path=paths, content=contents)
337 def writecontent(self, path, content):
339 def writecontent(self, path, content):
338 self.unadded_changes = True
340 self.unadded_changes = True
339 if os.path.isdir(path):
341 if os.path.isdir(path):
340 return
342 return
341 parent = os.path.dirname(path)
343 parent = os.path.dirname(path)
342 if parent:
344 if parent:
343 try:
345 try:
344 self.mkdirp(parent)
346 self.mkdirp(parent)
345 except OSError:
347 except OSError:
346 # It may be the case that there is a regular file that has
348 # It may be the case that there is a regular file that has
347 # previously been created that has the same name as an ancestor
349 # previously been created that has the same name as an ancestor
348 # of the current path. This will cause mkdirp to fail with this
350 # of the current path. This will cause mkdirp to fail with this
349 # error. We just turn this into a no-op in that case.
351 # error. We just turn this into a no-op in that case.
350 return
352 return
351 with open(path, 'wb') as o:
353 with open(path, 'wb') as o:
352 o.write(content)
354 o.write(content)
353 self.log.append(
355 self.log.append(
354 (
356 (
355 "$ python -c 'import binascii; "
357 "$ $PYTHON -c 'import binascii; "
356 "print(binascii.unhexlify(\"%s\"))' > %s"
358 "print(binascii.unhexlify(\"%s\"))' > %s"
357 )
359 )
358 % (
360 % (
359 binascii.hexlify(content),
361 binascii.hexlify(content),
360 pipes.quote(path),
362 pipes.quote(path),
361 )
363 )
362 )
364 )
363
365
364 @rule(path=paths)
366 @rule(path=paths)
365 def addpath(self, path):
367 def addpath(self, path):
366 if os.path.exists(path):
368 if os.path.exists(path):
367 self.hg("add", "--", path)
369 self.hg("add", "--", path)
368
370
369 @rule(path=paths)
371 @rule(path=paths)
370 def forgetpath(self, path):
372 def forgetpath(self, path):
371 if os.path.exists(path):
373 if os.path.exists(path):
372 with acceptableerrors(
374 with acceptableerrors(
373 "file is already untracked",
375 "file is already untracked",
374 ):
376 ):
375 self.hg("forget", "--", path)
377 self.hg("forget", "--", path)
376
378
377 @rule(s=st.none() | st.integers(0, 100))
379 @rule(s=st.none() | st.integers(0, 100))
378 def addremove(self, s):
380 def addremove(self, s):
379 args = ["addremove"]
381 args = ["addremove"]
380 if s is not None:
382 if s is not None:
381 args.extend(["-s", str(s)])
383 args.extend(["-s", str(s)])
382 self.hg(*args)
384 self.hg(*args)
383
385
384 @rule(path=paths)
386 @rule(path=paths)
385 def removepath(self, path):
387 def removepath(self, path):
386 if os.path.exists(path):
388 if os.path.exists(path):
387 with acceptableerrors(
389 with acceptableerrors(
388 'file is untracked',
390 'file is untracked',
389 'file has been marked for add',
391 'file has been marked for add',
390 'file is modified',
392 'file is modified',
391 ):
393 ):
392 self.hg("remove", "--", path)
394 self.hg("remove", "--", path)
393
395
394 @rule(
396 @rule(
395 message=safetext,
397 message=safetext,
396 amend=st.booleans(),
398 amend=st.booleans(),
397 when=committimes,
399 when=committimes,
398 addremove=st.booleans(),
400 addremove=st.booleans(),
399 secret=st.booleans(),
401 secret=st.booleans(),
400 close_branch=st.booleans(),
402 close_branch=st.booleans(),
401 )
403 )
402 def maybecommit(
404 def maybecommit(
403 self, message, amend, when, addremove, secret, close_branch
405 self, message, amend, when, addremove, secret, close_branch
404 ):
406 ):
405 command = ["commit"]
407 command = ["commit"]
406 errors = ["nothing changed"]
408 errors = ["nothing changed"]
407 if amend:
409 if amend:
408 errors.append("cannot amend public changesets")
410 errors.append("cannot amend public changesets")
409 command.append("--amend")
411 command.append("--amend")
410 command.append("-m" + pipes.quote(message))
412 command.append("-m" + pipes.quote(message))
411 if secret:
413 if secret:
412 command.append("--secret")
414 command.append("--secret")
413 if close_branch:
415 if close_branch:
414 command.append("--close-branch")
416 command.append("--close-branch")
415 errors.append("can only close branch heads")
417 errors.append("can only close branch heads")
416 if addremove:
418 if addremove:
417 command.append("--addremove")
419 command.append("--addremove")
418 if when is not None:
420 if when is not None:
419 if when.year == 1970:
421 if when.year == 1970:
420 errors.append('negative date value')
422 errors.append('negative date value')
421 if when.year == 2038:
423 if when.year == 2038:
422 errors.append('exceeds 32 bits')
424 errors.append('exceeds 32 bits')
423 command.append(
425 command.append(
424 "--date=%s" % (when.strftime('%Y-%m-%d %H:%M:%S %z'),)
426 "--date=%s" % (when.strftime('%Y-%m-%d %H:%M:%S %z'),)
425 )
427 )
426
428
427 with acceptableerrors(*errors):
429 with acceptableerrors(*errors):
428 self.hg(*command)
430 self.hg(*command)
429
431
430 # Section: Repository management
432 # Section: Repository management
431 @property
433 @property
432 def currentrepo(self):
434 def currentrepo(self):
433 return os.path.basename(os.getcwd())
435 return os.path.basename(os.getcwd())
434
436
435 @property
437 @property
436 def config(self):
438 def config(self):
437 return self.configperrepo.setdefault(self.currentrepo, {})
439 return self.configperrepo.setdefault(self.currentrepo, {})
438
440
439 @rule(
441 @rule(
440 target=repos,
442 target=repos,
441 source=repos,
443 source=repos,
442 name=reponames,
444 name=reponames,
443 )
445 )
444 def clone(self, source, name):
446 def clone(self, source, name):
445 if not os.path.exists(os.path.join("..", name)):
447 if not os.path.exists(os.path.join("..", name)):
446 self.cd("..")
448 self.cd("..")
447 self.hg("clone", source, name)
449 self.hg("clone", source, name)
448 self.cd(name)
450 self.cd(name)
449 return name
451 return name
450
452
451 @rule(
453 @rule(
452 target=repos,
454 target=repos,
453 name=reponames,
455 name=reponames,
454 )
456 )
455 def fresh(self, name):
457 def fresh(self, name):
456 if not os.path.exists(os.path.join("..", name)):
458 if not os.path.exists(os.path.join("..", name)):
457 self.cd("..")
459 self.cd("..")
458 self.mkdirp(name)
460 self.mkdirp(name)
459 self.cd(name)
461 self.cd(name)
460 self.hg("init")
462 self.hg("init")
461 return name
463 return name
462
464
463 @rule(name=repos)
465 @rule(name=repos)
464 def switch(self, name):
466 def switch(self, name):
465 self.cd(os.path.join("..", name))
467 self.cd(os.path.join("..", name))
466 assert self.currentrepo == name
468 assert self.currentrepo == name
467 assert os.path.exists(".hg")
469 assert os.path.exists(".hg")
468
470
469 @rule(target=repos)
471 @rule(target=repos)
470 def origin(self):
472 def origin(self):
471 return "repo1"
473 return "repo1"
472
474
473 @rule()
475 @rule()
474 def pull(self, repo=repos):
476 def pull(self, repo=repos):
475 with acceptableerrors(
477 with acceptableerrors(
476 "repository default not found",
478 "repository default not found",
477 "repository is unrelated",
479 "repository is unrelated",
478 ):
480 ):
479 self.hg("pull")
481 self.hg("pull")
480
482
481 @rule(newbranch=st.booleans())
483 @rule(newbranch=st.booleans())
482 def push(self, newbranch):
484 def push(self, newbranch):
483 with acceptableerrors(
485 with acceptableerrors(
484 "default repository not configured",
486 "default repository not configured",
485 "no changes found",
487 "no changes found",
486 ):
488 ):
487 if newbranch:
489 if newbranch:
488 self.hg("push", "--new-branch")
490 self.hg("push", "--new-branch")
489 else:
491 else:
490 with acceptableerrors("creates new branches"):
492 with acceptableerrors("creates new branches"):
491 self.hg("push")
493 self.hg("push")
492
494
493 # Section: Simple side effect free "check" operations
495 # Section: Simple side effect free "check" operations
494 @rule()
496 @rule()
495 def log(self):
497 def log(self):
496 self.hg("log")
498 self.hg("log")
497
499
498 @rule()
500 @rule()
499 def verify(self):
501 def verify(self):
500 self.hg("verify")
502 self.hg("verify")
501
503
502 @rule()
504 @rule()
503 def diff(self):
505 def diff(self):
504 self.hg("diff", "--nodates")
506 self.hg("diff", "--nodates")
505
507
506 @rule()
508 @rule()
507 def status(self):
509 def status(self):
508 self.hg("status")
510 self.hg("status")
509
511
510 @rule()
512 @rule()
511 def export(self):
513 def export(self):
512 self.hg("export")
514 self.hg("export")
513
515
514 # Section: Branch management
516 # Section: Branch management
515 @rule()
517 @rule()
516 def checkbranch(self):
518 def checkbranch(self):
517 self.hg("branch")
519 self.hg("branch")
518
520
519 @rule(branch=branches)
521 @rule(branch=branches)
520 def switchbranch(self, branch):
522 def switchbranch(self, branch):
521 with acceptableerrors(
523 with acceptableerrors(
522 'cannot use an integer as a name',
524 'cannot use an integer as a name',
523 'cannot be used in a name',
525 'cannot be used in a name',
524 'a branch of the same name already exists',
526 'a branch of the same name already exists',
525 'is reserved',
527 'is reserved',
526 ):
528 ):
527 self.hg("branch", "--", branch)
529 self.hg("branch", "--", branch)
528
530
529 @rule(branch=branches, clean=st.booleans())
531 @rule(branch=branches, clean=st.booleans())
530 def update(self, branch, clean):
532 def update(self, branch, clean):
531 with acceptableerrors(
533 with acceptableerrors(
532 'unknown revision',
534 'unknown revision',
533 'parse error',
535 'parse error',
534 ):
536 ):
535 if clean:
537 if clean:
536 self.hg("update", "-C", "--", branch)
538 self.hg("update", "-C", "--", branch)
537 else:
539 else:
538 self.hg("update", "--", branch)
540 self.hg("update", "--", branch)
539
541
540 # Section: Extension management
542 # Section: Extension management
541 def hasextension(self, extension):
543 def hasextension(self, extension):
542 return extensionconfigkey(extension) in self.config
544 return extensionconfigkey(extension) in self.config
543
545
544 def commandused(self, extension):
546 def commandused(self, extension):
545 assert extension in self.all_extensions
547 assert extension in self.all_extensions
546 self.non_skippable_extensions.add(extension)
548 self.non_skippable_extensions.add(extension)
547
549
548 @rule(extension=extensions)
550 @rule(extension=extensions)
549 def addextension(self, extension):
551 def addextension(self, extension):
550 self.all_extensions.add(extension)
552 self.all_extensions.add(extension)
551 self.config[extensionconfigkey(extension)] = ""
553 self.config[extensionconfigkey(extension)] = ""
552
554
553 @rule(extension=extensions)
555 @rule(extension=extensions)
554 def removeextension(self, extension):
556 def removeextension(self, extension):
555 self.config.pop(extensionconfigkey(extension), None)
557 self.config.pop(extensionconfigkey(extension), None)
556
558
557 # Section: Commands from the shelve extension
559 # Section: Commands from the shelve extension
558 @rule()
560 @rule()
559 @precondition(lambda self: self.hasextension("shelve"))
561 @precondition(lambda self: self.hasextension("shelve"))
560 def shelve(self):
562 def shelve(self):
561 self.commandused("shelve")
563 self.commandused("shelve")
562 with acceptableerrors("nothing changed"):
564 with acceptableerrors("nothing changed"):
563 self.hg("shelve")
565 self.hg("shelve")
564
566
565 @rule()
567 @rule()
566 @precondition(lambda self: self.hasextension("shelve"))
568 @precondition(lambda self: self.hasextension("shelve"))
567 def unshelve(self):
569 def unshelve(self):
568 self.commandused("shelve")
570 self.commandused("shelve")
569 with acceptableerrors("no shelved changes to apply"):
571 with acceptableerrors("no shelved changes to apply"):
570 self.hg("unshelve")
572 self.hg("unshelve")
571
573
572
574
573 class writeonlydatabase(ExampleDatabase):
575 class writeonlydatabase(ExampleDatabase):
574 def __init__(self, underlying):
576 def __init__(self, underlying):
575 super(ExampleDatabase, self).__init__()
577 super(ExampleDatabase, self).__init__()
576 self.underlying = underlying
578 self.underlying = underlying
577
579
578 def fetch(self, key):
580 def fetch(self, key):
579 return ()
581 return ()
580
582
581 def save(self, key, value):
583 def save(self, key, value):
582 self.underlying.save(key, value)
584 self.underlying.save(key, value)
583
585
584 def delete(self, key, value):
586 def delete(self, key, value):
585 self.underlying.delete(key, value)
587 self.underlying.delete(key, value)
586
588
587 def close(self):
589 def close(self):
588 self.underlying.close()
590 self.underlying.close()
589
591
590
592
591 def extensionconfigkey(extension):
593 def extensionconfigkey(extension):
592 return "extensions." + extension
594 return "extensions." + extension
593
595
594
596
595 settings.register_profile(
597 settings.register_profile(
596 'default',
598 'default',
597 settings(
599 settings(
598 timeout=300,
600 timeout=300,
599 stateful_step_count=50,
601 stateful_step_count=50,
600 max_examples=10,
602 max_examples=10,
601 ),
603 ),
602 )
604 )
603
605
604 settings.register_profile(
606 settings.register_profile(
605 'fast',
607 'fast',
606 settings(
608 settings(
607 timeout=10,
609 timeout=10,
608 stateful_step_count=20,
610 stateful_step_count=20,
609 max_examples=5,
611 max_examples=5,
610 min_satisfying_examples=1,
612 min_satisfying_examples=1,
611 max_shrinks=0,
613 max_shrinks=0,
612 ),
614 ),
613 )
615 )
614
616
615 settings.register_profile(
617 settings.register_profile(
616 'continuous',
618 'continuous',
617 settings(
619 settings(
618 timeout=-1,
620 timeout=-1,
619 stateful_step_count=1000,
621 stateful_step_count=1000,
620 max_examples=10 ** 8,
622 max_examples=10 ** 8,
621 max_iterations=10 ** 8,
623 max_iterations=10 ** 8,
622 database=writeonlydatabase(settings.default.database),
624 database=writeonlydatabase(settings.default.database),
623 ),
625 ),
624 )
626 )
625
627
626 settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default'))
628 settings.load_profile(os.getenv('HYPOTHESIS_PROFILE', 'default'))
627
629
628 verifyingtest = verifyingstatemachine.TestCase
630 verifyingtest = verifyingstatemachine.TestCase
629
631
630 verifyingtest.settings = settings.default
632 verifyingtest.settings = settings.default
631
633
632 if __name__ == '__main__':
634 if __name__ == '__main__':
633 try:
635 try:
634 silenttestrunner.main(__name__)
636 silenttestrunner.main(__name__)
635 finally:
637 finally:
636 # So as to prevent proliferation of useless test files, if we never
638 # So as to prevent proliferation of useless test files, if we never
637 # actually wrote a failing test we clean up after ourselves and delete
639 # actually wrote a failing test we clean up after ourselves and delete
638 # the file for doing so that we owned.
640 # the file for doing so that we owned.
639 if os.path.exists(savefile) and os.path.getsize(savefile) == 0:
641 if os.path.exists(savefile) and os.path.getsize(savefile) == 0:
640 os.unlink(savefile)
642 os.unlink(savefile)
General Comments 0
You need to be logged in to leave comments. Login now