##// END OF EJS Templates
merge with stable
Martin von Zweigbergk -
r44838:a69c08cd merge default
parent child Browse files
Show More
@@ -1,714 +1,715 b''
1 # chgserver.py - command server extension for cHg
1 # chgserver.py - command server extension for cHg
2 #
2 #
3 # Copyright 2011 Yuya Nishihara <yuya@tcha.org>
3 # Copyright 2011 Yuya Nishihara <yuya@tcha.org>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """command server extension for cHg
8 """command server extension for cHg
9
9
10 'S' channel (read/write)
10 'S' channel (read/write)
11 propagate ui.system() request to client
11 propagate ui.system() request to client
12
12
13 'attachio' command
13 'attachio' command
14 attach client's stdio passed by sendmsg()
14 attach client's stdio passed by sendmsg()
15
15
16 'chdir' command
16 'chdir' command
17 change current directory
17 change current directory
18
18
19 'setenv' command
19 'setenv' command
20 replace os.environ completely
20 replace os.environ completely
21
21
22 'setumask' command (DEPRECATED)
22 'setumask' command (DEPRECATED)
23 'setumask2' command
23 'setumask2' command
24 set umask
24 set umask
25
25
26 'validate' command
26 'validate' command
27 reload the config and check if the server is up to date
27 reload the config and check if the server is up to date
28
28
29 Config
29 Config
30 ------
30 ------
31
31
32 ::
32 ::
33
33
34 [chgserver]
34 [chgserver]
35 # how long (in seconds) should an idle chg server exit
35 # how long (in seconds) should an idle chg server exit
36 idletimeout = 3600
36 idletimeout = 3600
37
37
38 # whether to skip config or env change checks
38 # whether to skip config or env change checks
39 skiphash = False
39 skiphash = False
40 """
40 """
41
41
42 from __future__ import absolute_import
42 from __future__ import absolute_import
43
43
44 import inspect
44 import inspect
45 import os
45 import os
46 import re
46 import re
47 import socket
47 import socket
48 import stat
48 import stat
49 import struct
49 import struct
50 import time
50 import time
51
51
52 from .i18n import _
52 from .i18n import _
53 from .pycompat import (
53 from .pycompat import (
54 getattr,
54 getattr,
55 setattr,
55 setattr,
56 )
56 )
57
57
58 from . import (
58 from . import (
59 commandserver,
59 commandserver,
60 encoding,
60 encoding,
61 error,
61 error,
62 extensions,
62 extensions,
63 node,
63 node,
64 pycompat,
64 pycompat,
65 util,
65 util,
66 )
66 )
67
67
68 from .utils import (
68 from .utils import (
69 hashutil,
69 hashutil,
70 procutil,
70 procutil,
71 stringutil,
71 stringutil,
72 )
72 )
73
73
74
74
75 def _hashlist(items):
75 def _hashlist(items):
76 """return sha1 hexdigest for a list"""
76 """return sha1 hexdigest for a list"""
77 return node.hex(hashutil.sha1(stringutil.pprint(items)).digest())
77 return node.hex(hashutil.sha1(stringutil.pprint(items)).digest())
78
78
79
79
80 # sensitive config sections affecting confighash
80 # sensitive config sections affecting confighash
81 _configsections = [
81 _configsections = [
82 b'alias', # affects global state commands.table
82 b'alias', # affects global state commands.table
83 b'eol', # uses setconfig('eol', ...)
83 b'eol', # uses setconfig('eol', ...)
84 b'extdiff', # uisetup will register new commands
84 b'extdiff', # uisetup will register new commands
85 b'extensions',
85 b'extensions',
86 b'schemes', # extsetup will update global hg.schemes
86 ]
87 ]
87
88
88 _configsectionitems = [
89 _configsectionitems = [
89 (b'commands', b'show.aliasprefix'), # show.py reads it in extsetup
90 (b'commands', b'show.aliasprefix'), # show.py reads it in extsetup
90 ]
91 ]
91
92
92 # sensitive environment variables affecting confighash
93 # sensitive environment variables affecting confighash
93 _envre = re.compile(
94 _envre = re.compile(
94 br'''\A(?:
95 br'''\A(?:
95 CHGHG
96 CHGHG
96 |HG(?:DEMANDIMPORT|EMITWARNINGS|MODULEPOLICY|PROF|RCPATH)?
97 |HG(?:DEMANDIMPORT|EMITWARNINGS|MODULEPOLICY|PROF|RCPATH)?
97 |HG(?:ENCODING|PLAIN).*
98 |HG(?:ENCODING|PLAIN).*
98 |LANG(?:UAGE)?
99 |LANG(?:UAGE)?
99 |LC_.*
100 |LC_.*
100 |LD_.*
101 |LD_.*
101 |PATH
102 |PATH
102 |PYTHON.*
103 |PYTHON.*
103 |TERM(?:INFO)?
104 |TERM(?:INFO)?
104 |TZ
105 |TZ
105 )\Z''',
106 )\Z''',
106 re.X,
107 re.X,
107 )
108 )
108
109
109
110
110 def _confighash(ui):
111 def _confighash(ui):
111 """return a quick hash for detecting config/env changes
112 """return a quick hash for detecting config/env changes
112
113
113 confighash is the hash of sensitive config items and environment variables.
114 confighash is the hash of sensitive config items and environment variables.
114
115
115 for chgserver, it is designed that once confighash changes, the server is
116 for chgserver, it is designed that once confighash changes, the server is
116 not qualified to serve its client and should redirect the client to a new
117 not qualified to serve its client and should redirect the client to a new
117 server. different from mtimehash, confighash change will not mark the
118 server. different from mtimehash, confighash change will not mark the
118 server outdated and exit since the user can have different configs at the
119 server outdated and exit since the user can have different configs at the
119 same time.
120 same time.
120 """
121 """
121 sectionitems = []
122 sectionitems = []
122 for section in _configsections:
123 for section in _configsections:
123 sectionitems.append(ui.configitems(section))
124 sectionitems.append(ui.configitems(section))
124 for section, item in _configsectionitems:
125 for section, item in _configsectionitems:
125 sectionitems.append(ui.config(section, item))
126 sectionitems.append(ui.config(section, item))
126 sectionhash = _hashlist(sectionitems)
127 sectionhash = _hashlist(sectionitems)
127 # If $CHGHG is set, the change to $HG should not trigger a new chg server
128 # If $CHGHG is set, the change to $HG should not trigger a new chg server
128 if b'CHGHG' in encoding.environ:
129 if b'CHGHG' in encoding.environ:
129 ignored = {b'HG'}
130 ignored = {b'HG'}
130 else:
131 else:
131 ignored = set()
132 ignored = set()
132 envitems = [
133 envitems = [
133 (k, v)
134 (k, v)
134 for k, v in pycompat.iteritems(encoding.environ)
135 for k, v in pycompat.iteritems(encoding.environ)
135 if _envre.match(k) and k not in ignored
136 if _envre.match(k) and k not in ignored
136 ]
137 ]
137 envhash = _hashlist(sorted(envitems))
138 envhash = _hashlist(sorted(envitems))
138 return sectionhash[:6] + envhash[:6]
139 return sectionhash[:6] + envhash[:6]
139
140
140
141
141 def _getmtimepaths(ui):
142 def _getmtimepaths(ui):
142 """get a list of paths that should be checked to detect change
143 """get a list of paths that should be checked to detect change
143
144
144 The list will include:
145 The list will include:
145 - extensions (will not cover all files for complex extensions)
146 - extensions (will not cover all files for complex extensions)
146 - mercurial/__version__.py
147 - mercurial/__version__.py
147 - python binary
148 - python binary
148 """
149 """
149 modules = [m for n, m in extensions.extensions(ui)]
150 modules = [m for n, m in extensions.extensions(ui)]
150 try:
151 try:
151 from . import __version__
152 from . import __version__
152
153
153 modules.append(__version__)
154 modules.append(__version__)
154 except ImportError:
155 except ImportError:
155 pass
156 pass
156 files = []
157 files = []
157 if pycompat.sysexecutable:
158 if pycompat.sysexecutable:
158 files.append(pycompat.sysexecutable)
159 files.append(pycompat.sysexecutable)
159 for m in modules:
160 for m in modules:
160 try:
161 try:
161 files.append(pycompat.fsencode(inspect.getabsfile(m)))
162 files.append(pycompat.fsencode(inspect.getabsfile(m)))
162 except TypeError:
163 except TypeError:
163 pass
164 pass
164 return sorted(set(files))
165 return sorted(set(files))
165
166
166
167
167 def _mtimehash(paths):
168 def _mtimehash(paths):
168 """return a quick hash for detecting file changes
169 """return a quick hash for detecting file changes
169
170
170 mtimehash calls stat on given paths and calculate a hash based on size and
171 mtimehash calls stat on given paths and calculate a hash based on size and
171 mtime of each file. mtimehash does not read file content because reading is
172 mtime of each file. mtimehash does not read file content because reading is
172 expensive. therefore it's not 100% reliable for detecting content changes.
173 expensive. therefore it's not 100% reliable for detecting content changes.
173 it's possible to return different hashes for same file contents.
174 it's possible to return different hashes for same file contents.
174 it's also possible to return a same hash for different file contents for
175 it's also possible to return a same hash for different file contents for
175 some carefully crafted situation.
176 some carefully crafted situation.
176
177
177 for chgserver, it is designed that once mtimehash changes, the server is
178 for chgserver, it is designed that once mtimehash changes, the server is
178 considered outdated immediately and should no longer provide service.
179 considered outdated immediately and should no longer provide service.
179
180
180 mtimehash is not included in confighash because we only know the paths of
181 mtimehash is not included in confighash because we only know the paths of
181 extensions after importing them (there is imp.find_module but that faces
182 extensions after importing them (there is imp.find_module but that faces
182 race conditions). We need to calculate confighash without importing.
183 race conditions). We need to calculate confighash without importing.
183 """
184 """
184
185
185 def trystat(path):
186 def trystat(path):
186 try:
187 try:
187 st = os.stat(path)
188 st = os.stat(path)
188 return (st[stat.ST_MTIME], st.st_size)
189 return (st[stat.ST_MTIME], st.st_size)
189 except OSError:
190 except OSError:
190 # could be ENOENT, EPERM etc. not fatal in any case
191 # could be ENOENT, EPERM etc. not fatal in any case
191 pass
192 pass
192
193
193 return _hashlist(pycompat.maplist(trystat, paths))[:12]
194 return _hashlist(pycompat.maplist(trystat, paths))[:12]
194
195
195
196
196 class hashstate(object):
197 class hashstate(object):
197 """a structure storing confighash, mtimehash, paths used for mtimehash"""
198 """a structure storing confighash, mtimehash, paths used for mtimehash"""
198
199
199 def __init__(self, confighash, mtimehash, mtimepaths):
200 def __init__(self, confighash, mtimehash, mtimepaths):
200 self.confighash = confighash
201 self.confighash = confighash
201 self.mtimehash = mtimehash
202 self.mtimehash = mtimehash
202 self.mtimepaths = mtimepaths
203 self.mtimepaths = mtimepaths
203
204
204 @staticmethod
205 @staticmethod
205 def fromui(ui, mtimepaths=None):
206 def fromui(ui, mtimepaths=None):
206 if mtimepaths is None:
207 if mtimepaths is None:
207 mtimepaths = _getmtimepaths(ui)
208 mtimepaths = _getmtimepaths(ui)
208 confighash = _confighash(ui)
209 confighash = _confighash(ui)
209 mtimehash = _mtimehash(mtimepaths)
210 mtimehash = _mtimehash(mtimepaths)
210 ui.log(
211 ui.log(
211 b'cmdserver',
212 b'cmdserver',
212 b'confighash = %s mtimehash = %s\n',
213 b'confighash = %s mtimehash = %s\n',
213 confighash,
214 confighash,
214 mtimehash,
215 mtimehash,
215 )
216 )
216 return hashstate(confighash, mtimehash, mtimepaths)
217 return hashstate(confighash, mtimehash, mtimepaths)
217
218
218
219
219 def _newchgui(srcui, csystem, attachio):
220 def _newchgui(srcui, csystem, attachio):
220 class chgui(srcui.__class__):
221 class chgui(srcui.__class__):
221 def __init__(self, src=None):
222 def __init__(self, src=None):
222 super(chgui, self).__init__(src)
223 super(chgui, self).__init__(src)
223 if src:
224 if src:
224 self._csystem = getattr(src, '_csystem', csystem)
225 self._csystem = getattr(src, '_csystem', csystem)
225 else:
226 else:
226 self._csystem = csystem
227 self._csystem = csystem
227
228
228 def _runsystem(self, cmd, environ, cwd, out):
229 def _runsystem(self, cmd, environ, cwd, out):
229 # fallback to the original system method if
230 # fallback to the original system method if
230 # a. the output stream is not stdout (e.g. stderr, cStringIO),
231 # a. the output stream is not stdout (e.g. stderr, cStringIO),
231 # b. or stdout is redirected by protectfinout(),
232 # b. or stdout is redirected by protectfinout(),
232 # because the chg client is not aware of these situations and
233 # because the chg client is not aware of these situations and
233 # will behave differently (i.e. write to stdout).
234 # will behave differently (i.e. write to stdout).
234 if (
235 if (
235 out is not self.fout
236 out is not self.fout
236 or not util.safehasattr(self.fout, b'fileno')
237 or not util.safehasattr(self.fout, b'fileno')
237 or self.fout.fileno() != procutil.stdout.fileno()
238 or self.fout.fileno() != procutil.stdout.fileno()
238 or self._finoutredirected
239 or self._finoutredirected
239 ):
240 ):
240 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
241 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
241 self.flush()
242 self.flush()
242 return self._csystem(cmd, procutil.shellenviron(environ), cwd)
243 return self._csystem(cmd, procutil.shellenviron(environ), cwd)
243
244
244 def _runpager(self, cmd, env=None):
245 def _runpager(self, cmd, env=None):
245 self._csystem(
246 self._csystem(
246 cmd,
247 cmd,
247 procutil.shellenviron(env),
248 procutil.shellenviron(env),
248 type=b'pager',
249 type=b'pager',
249 cmdtable={b'attachio': attachio},
250 cmdtable={b'attachio': attachio},
250 )
251 )
251 return True
252 return True
252
253
253 return chgui(srcui)
254 return chgui(srcui)
254
255
255
256
256 def _loadnewui(srcui, args, cdebug):
257 def _loadnewui(srcui, args, cdebug):
257 from . import dispatch # avoid cycle
258 from . import dispatch # avoid cycle
258
259
259 newui = srcui.__class__.load()
260 newui = srcui.__class__.load()
260 for a in [b'fin', b'fout', b'ferr', b'environ']:
261 for a in [b'fin', b'fout', b'ferr', b'environ']:
261 setattr(newui, a, getattr(srcui, a))
262 setattr(newui, a, getattr(srcui, a))
262 if util.safehasattr(srcui, b'_csystem'):
263 if util.safehasattr(srcui, b'_csystem'):
263 newui._csystem = srcui._csystem
264 newui._csystem = srcui._csystem
264
265
265 # command line args
266 # command line args
266 options = dispatch._earlyparseopts(newui, args)
267 options = dispatch._earlyparseopts(newui, args)
267 dispatch._parseconfig(newui, options[b'config'])
268 dispatch._parseconfig(newui, options[b'config'])
268
269
269 # stolen from tortoisehg.util.copydynamicconfig()
270 # stolen from tortoisehg.util.copydynamicconfig()
270 for section, name, value in srcui.walkconfig():
271 for section, name, value in srcui.walkconfig():
271 source = srcui.configsource(section, name)
272 source = srcui.configsource(section, name)
272 if b':' in source or source == b'--config' or source.startswith(b'$'):
273 if b':' in source or source == b'--config' or source.startswith(b'$'):
273 # path:line or command line, or environ
274 # path:line or command line, or environ
274 continue
275 continue
275 newui.setconfig(section, name, value, source)
276 newui.setconfig(section, name, value, source)
276
277
277 # load wd and repo config, copied from dispatch.py
278 # load wd and repo config, copied from dispatch.py
278 cwd = options[b'cwd']
279 cwd = options[b'cwd']
279 cwd = cwd and os.path.realpath(cwd) or None
280 cwd = cwd and os.path.realpath(cwd) or None
280 rpath = options[b'repository']
281 rpath = options[b'repository']
281 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
282 path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
282
283
283 extensions.populateui(newui)
284 extensions.populateui(newui)
284 commandserver.setuplogging(newui, fp=cdebug)
285 commandserver.setuplogging(newui, fp=cdebug)
285 if newui is not newlui:
286 if newui is not newlui:
286 extensions.populateui(newlui)
287 extensions.populateui(newlui)
287 commandserver.setuplogging(newlui, fp=cdebug)
288 commandserver.setuplogging(newlui, fp=cdebug)
288
289
289 return (newui, newlui)
290 return (newui, newlui)
290
291
291
292
292 class channeledsystem(object):
293 class channeledsystem(object):
293 """Propagate ui.system() request in the following format:
294 """Propagate ui.system() request in the following format:
294
295
295 payload length (unsigned int),
296 payload length (unsigned int),
296 type, '\0',
297 type, '\0',
297 cmd, '\0',
298 cmd, '\0',
298 cwd, '\0',
299 cwd, '\0',
299 envkey, '=', val, '\0',
300 envkey, '=', val, '\0',
300 ...
301 ...
301 envkey, '=', val
302 envkey, '=', val
302
303
303 if type == 'system', waits for:
304 if type == 'system', waits for:
304
305
305 exitcode length (unsigned int),
306 exitcode length (unsigned int),
306 exitcode (int)
307 exitcode (int)
307
308
308 if type == 'pager', repetitively waits for a command name ending with '\n'
309 if type == 'pager', repetitively waits for a command name ending with '\n'
309 and executes it defined by cmdtable, or exits the loop if the command name
310 and executes it defined by cmdtable, or exits the loop if the command name
310 is empty.
311 is empty.
311 """
312 """
312
313
313 def __init__(self, in_, out, channel):
314 def __init__(self, in_, out, channel):
314 self.in_ = in_
315 self.in_ = in_
315 self.out = out
316 self.out = out
316 self.channel = channel
317 self.channel = channel
317
318
318 def __call__(self, cmd, environ, cwd=None, type=b'system', cmdtable=None):
319 def __call__(self, cmd, environ, cwd=None, type=b'system', cmdtable=None):
319 args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or b'.')]
320 args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or b'.')]
320 args.extend(b'%s=%s' % (k, v) for k, v in pycompat.iteritems(environ))
321 args.extend(b'%s=%s' % (k, v) for k, v in pycompat.iteritems(environ))
321 data = b'\0'.join(args)
322 data = b'\0'.join(args)
322 self.out.write(struct.pack(b'>cI', self.channel, len(data)))
323 self.out.write(struct.pack(b'>cI', self.channel, len(data)))
323 self.out.write(data)
324 self.out.write(data)
324 self.out.flush()
325 self.out.flush()
325
326
326 if type == b'system':
327 if type == b'system':
327 length = self.in_.read(4)
328 length = self.in_.read(4)
328 (length,) = struct.unpack(b'>I', length)
329 (length,) = struct.unpack(b'>I', length)
329 if length != 4:
330 if length != 4:
330 raise error.Abort(_(b'invalid response'))
331 raise error.Abort(_(b'invalid response'))
331 (rc,) = struct.unpack(b'>i', self.in_.read(4))
332 (rc,) = struct.unpack(b'>i', self.in_.read(4))
332 return rc
333 return rc
333 elif type == b'pager':
334 elif type == b'pager':
334 while True:
335 while True:
335 cmd = self.in_.readline()[:-1]
336 cmd = self.in_.readline()[:-1]
336 if not cmd:
337 if not cmd:
337 break
338 break
338 if cmdtable and cmd in cmdtable:
339 if cmdtable and cmd in cmdtable:
339 cmdtable[cmd]()
340 cmdtable[cmd]()
340 else:
341 else:
341 raise error.Abort(_(b'unexpected command: %s') % cmd)
342 raise error.Abort(_(b'unexpected command: %s') % cmd)
342 else:
343 else:
343 raise error.ProgrammingError(b'invalid S channel type: %s' % type)
344 raise error.ProgrammingError(b'invalid S channel type: %s' % type)
344
345
345
346
346 _iochannels = [
347 _iochannels = [
347 # server.ch, ui.fp, mode
348 # server.ch, ui.fp, mode
348 (b'cin', b'fin', 'rb'),
349 (b'cin', b'fin', 'rb'),
349 (b'cout', b'fout', 'wb'),
350 (b'cout', b'fout', 'wb'),
350 (b'cerr', b'ferr', 'wb'),
351 (b'cerr', b'ferr', 'wb'),
351 ]
352 ]
352
353
353
354
354 class chgcmdserver(commandserver.server):
355 class chgcmdserver(commandserver.server):
355 def __init__(
356 def __init__(
356 self, ui, repo, fin, fout, sock, prereposetups, hashstate, baseaddress
357 self, ui, repo, fin, fout, sock, prereposetups, hashstate, baseaddress
357 ):
358 ):
358 super(chgcmdserver, self).__init__(
359 super(chgcmdserver, self).__init__(
359 _newchgui(ui, channeledsystem(fin, fout, b'S'), self.attachio),
360 _newchgui(ui, channeledsystem(fin, fout, b'S'), self.attachio),
360 repo,
361 repo,
361 fin,
362 fin,
362 fout,
363 fout,
363 prereposetups,
364 prereposetups,
364 )
365 )
365 self.clientsock = sock
366 self.clientsock = sock
366 self._ioattached = False
367 self._ioattached = False
367 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
368 self._oldios = [] # original (self.ch, ui.fp, fd) before "attachio"
368 self.hashstate = hashstate
369 self.hashstate = hashstate
369 self.baseaddress = baseaddress
370 self.baseaddress = baseaddress
370 if hashstate is not None:
371 if hashstate is not None:
371 self.capabilities = self.capabilities.copy()
372 self.capabilities = self.capabilities.copy()
372 self.capabilities[b'validate'] = chgcmdserver.validate
373 self.capabilities[b'validate'] = chgcmdserver.validate
373
374
374 def cleanup(self):
375 def cleanup(self):
375 super(chgcmdserver, self).cleanup()
376 super(chgcmdserver, self).cleanup()
376 # dispatch._runcatch() does not flush outputs if exception is not
377 # dispatch._runcatch() does not flush outputs if exception is not
377 # handled by dispatch._dispatch()
378 # handled by dispatch._dispatch()
378 self.ui.flush()
379 self.ui.flush()
379 self._restoreio()
380 self._restoreio()
380 self._ioattached = False
381 self._ioattached = False
381
382
382 def attachio(self):
383 def attachio(self):
383 """Attach to client's stdio passed via unix domain socket; all
384 """Attach to client's stdio passed via unix domain socket; all
384 channels except cresult will no longer be used
385 channels except cresult will no longer be used
385 """
386 """
386 # tell client to sendmsg() with 1-byte payload, which makes it
387 # tell client to sendmsg() with 1-byte payload, which makes it
387 # distinctive from "attachio\n" command consumed by client.read()
388 # distinctive from "attachio\n" command consumed by client.read()
388 self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
389 self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
389 clientfds = util.recvfds(self.clientsock.fileno())
390 clientfds = util.recvfds(self.clientsock.fileno())
390 self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
391 self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
391
392
392 ui = self.ui
393 ui = self.ui
393 ui.flush()
394 ui.flush()
394 self._saveio()
395 self._saveio()
395 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
396 for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
396 assert fd > 0
397 assert fd > 0
397 fp = getattr(ui, fn)
398 fp = getattr(ui, fn)
398 os.dup2(fd, fp.fileno())
399 os.dup2(fd, fp.fileno())
399 os.close(fd)
400 os.close(fd)
400 if self._ioattached:
401 if self._ioattached:
401 continue
402 continue
402 # reset buffering mode when client is first attached. as we want
403 # reset buffering mode when client is first attached. as we want
403 # to see output immediately on pager, the mode stays unchanged
404 # to see output immediately on pager, the mode stays unchanged
404 # when client re-attached. ferr is unchanged because it should
405 # when client re-attached. ferr is unchanged because it should
405 # be unbuffered no matter if it is a tty or not.
406 # be unbuffered no matter if it is a tty or not.
406 if fn == b'ferr':
407 if fn == b'ferr':
407 newfp = fp
408 newfp = fp
408 else:
409 else:
409 # make it line buffered explicitly because the default is
410 # make it line buffered explicitly because the default is
410 # decided on first write(), where fout could be a pager.
411 # decided on first write(), where fout could be a pager.
411 if fp.isatty():
412 if fp.isatty():
412 bufsize = 1 # line buffered
413 bufsize = 1 # line buffered
413 else:
414 else:
414 bufsize = -1 # system default
415 bufsize = -1 # system default
415 newfp = os.fdopen(fp.fileno(), mode, bufsize)
416 newfp = os.fdopen(fp.fileno(), mode, bufsize)
416 setattr(ui, fn, newfp)
417 setattr(ui, fn, newfp)
417 setattr(self, cn, newfp)
418 setattr(self, cn, newfp)
418
419
419 self._ioattached = True
420 self._ioattached = True
420 self.cresult.write(struct.pack(b'>i', len(clientfds)))
421 self.cresult.write(struct.pack(b'>i', len(clientfds)))
421
422
422 def _saveio(self):
423 def _saveio(self):
423 if self._oldios:
424 if self._oldios:
424 return
425 return
425 ui = self.ui
426 ui = self.ui
426 for cn, fn, _mode in _iochannels:
427 for cn, fn, _mode in _iochannels:
427 ch = getattr(self, cn)
428 ch = getattr(self, cn)
428 fp = getattr(ui, fn)
429 fp = getattr(ui, fn)
429 fd = os.dup(fp.fileno())
430 fd = os.dup(fp.fileno())
430 self._oldios.append((ch, fp, fd))
431 self._oldios.append((ch, fp, fd))
431
432
432 def _restoreio(self):
433 def _restoreio(self):
433 ui = self.ui
434 ui = self.ui
434 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
435 for (ch, fp, fd), (cn, fn, _mode) in zip(self._oldios, _iochannels):
435 newfp = getattr(ui, fn)
436 newfp = getattr(ui, fn)
436 # close newfp while it's associated with client; otherwise it
437 # close newfp while it's associated with client; otherwise it
437 # would be closed when newfp is deleted
438 # would be closed when newfp is deleted
438 if newfp is not fp:
439 if newfp is not fp:
439 newfp.close()
440 newfp.close()
440 # restore original fd: fp is open again
441 # restore original fd: fp is open again
441 os.dup2(fd, fp.fileno())
442 os.dup2(fd, fp.fileno())
442 os.close(fd)
443 os.close(fd)
443 setattr(self, cn, ch)
444 setattr(self, cn, ch)
444 setattr(ui, fn, fp)
445 setattr(ui, fn, fp)
445 del self._oldios[:]
446 del self._oldios[:]
446
447
447 def validate(self):
448 def validate(self):
448 """Reload the config and check if the server is up to date
449 """Reload the config and check if the server is up to date
449
450
450 Read a list of '\0' separated arguments.
451 Read a list of '\0' separated arguments.
451 Write a non-empty list of '\0' separated instruction strings or '\0'
452 Write a non-empty list of '\0' separated instruction strings or '\0'
452 if the list is empty.
453 if the list is empty.
453 An instruction string could be either:
454 An instruction string could be either:
454 - "unlink $path", the client should unlink the path to stop the
455 - "unlink $path", the client should unlink the path to stop the
455 outdated server.
456 outdated server.
456 - "redirect $path", the client should attempt to connect to $path
457 - "redirect $path", the client should attempt to connect to $path
457 first. If it does not work, start a new server. It implies
458 first. If it does not work, start a new server. It implies
458 "reconnect".
459 "reconnect".
459 - "exit $n", the client should exit directly with code n.
460 - "exit $n", the client should exit directly with code n.
460 This may happen if we cannot parse the config.
461 This may happen if we cannot parse the config.
461 - "reconnect", the client should close the connection and
462 - "reconnect", the client should close the connection and
462 reconnect.
463 reconnect.
463 If neither "reconnect" nor "redirect" is included in the instruction
464 If neither "reconnect" nor "redirect" is included in the instruction
464 list, the client can continue with this server after completing all
465 list, the client can continue with this server after completing all
465 the instructions.
466 the instructions.
466 """
467 """
467 from . import dispatch # avoid cycle
468 from . import dispatch # avoid cycle
468
469
469 args = self._readlist()
470 args = self._readlist()
470 try:
471 try:
471 self.ui, lui = _loadnewui(self.ui, args, self.cdebug)
472 self.ui, lui = _loadnewui(self.ui, args, self.cdebug)
472 except error.ParseError as inst:
473 except error.ParseError as inst:
473 dispatch._formatparse(self.ui.warn, inst)
474 dispatch._formatparse(self.ui.warn, inst)
474 self.ui.flush()
475 self.ui.flush()
475 self.cresult.write(b'exit 255')
476 self.cresult.write(b'exit 255')
476 return
477 return
477 except error.Abort as inst:
478 except error.Abort as inst:
478 self.ui.error(_(b"abort: %s\n") % inst)
479 self.ui.error(_(b"abort: %s\n") % inst)
479 if inst.hint:
480 if inst.hint:
480 self.ui.error(_(b"(%s)\n") % inst.hint)
481 self.ui.error(_(b"(%s)\n") % inst.hint)
481 self.ui.flush()
482 self.ui.flush()
482 self.cresult.write(b'exit 255')
483 self.cresult.write(b'exit 255')
483 return
484 return
484 newhash = hashstate.fromui(lui, self.hashstate.mtimepaths)
485 newhash = hashstate.fromui(lui, self.hashstate.mtimepaths)
485 insts = []
486 insts = []
486 if newhash.mtimehash != self.hashstate.mtimehash:
487 if newhash.mtimehash != self.hashstate.mtimehash:
487 addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
488 addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
488 insts.append(b'unlink %s' % addr)
489 insts.append(b'unlink %s' % addr)
489 # mtimehash is empty if one or more extensions fail to load.
490 # mtimehash is empty if one or more extensions fail to load.
490 # to be compatible with hg, still serve the client this time.
491 # to be compatible with hg, still serve the client this time.
491 if self.hashstate.mtimehash:
492 if self.hashstate.mtimehash:
492 insts.append(b'reconnect')
493 insts.append(b'reconnect')
493 if newhash.confighash != self.hashstate.confighash:
494 if newhash.confighash != self.hashstate.confighash:
494 addr = _hashaddress(self.baseaddress, newhash.confighash)
495 addr = _hashaddress(self.baseaddress, newhash.confighash)
495 insts.append(b'redirect %s' % addr)
496 insts.append(b'redirect %s' % addr)
496 self.ui.log(b'chgserver', b'validate: %s\n', stringutil.pprint(insts))
497 self.ui.log(b'chgserver', b'validate: %s\n', stringutil.pprint(insts))
497 self.cresult.write(b'\0'.join(insts) or b'\0')
498 self.cresult.write(b'\0'.join(insts) or b'\0')
498
499
499 def chdir(self):
500 def chdir(self):
500 """Change current directory
501 """Change current directory
501
502
502 Note that the behavior of --cwd option is bit different from this.
503 Note that the behavior of --cwd option is bit different from this.
503 It does not affect --config parameter.
504 It does not affect --config parameter.
504 """
505 """
505 path = self._readstr()
506 path = self._readstr()
506 if not path:
507 if not path:
507 return
508 return
508 self.ui.log(b'chgserver', b"chdir to '%s'\n", path)
509 self.ui.log(b'chgserver', b"chdir to '%s'\n", path)
509 os.chdir(path)
510 os.chdir(path)
510
511
511 def setumask(self):
512 def setumask(self):
512 """Change umask (DEPRECATED)"""
513 """Change umask (DEPRECATED)"""
513 # BUG: this does not follow the message frame structure, but kept for
514 # BUG: this does not follow the message frame structure, but kept for
514 # backward compatibility with old chg clients for some time
515 # backward compatibility with old chg clients for some time
515 self._setumask(self._read(4))
516 self._setumask(self._read(4))
516
517
517 def setumask2(self):
518 def setumask2(self):
518 """Change umask"""
519 """Change umask"""
519 data = self._readstr()
520 data = self._readstr()
520 if len(data) != 4:
521 if len(data) != 4:
521 raise ValueError(b'invalid mask length in setumask2 request')
522 raise ValueError(b'invalid mask length in setumask2 request')
522 self._setumask(data)
523 self._setumask(data)
523
524
524 def _setumask(self, data):
525 def _setumask(self, data):
525 mask = struct.unpack(b'>I', data)[0]
526 mask = struct.unpack(b'>I', data)[0]
526 self.ui.log(b'chgserver', b'setumask %r\n', mask)
527 self.ui.log(b'chgserver', b'setumask %r\n', mask)
527 os.umask(mask)
528 os.umask(mask)
528
529
529 def runcommand(self):
530 def runcommand(self):
530 # pager may be attached within the runcommand session, which should
531 # pager may be attached within the runcommand session, which should
531 # be detached at the end of the session. otherwise the pager wouldn't
532 # be detached at the end of the session. otherwise the pager wouldn't
532 # receive EOF.
533 # receive EOF.
533 globaloldios = self._oldios
534 globaloldios = self._oldios
534 self._oldios = []
535 self._oldios = []
535 try:
536 try:
536 return super(chgcmdserver, self).runcommand()
537 return super(chgcmdserver, self).runcommand()
537 finally:
538 finally:
538 self._restoreio()
539 self._restoreio()
539 self._oldios = globaloldios
540 self._oldios = globaloldios
540
541
541 def setenv(self):
542 def setenv(self):
542 """Clear and update os.environ
543 """Clear and update os.environ
543
544
544 Note that not all variables can make an effect on the running process.
545 Note that not all variables can make an effect on the running process.
545 """
546 """
546 l = self._readlist()
547 l = self._readlist()
547 try:
548 try:
548 newenv = dict(s.split(b'=', 1) for s in l)
549 newenv = dict(s.split(b'=', 1) for s in l)
549 except ValueError:
550 except ValueError:
550 raise ValueError(b'unexpected value in setenv request')
551 raise ValueError(b'unexpected value in setenv request')
551 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys()))
552 self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys()))
552
553
553 encoding.environ.clear()
554 encoding.environ.clear()
554 encoding.environ.update(newenv)
555 encoding.environ.update(newenv)
555
556
556 capabilities = commandserver.server.capabilities.copy()
557 capabilities = commandserver.server.capabilities.copy()
557 capabilities.update(
558 capabilities.update(
558 {
559 {
559 b'attachio': attachio,
560 b'attachio': attachio,
560 b'chdir': chdir,
561 b'chdir': chdir,
561 b'runcommand': runcommand,
562 b'runcommand': runcommand,
562 b'setenv': setenv,
563 b'setenv': setenv,
563 b'setumask': setumask,
564 b'setumask': setumask,
564 b'setumask2': setumask2,
565 b'setumask2': setumask2,
565 }
566 }
566 )
567 )
567
568
568 if util.safehasattr(procutil, b'setprocname'):
569 if util.safehasattr(procutil, b'setprocname'):
569
570
570 def setprocname(self):
571 def setprocname(self):
571 """Change process title"""
572 """Change process title"""
572 name = self._readstr()
573 name = self._readstr()
573 self.ui.log(b'chgserver', b'setprocname: %r\n', name)
574 self.ui.log(b'chgserver', b'setprocname: %r\n', name)
574 procutil.setprocname(name)
575 procutil.setprocname(name)
575
576
576 capabilities[b'setprocname'] = setprocname
577 capabilities[b'setprocname'] = setprocname
577
578
578
579
579 def _tempaddress(address):
580 def _tempaddress(address):
580 return b'%s.%d.tmp' % (address, os.getpid())
581 return b'%s.%d.tmp' % (address, os.getpid())
581
582
582
583
583 def _hashaddress(address, hashstr):
584 def _hashaddress(address, hashstr):
584 # if the basename of address contains '.', use only the left part. this
585 # if the basename of address contains '.', use only the left part. this
585 # makes it possible for the client to pass 'server.tmp$PID' and follow by
586 # makes it possible for the client to pass 'server.tmp$PID' and follow by
586 # an atomic rename to avoid locking when spawning new servers.
587 # an atomic rename to avoid locking when spawning new servers.
587 dirname, basename = os.path.split(address)
588 dirname, basename = os.path.split(address)
588 basename = basename.split(b'.', 1)[0]
589 basename = basename.split(b'.', 1)[0]
589 return b'%s-%s' % (os.path.join(dirname, basename), hashstr)
590 return b'%s-%s' % (os.path.join(dirname, basename), hashstr)
590
591
591
592
592 class chgunixservicehandler(object):
593 class chgunixservicehandler(object):
593 """Set of operations for chg services"""
594 """Set of operations for chg services"""
594
595
595 pollinterval = 1 # [sec]
596 pollinterval = 1 # [sec]
596
597
597 def __init__(self, ui):
598 def __init__(self, ui):
598 self.ui = ui
599 self.ui = ui
599 self._idletimeout = ui.configint(b'chgserver', b'idletimeout')
600 self._idletimeout = ui.configint(b'chgserver', b'idletimeout')
600 self._lastactive = time.time()
601 self._lastactive = time.time()
601
602
602 def bindsocket(self, sock, address):
603 def bindsocket(self, sock, address):
603 self._inithashstate(address)
604 self._inithashstate(address)
604 self._checkextensions()
605 self._checkextensions()
605 self._bind(sock)
606 self._bind(sock)
606 self._createsymlink()
607 self._createsymlink()
607 # no "listening at" message should be printed to simulate hg behavior
608 # no "listening at" message should be printed to simulate hg behavior
608
609
609 def _inithashstate(self, address):
610 def _inithashstate(self, address):
610 self._baseaddress = address
611 self._baseaddress = address
611 if self.ui.configbool(b'chgserver', b'skiphash'):
612 if self.ui.configbool(b'chgserver', b'skiphash'):
612 self._hashstate = None
613 self._hashstate = None
613 self._realaddress = address
614 self._realaddress = address
614 return
615 return
615 self._hashstate = hashstate.fromui(self.ui)
616 self._hashstate = hashstate.fromui(self.ui)
616 self._realaddress = _hashaddress(address, self._hashstate.confighash)
617 self._realaddress = _hashaddress(address, self._hashstate.confighash)
617
618
618 def _checkextensions(self):
619 def _checkextensions(self):
619 if not self._hashstate:
620 if not self._hashstate:
620 return
621 return
621 if extensions.notloaded():
622 if extensions.notloaded():
622 # one or more extensions failed to load. mtimehash becomes
623 # one or more extensions failed to load. mtimehash becomes
623 # meaningless because we do not know the paths of those extensions.
624 # meaningless because we do not know the paths of those extensions.
624 # set mtimehash to an illegal hash value to invalidate the server.
625 # set mtimehash to an illegal hash value to invalidate the server.
625 self._hashstate.mtimehash = b''
626 self._hashstate.mtimehash = b''
626
627
627 def _bind(self, sock):
628 def _bind(self, sock):
628 # use a unique temp address so we can stat the file and do ownership
629 # use a unique temp address so we can stat the file and do ownership
629 # check later
630 # check later
630 tempaddress = _tempaddress(self._realaddress)
631 tempaddress = _tempaddress(self._realaddress)
631 util.bindunixsocket(sock, tempaddress)
632 util.bindunixsocket(sock, tempaddress)
632 self._socketstat = os.stat(tempaddress)
633 self._socketstat = os.stat(tempaddress)
633 sock.listen(socket.SOMAXCONN)
634 sock.listen(socket.SOMAXCONN)
634 # rename will replace the old socket file if exists atomically. the
635 # rename will replace the old socket file if exists atomically. the
635 # old server will detect ownership change and exit.
636 # old server will detect ownership change and exit.
636 util.rename(tempaddress, self._realaddress)
637 util.rename(tempaddress, self._realaddress)
637
638
638 def _createsymlink(self):
639 def _createsymlink(self):
639 if self._baseaddress == self._realaddress:
640 if self._baseaddress == self._realaddress:
640 return
641 return
641 tempaddress = _tempaddress(self._baseaddress)
642 tempaddress = _tempaddress(self._baseaddress)
642 os.symlink(os.path.basename(self._realaddress), tempaddress)
643 os.symlink(os.path.basename(self._realaddress), tempaddress)
643 util.rename(tempaddress, self._baseaddress)
644 util.rename(tempaddress, self._baseaddress)
644
645
645 def _issocketowner(self):
646 def _issocketowner(self):
646 try:
647 try:
647 st = os.stat(self._realaddress)
648 st = os.stat(self._realaddress)
648 return (
649 return (
649 st.st_ino == self._socketstat.st_ino
650 st.st_ino == self._socketstat.st_ino
650 and st[stat.ST_MTIME] == self._socketstat[stat.ST_MTIME]
651 and st[stat.ST_MTIME] == self._socketstat[stat.ST_MTIME]
651 )
652 )
652 except OSError:
653 except OSError:
653 return False
654 return False
654
655
655 def unlinksocket(self, address):
656 def unlinksocket(self, address):
656 if not self._issocketowner():
657 if not self._issocketowner():
657 return
658 return
658 # it is possible to have a race condition here that we may
659 # it is possible to have a race condition here that we may
659 # remove another server's socket file. but that's okay
660 # remove another server's socket file. but that's okay
660 # since that server will detect and exit automatically and
661 # since that server will detect and exit automatically and
661 # the client will start a new server on demand.
662 # the client will start a new server on demand.
662 util.tryunlink(self._realaddress)
663 util.tryunlink(self._realaddress)
663
664
664 def shouldexit(self):
665 def shouldexit(self):
665 if not self._issocketowner():
666 if not self._issocketowner():
666 self.ui.log(
667 self.ui.log(
667 b'chgserver', b'%s is not owned, exiting.\n', self._realaddress
668 b'chgserver', b'%s is not owned, exiting.\n', self._realaddress
668 )
669 )
669 return True
670 return True
670 if time.time() - self._lastactive > self._idletimeout:
671 if time.time() - self._lastactive > self._idletimeout:
671 self.ui.log(b'chgserver', b'being idle too long. exiting.\n')
672 self.ui.log(b'chgserver', b'being idle too long. exiting.\n')
672 return True
673 return True
673 return False
674 return False
674
675
675 def newconnection(self):
676 def newconnection(self):
676 self._lastactive = time.time()
677 self._lastactive = time.time()
677
678
678 def createcmdserver(self, repo, conn, fin, fout, prereposetups):
679 def createcmdserver(self, repo, conn, fin, fout, prereposetups):
679 return chgcmdserver(
680 return chgcmdserver(
680 self.ui,
681 self.ui,
681 repo,
682 repo,
682 fin,
683 fin,
683 fout,
684 fout,
684 conn,
685 conn,
685 prereposetups,
686 prereposetups,
686 self._hashstate,
687 self._hashstate,
687 self._baseaddress,
688 self._baseaddress,
688 )
689 )
689
690
690
691
691 def chgunixservice(ui, repo, opts):
692 def chgunixservice(ui, repo, opts):
692 # CHGINTERNALMARK is set by chg client. It is an indication of things are
693 # CHGINTERNALMARK is set by chg client. It is an indication of things are
693 # started by chg so other code can do things accordingly, like disabling
694 # started by chg so other code can do things accordingly, like disabling
694 # demandimport or detecting chg client started by chg client. When executed
695 # demandimport or detecting chg client started by chg client. When executed
695 # here, CHGINTERNALMARK is no longer useful and hence dropped to make
696 # here, CHGINTERNALMARK is no longer useful and hence dropped to make
696 # environ cleaner.
697 # environ cleaner.
697 if b'CHGINTERNALMARK' in encoding.environ:
698 if b'CHGINTERNALMARK' in encoding.environ:
698 del encoding.environ[b'CHGINTERNALMARK']
699 del encoding.environ[b'CHGINTERNALMARK']
699 # Python3.7+ "coerces" the LC_CTYPE environment variable to a UTF-8 one if
700 # Python3.7+ "coerces" the LC_CTYPE environment variable to a UTF-8 one if
700 # it thinks the current value is "C". This breaks the hash computation and
701 # it thinks the current value is "C". This breaks the hash computation and
701 # causes chg to restart loop.
702 # causes chg to restart loop.
702 if b'CHGORIG_LC_CTYPE' in encoding.environ:
703 if b'CHGORIG_LC_CTYPE' in encoding.environ:
703 encoding.environ[b'LC_CTYPE'] = encoding.environ[b'CHGORIG_LC_CTYPE']
704 encoding.environ[b'LC_CTYPE'] = encoding.environ[b'CHGORIG_LC_CTYPE']
704 del encoding.environ[b'CHGORIG_LC_CTYPE']
705 del encoding.environ[b'CHGORIG_LC_CTYPE']
705 elif b'CHG_CLEAR_LC_CTYPE' in encoding.environ:
706 elif b'CHG_CLEAR_LC_CTYPE' in encoding.environ:
706 if b'LC_CTYPE' in encoding.environ:
707 if b'LC_CTYPE' in encoding.environ:
707 del encoding.environ[b'LC_CTYPE']
708 del encoding.environ[b'LC_CTYPE']
708 del encoding.environ[b'CHG_CLEAR_LC_CTYPE']
709 del encoding.environ[b'CHG_CLEAR_LC_CTYPE']
709
710
710 if repo:
711 if repo:
711 # one chgserver can serve multiple repos. drop repo information
712 # one chgserver can serve multiple repos. drop repo information
712 ui.setconfig(b'bundle', b'mainreporoot', b'', b'repo')
713 ui.setconfig(b'bundle', b'mainreporoot', b'', b'repo')
713 h = chgunixservicehandler(ui)
714 h = chgunixservicehandler(ui)
714 return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)
715 return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)
@@ -1,368 +1,418 b''
1 #require chg
1 #require chg
2
2
3 $ mkdir log
3 $ mkdir log
4 $ cp $HGRCPATH $HGRCPATH.unconfigured
4 $ cp $HGRCPATH $HGRCPATH.unconfigured
5 $ cat <<'EOF' >> $HGRCPATH
5 $ cat <<'EOF' >> $HGRCPATH
6 > [cmdserver]
6 > [cmdserver]
7 > log = $TESTTMP/log/server.log
7 > log = $TESTTMP/log/server.log
8 > max-log-files = 1
8 > max-log-files = 1
9 > max-log-size = 10 kB
9 > max-log-size = 10 kB
10 > EOF
10 > EOF
11 $ cp $HGRCPATH $HGRCPATH.orig
11 $ cp $HGRCPATH $HGRCPATH.orig
12
12
13 $ filterlog () {
13 $ filterlog () {
14 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
14 > sed -e 's!^[0-9/]* [0-9:]* ([0-9]*)>!YYYY/MM/DD HH:MM:SS (PID)>!' \
15 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
15 > -e 's!\(setprocname\|received fds\|setenv\): .*!\1: ...!' \
16 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
16 > -e 's!\(confighash\|mtimehash\) = [0-9a-f]*!\1 = ...!g' \
17 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
17 > -e 's!\(in \)[0-9.]*s\b!\1 ...s!g' \
18 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
18 > -e 's!\(pid\)=[0-9]*!\1=...!g' \
19 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
19 > -e 's!\(/server-\)[0-9a-f]*!\1...!g'
20 > }
20 > }
21
21
22 init repo
22 init repo
23
23
24 $ chg init foo
24 $ chg init foo
25 $ cd foo
25 $ cd foo
26
26
27 ill-formed config
27 ill-formed config
28
28
29 $ chg status
29 $ chg status
30 $ echo '=brokenconfig' >> $HGRCPATH
30 $ echo '=brokenconfig' >> $HGRCPATH
31 $ chg status
31 $ chg status
32 hg: parse error at * (glob)
32 hg: parse error at * (glob)
33 [255]
33 [255]
34
34
35 $ cp $HGRCPATH.orig $HGRCPATH
35 $ cp $HGRCPATH.orig $HGRCPATH
36
36
37 long socket path
37 long socket path
38
38
39 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
39 $ sockpath=$TESTTMP/this/path/should/be/longer/than/one-hundred-and-seven/characters/where/107/is/the/typical/size/limit/of/unix-domain-socket
40 $ mkdir -p $sockpath
40 $ mkdir -p $sockpath
41 $ bakchgsockname=$CHGSOCKNAME
41 $ bakchgsockname=$CHGSOCKNAME
42 $ CHGSOCKNAME=$sockpath/server
42 $ CHGSOCKNAME=$sockpath/server
43 $ export CHGSOCKNAME
43 $ export CHGSOCKNAME
44 $ chg root
44 $ chg root
45 $TESTTMP/foo
45 $TESTTMP/foo
46 $ rm -rf $sockpath
46 $ rm -rf $sockpath
47 $ CHGSOCKNAME=$bakchgsockname
47 $ CHGSOCKNAME=$bakchgsockname
48 $ export CHGSOCKNAME
48 $ export CHGSOCKNAME
49
49
50 $ cd ..
50 $ cd ..
51
51
52 editor
52 editor
53 ------
53 ------
54
54
55 $ cat >> pushbuffer.py <<EOF
55 $ cat >> pushbuffer.py <<EOF
56 > def reposetup(ui, repo):
56 > def reposetup(ui, repo):
57 > repo.ui.pushbuffer(subproc=True)
57 > repo.ui.pushbuffer(subproc=True)
58 > EOF
58 > EOF
59
59
60 $ chg init editor
60 $ chg init editor
61 $ cd editor
61 $ cd editor
62
62
63 by default, system() should be redirected to the client:
63 by default, system() should be redirected to the client:
64
64
65 $ touch foo
65 $ touch foo
66 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
66 $ CHGDEBUG= HGEDITOR=cat chg ci -Am channeled --edit 2>&1 \
67 > | egrep "HG:|run 'cat"
67 > | egrep "HG:|run 'cat"
68 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
68 chg: debug: * run 'cat "*"' at '$TESTTMP/editor' (glob)
69 HG: Enter commit message. Lines beginning with 'HG:' are removed.
69 HG: Enter commit message. Lines beginning with 'HG:' are removed.
70 HG: Leave message empty to abort commit.
70 HG: Leave message empty to abort commit.
71 HG: --
71 HG: --
72 HG: user: test
72 HG: user: test
73 HG: branch 'default'
73 HG: branch 'default'
74 HG: added foo
74 HG: added foo
75
75
76 but no redirection should be made if output is captured:
76 but no redirection should be made if output is captured:
77
77
78 $ touch bar
78 $ touch bar
79 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
79 $ CHGDEBUG= HGEDITOR=cat chg ci -Am bufferred --edit \
80 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
80 > --config extensions.pushbuffer="$TESTTMP/pushbuffer.py" 2>&1 \
81 > | egrep "HG:|run 'cat"
81 > | egrep "HG:|run 'cat"
82 [1]
82 [1]
83
83
84 check that commit commands succeeded:
84 check that commit commands succeeded:
85
85
86 $ hg log -T '{rev}:{desc}\n'
86 $ hg log -T '{rev}:{desc}\n'
87 1:bufferred
87 1:bufferred
88 0:channeled
88 0:channeled
89
89
90 $ cd ..
90 $ cd ..
91
91
92 pager
92 pager
93 -----
93 -----
94
94
95 $ cat >> fakepager.py <<EOF
95 $ cat >> fakepager.py <<EOF
96 > import sys
96 > import sys
97 > for line in sys.stdin:
97 > for line in sys.stdin:
98 > sys.stdout.write('paged! %r\n' % line)
98 > sys.stdout.write('paged! %r\n' % line)
99 > EOF
99 > EOF
100
100
101 enable pager extension globally, but spawns the master server with no tty:
101 enable pager extension globally, but spawns the master server with no tty:
102
102
103 $ chg init pager
103 $ chg init pager
104 $ cd pager
104 $ cd pager
105 $ cat >> $HGRCPATH <<EOF
105 $ cat >> $HGRCPATH <<EOF
106 > [extensions]
106 > [extensions]
107 > pager =
107 > pager =
108 > [pager]
108 > [pager]
109 > pager = "$PYTHON" $TESTTMP/fakepager.py
109 > pager = "$PYTHON" $TESTTMP/fakepager.py
110 > EOF
110 > EOF
111 $ chg version > /dev/null
111 $ chg version > /dev/null
112 $ touch foo
112 $ touch foo
113 $ chg ci -qAm foo
113 $ chg ci -qAm foo
114
114
115 pager should be enabled if the attached client has a tty:
115 pager should be enabled if the attached client has a tty:
116
116
117 $ chg log -l1 -q --config ui.formatted=True
117 $ chg log -l1 -q --config ui.formatted=True
118 paged! '0:1f7b0de80e11\n'
118 paged! '0:1f7b0de80e11\n'
119 $ chg log -l1 -q --config ui.formatted=False
119 $ chg log -l1 -q --config ui.formatted=False
120 0:1f7b0de80e11
120 0:1f7b0de80e11
121
121
122 chg waits for pager if runcommand raises
122 chg waits for pager if runcommand raises
123
123
124 $ cat > $TESTTMP/crash.py <<EOF
124 $ cat > $TESTTMP/crash.py <<EOF
125 > from mercurial import registrar
125 > from mercurial import registrar
126 > cmdtable = {}
126 > cmdtable = {}
127 > command = registrar.command(cmdtable)
127 > command = registrar.command(cmdtable)
128 > @command(b'crash')
128 > @command(b'crash')
129 > def pagercrash(ui, repo, *pats, **opts):
129 > def pagercrash(ui, repo, *pats, **opts):
130 > ui.write(b'going to crash\n')
130 > ui.write(b'going to crash\n')
131 > raise Exception('.')
131 > raise Exception('.')
132 > EOF
132 > EOF
133
133
134 $ cat > $TESTTMP/fakepager.py <<EOF
134 $ cat > $TESTTMP/fakepager.py <<EOF
135 > from __future__ import absolute_import
135 > from __future__ import absolute_import
136 > import sys
136 > import sys
137 > import time
137 > import time
138 > for line in iter(sys.stdin.readline, ''):
138 > for line in iter(sys.stdin.readline, ''):
139 > if 'crash' in line: # only interested in lines containing 'crash'
139 > if 'crash' in line: # only interested in lines containing 'crash'
140 > # if chg exits when pager is sleeping (incorrectly), the output
140 > # if chg exits when pager is sleeping (incorrectly), the output
141 > # will be captured by the next test case
141 > # will be captured by the next test case
142 > time.sleep(1)
142 > time.sleep(1)
143 > sys.stdout.write('crash-pager: %s' % line)
143 > sys.stdout.write('crash-pager: %s' % line)
144 > EOF
144 > EOF
145
145
146 $ cat >> .hg/hgrc <<EOF
146 $ cat >> .hg/hgrc <<EOF
147 > [extensions]
147 > [extensions]
148 > crash = $TESTTMP/crash.py
148 > crash = $TESTTMP/crash.py
149 > EOF
149 > EOF
150
150
151 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
151 $ chg crash --pager=on --config ui.formatted=True 2>/dev/null
152 crash-pager: going to crash
152 crash-pager: going to crash
153 [255]
153 [255]
154
154
155 $ cd ..
155 $ cd ..
156
156
157 server lifecycle
157 server lifecycle
158 ----------------
158 ----------------
159
159
160 chg server should be restarted on code change, and old server will shut down
160 chg server should be restarted on code change, and old server will shut down
161 automatically. In this test, we use the following time parameters:
161 automatically. In this test, we use the following time parameters:
162
162
163 - "sleep 1" to make mtime different
163 - "sleep 1" to make mtime different
164 - "sleep 2" to notice mtime change (polling interval is 1 sec)
164 - "sleep 2" to notice mtime change (polling interval is 1 sec)
165
165
166 set up repository with an extension:
166 set up repository with an extension:
167
167
168 $ chg init extreload
168 $ chg init extreload
169 $ cd extreload
169 $ cd extreload
170 $ touch dummyext.py
170 $ touch dummyext.py
171 $ cat <<EOF >> .hg/hgrc
171 $ cat <<EOF >> .hg/hgrc
172 > [extensions]
172 > [extensions]
173 > dummyext = dummyext.py
173 > dummyext = dummyext.py
174 > EOF
174 > EOF
175
175
176 isolate socket directory for stable result:
176 isolate socket directory for stable result:
177
177
178 $ OLDCHGSOCKNAME=$CHGSOCKNAME
178 $ OLDCHGSOCKNAME=$CHGSOCKNAME
179 $ mkdir chgsock
179 $ mkdir chgsock
180 $ CHGSOCKNAME=`pwd`/chgsock/server
180 $ CHGSOCKNAME=`pwd`/chgsock/server
181
181
182 warm up server:
182 warm up server:
183
183
184 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
184 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
185 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
185 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
186
186
187 new server should be started if extension modified:
187 new server should be started if extension modified:
188
188
189 $ sleep 1
189 $ sleep 1
190 $ touch dummyext.py
190 $ touch dummyext.py
191 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
191 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
192 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
192 chg: debug: * instruction: unlink $TESTTMP/extreload/chgsock/server-* (glob)
193 chg: debug: * instruction: reconnect (glob)
193 chg: debug: * instruction: reconnect (glob)
194 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
194 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
195
195
196 old server will shut down, while new server should still be reachable:
196 old server will shut down, while new server should still be reachable:
197
197
198 $ sleep 2
198 $ sleep 2
199 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
199 $ CHGDEBUG= chg log 2>&1 | (egrep 'instruction|start' || true)
200
200
201 socket file should never be unlinked by old server:
201 socket file should never be unlinked by old server:
202 (simulates unowned socket by updating mtime, which makes sure server exits
202 (simulates unowned socket by updating mtime, which makes sure server exits
203 at polling cycle)
203 at polling cycle)
204
204
205 $ ls chgsock/server-*
205 $ ls chgsock/server-*
206 chgsock/server-* (glob)
206 chgsock/server-* (glob)
207 $ touch chgsock/server-*
207 $ touch chgsock/server-*
208 $ sleep 2
208 $ sleep 2
209 $ ls chgsock/server-*
209 $ ls chgsock/server-*
210 chgsock/server-* (glob)
210 chgsock/server-* (glob)
211
211
212 since no server is reachable from socket file, new server should be started:
212 since no server is reachable from socket file, new server should be started:
213 (this test makes sure that old server shut down automatically)
213 (this test makes sure that old server shut down automatically)
214
214
215 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
215 $ CHGDEBUG= chg log 2>&1 | egrep 'instruction|start'
216 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
216 chg: debug: * start cmdserver at $TESTTMP/extreload/chgsock/server.* (glob)
217
217
218 shut down servers and restore environment:
218 shut down servers and restore environment:
219
219
220 $ rm -R chgsock
220 $ rm -R chgsock
221 $ sleep 2
221 $ sleep 2
222 $ CHGSOCKNAME=$OLDCHGSOCKNAME
222 $ CHGSOCKNAME=$OLDCHGSOCKNAME
223 $ cd ..
223 $ cd ..
224
224
225 check that server events are recorded:
225 check that server events are recorded:
226
226
227 $ ls log
227 $ ls log
228 server.log
228 server.log
229 server.log.1
229 server.log.1
230
230
231 print only the last 10 lines, since we aren't sure how many records are
231 print only the last 10 lines, since we aren't sure how many records are
232 preserved (since setprocname isn't available on py3, the 10th-most-recent line
232 preserved (since setprocname isn't available on py3, the 10th-most-recent line
233 is different when using py3):
233 is different when using py3):
234
234
235 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
235 $ cat log/server.log.1 log/server.log | tail -10 | filterlog
236 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (py3 !)
236 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ... (py3 !)
237 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
237 YYYY/MM/DD HH:MM:SS (PID)> forked worker process (pid=...)
238 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (no-py3 !)
238 YYYY/MM/DD HH:MM:SS (PID)> setprocname: ... (no-py3 !)
239 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
239 YYYY/MM/DD HH:MM:SS (PID)> received fds: ...
240 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
240 YYYY/MM/DD HH:MM:SS (PID)> chdir to '$TESTTMP/extreload'
241 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
241 YYYY/MM/DD HH:MM:SS (PID)> setumask 18
242 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
242 YYYY/MM/DD HH:MM:SS (PID)> setenv: ...
243 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
243 YYYY/MM/DD HH:MM:SS (PID)> confighash = ... mtimehash = ...
244 YYYY/MM/DD HH:MM:SS (PID)> validate: []
244 YYYY/MM/DD HH:MM:SS (PID)> validate: []
245 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
245 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
246 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
246 YYYY/MM/DD HH:MM:SS (PID)> $TESTTMP/extreload/chgsock/server-... is not owned, exiting.
247
247
248 global data mutated by schems
249 -----------------------------
250
251 $ hg init schemes
252 $ cd schemes
253
254 initial state
255
256 $ cat > .hg/hgrc <<'EOF'
257 > [extensions]
258 > schemes =
259 > [schemes]
260 > foo = https://foo.example.org/
261 > EOF
262 $ hg debugexpandscheme foo://expanded
263 https://foo.example.org/expanded
264 $ hg debugexpandscheme bar://unexpanded
265 bar://unexpanded
266
267 add bar
268
269 $ cat > .hg/hgrc <<'EOF'
270 > [extensions]
271 > schemes =
272 > [schemes]
273 > foo = https://foo.example.org/
274 > bar = https://bar.example.org/
275 > EOF
276 $ hg debugexpandscheme foo://expanded
277 https://foo.example.org/expanded
278 $ hg debugexpandscheme bar://expanded
279 https://bar.example.org/expanded
280
281 remove foo
282
283 $ cat > .hg/hgrc <<'EOF'
284 > [extensions]
285 > schemes =
286 > [schemes]
287 > bar = https://bar.example.org/
288 > EOF
289 $ hg debugexpandscheme foo://unexpanded
290 foo://unexpanded
291 $ hg debugexpandscheme bar://expanded
292 https://bar.example.org/expanded
293
294 $ cd ..
295
248 repository cache
296 repository cache
249 ----------------
297 ----------------
250
298
251 $ rm log/server.log*
299 $ rm log/server.log*
252 $ cp $HGRCPATH.unconfigured $HGRCPATH
300 $ cp $HGRCPATH.unconfigured $HGRCPATH
253 $ cat <<'EOF' >> $HGRCPATH
301 $ cat <<'EOF' >> $HGRCPATH
254 > [cmdserver]
302 > [cmdserver]
255 > log = $TESTTMP/log/server.log
303 > log = $TESTTMP/log/server.log
256 > max-repo-cache = 1
304 > max-repo-cache = 1
257 > track-log = command, repocache
305 > track-log = command, repocache
258 > EOF
306 > EOF
259
307
260 isolate socket directory for stable result:
308 isolate socket directory for stable result:
261
309
262 $ OLDCHGSOCKNAME=$CHGSOCKNAME
310 $ OLDCHGSOCKNAME=$CHGSOCKNAME
263 $ mkdir chgsock
311 $ mkdir chgsock
264 $ CHGSOCKNAME=`pwd`/chgsock/server
312 $ CHGSOCKNAME=`pwd`/chgsock/server
265
313
266 create empty repo and cache it:
314 create empty repo and cache it:
267
315
268 $ hg init cached
316 $ hg init cached
269 $ hg id -R cached
317 $ hg id -R cached
270 000000000000 tip
318 000000000000 tip
271 $ sleep 1
319 $ sleep 1
272
320
273 modify repo (and cache will be invalidated):
321 modify repo (and cache will be invalidated):
274
322
275 $ touch cached/a
323 $ touch cached/a
276 $ hg ci -R cached -Am 'add a'
324 $ hg ci -R cached -Am 'add a'
277 adding a
325 adding a
278 $ sleep 1
326 $ sleep 1
279
327
280 read cached repo:
328 read cached repo:
281
329
282 $ hg log -R cached
330 $ hg log -R cached
283 changeset: 0:ac82d8b1f7c4
331 changeset: 0:ac82d8b1f7c4
284 tag: tip
332 tag: tip
285 user: test
333 user: test
286 date: Thu Jan 01 00:00:00 1970 +0000
334 date: Thu Jan 01 00:00:00 1970 +0000
287 summary: add a
335 summary: add a
288
336
289 $ sleep 1
337 $ sleep 1
290
338
291 discard cached from LRU cache:
339 discard cached from LRU cache:
292
340
293 $ hg clone cached cached2
341 $ hg clone cached cached2
294 updating to branch default
342 updating to branch default
295 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
343 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
296 $ hg id -R cached2
344 $ hg id -R cached2
297 ac82d8b1f7c4 tip
345 ac82d8b1f7c4 tip
298 $ sleep 1
346 $ sleep 1
299
347
300 read uncached repo:
348 read uncached repo:
301
349
302 $ hg log -R cached
350 $ hg log -R cached
303 changeset: 0:ac82d8b1f7c4
351 changeset: 0:ac82d8b1f7c4
304 tag: tip
352 tag: tip
305 user: test
353 user: test
306 date: Thu Jan 01 00:00:00 1970 +0000
354 date: Thu Jan 01 00:00:00 1970 +0000
307 summary: add a
355 summary: add a
308
356
309 $ sleep 1
357 $ sleep 1
310
358
311 shut down servers and restore environment:
359 shut down servers and restore environment:
312
360
313 $ rm -R chgsock
361 $ rm -R chgsock
314 $ sleep 2
362 $ sleep 2
315 $ CHGSOCKNAME=$OLDCHGSOCKNAME
363 $ CHGSOCKNAME=$OLDCHGSOCKNAME
316
364
317 check server log:
365 check server log:
318
366
319 $ cat log/server.log | filterlog
367 $ cat log/server.log | filterlog
368 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
369 YYYY/MM/DD HH:MM:SS (PID)> worker process exited (pid=...)
320 YYYY/MM/DD HH:MM:SS (PID)> init cached
370 YYYY/MM/DD HH:MM:SS (PID)> init cached
321 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
371 YYYY/MM/DD HH:MM:SS (PID)> id -R cached
322 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
372 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
323 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
373 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
324 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
374 YYYY/MM/DD HH:MM:SS (PID)> ci -R cached -Am 'add a'
325 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
375 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
326 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
376 YYYY/MM/DD HH:MM:SS (PID)> repo from cache: $TESTTMP/cached
327 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
377 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
328 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
378 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
329 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
379 YYYY/MM/DD HH:MM:SS (PID)> clone cached cached2
330 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
380 YYYY/MM/DD HH:MM:SS (PID)> id -R cached2
331 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
381 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached2 (in ...s)
332 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
382 YYYY/MM/DD HH:MM:SS (PID)> log -R cached
333 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
383 YYYY/MM/DD HH:MM:SS (PID)> loaded repo into cache: $TESTTMP/cached (in ...s)
334
384
335 Test that chg works (sets to the user's actual LC_CTYPE) even when python
385 Test that chg works (sets to the user's actual LC_CTYPE) even when python
336 "coerces" the locale (py3.7+)
386 "coerces" the locale (py3.7+)
337
387
338 $ cat > $TESTTMP/debugenv.py <<EOF
388 $ cat > $TESTTMP/debugenv.py <<EOF
339 > from mercurial import encoding
389 > from mercurial import encoding
340 > from mercurial import registrar
390 > from mercurial import registrar
341 > cmdtable = {}
391 > cmdtable = {}
342 > command = registrar.command(cmdtable)
392 > command = registrar.command(cmdtable)
343 > @command(b'debugenv', [], b'', norepo=True)
393 > @command(b'debugenv', [], b'', norepo=True)
344 > def debugenv(ui):
394 > def debugenv(ui):
345 > for k in [b'LC_ALL', b'LC_CTYPE', b'LANG']:
395 > for k in [b'LC_ALL', b'LC_CTYPE', b'LANG']:
346 > v = encoding.environ.get(k)
396 > v = encoding.environ.get(k)
347 > if v is not None:
397 > if v is not None:
348 > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
398 > ui.write(b'%s=%s\n' % (k, encoding.environ[k]))
349 > EOF
399 > EOF
350 (hg keeps python's modified LC_CTYPE, chg doesn't)
400 (hg keeps python's modified LC_CTYPE, chg doesn't)
351 $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
401 $ (unset LC_ALL; unset LANG; LC_CTYPE= "$CHGHG" \
352 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
402 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
353 LC_CTYPE=C.UTF-8 (py37 !)
403 LC_CTYPE=C.UTF-8 (py37 !)
354 LC_CTYPE= (no-py37 !)
404 LC_CTYPE= (no-py37 !)
355 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
405 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
356 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
406 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
357 LC_CTYPE=
407 LC_CTYPE=
358 $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
408 $ (unset LC_ALL; unset LANG; LC_CTYPE=unsupported_value chg \
359 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
409 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
360 LC_CTYPE=unsupported_value
410 LC_CTYPE=unsupported_value
361 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
411 $ (unset LC_ALL; unset LANG; LC_CTYPE= chg \
362 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
412 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv)
363 LC_CTYPE=
413 LC_CTYPE=
364 $ LANG= LC_ALL= LC_CTYPE= chg \
414 $ LANG= LC_ALL= LC_CTYPE= chg \
365 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv
415 > --config extensions.debugenv=$TESTTMP/debugenv.py debugenv
366 LC_ALL=
416 LC_ALL=
367 LC_CTYPE=
417 LC_CTYPE=
368 LANG=
418 LANG=
@@ -1,194 +1,197 b''
1 #require bzr
1 #require bzr
2
2
3 $ . "$TESTDIR/bzr-definitions"
3 $ . "$TESTDIR/bzr-definitions"
4
4
5 Work around https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=944379
6 $ mkdir -p "${HOME}/.config/breezy"
7
5 empty directory
8 empty directory
6
9
7 $ mkdir test-empty
10 $ mkdir test-empty
8 $ cd test-empty
11 $ cd test-empty
9 $ bzr init -q source
12 $ bzr init -q source
10 $ cd source
13 $ cd source
11 $ echo content > a
14 $ echo content > a
12 $ bzr add -q a
15 $ bzr add -q a
13 $ bzr commit -q -m 'Initial add'
16 $ bzr commit -q -m 'Initial add'
14 $ mkdir empty
17 $ mkdir empty
15 $ bzr add -q empty
18 $ bzr add -q empty
16 $ bzr commit -q -m 'Empty directory added'
19 $ bzr commit -q -m 'Empty directory added'
17 $ echo content > empty/something
20 $ echo content > empty/something
18 $ bzr add -q empty/something
21 $ bzr add -q empty/something
19 $ bzr commit -q -m 'Added file into directory'
22 $ bzr commit -q -m 'Added file into directory'
20 $ cd ..
23 $ cd ..
21 $ hg convert source source-hg
24 $ hg convert source source-hg
22 initializing destination source-hg repository
25 initializing destination source-hg repository
23 scanning source...
26 scanning source...
24 sorting...
27 sorting...
25 converting...
28 converting...
26 2 Initial add
29 2 Initial add
27 1 Empty directory added
30 1 Empty directory added
28 0 Added file into directory
31 0 Added file into directory
29 $ manifest source-hg 1
32 $ manifest source-hg 1
30 % manifest of 1
33 % manifest of 1
31 644 a
34 644 a
32 $ manifest source-hg tip
35 $ manifest source-hg tip
33 % manifest of tip
36 % manifest of tip
34 644 a
37 644 a
35 644 empty/something
38 644 empty/something
36 $ cd ..
39 $ cd ..
37
40
38 directory renames
41 directory renames
39
42
40 $ mkdir test-dir-rename
43 $ mkdir test-dir-rename
41 $ cd test-dir-rename
44 $ cd test-dir-rename
42 $ bzr init -q source
45 $ bzr init -q source
43 $ cd source
46 $ cd source
44 $ mkdir tpyo
47 $ mkdir tpyo
45 $ echo content > tpyo/something
48 $ echo content > tpyo/something
46 $ bzr add -q tpyo
49 $ bzr add -q tpyo
47 $ bzr commit -q -m 'Added directory'
50 $ bzr commit -q -m 'Added directory'
48 $ bzr mv tpyo typo
51 $ bzr mv tpyo typo
49 tpyo => typo
52 tpyo => typo
50 $ bzr commit -q -m 'Oops, typo'
53 $ bzr commit -q -m 'Oops, typo'
51 $ cd ..
54 $ cd ..
52 $ hg convert source source-hg
55 $ hg convert source source-hg
53 initializing destination source-hg repository
56 initializing destination source-hg repository
54 scanning source...
57 scanning source...
55 sorting...
58 sorting...
56 converting...
59 converting...
57 1 Added directory
60 1 Added directory
58 0 Oops, typo
61 0 Oops, typo
59 $ manifest source-hg 0
62 $ manifest source-hg 0
60 % manifest of 0
63 % manifest of 0
61 644 tpyo/something
64 644 tpyo/something
62 $ manifest source-hg tip
65 $ manifest source-hg tip
63 % manifest of tip
66 % manifest of tip
64 644 typo/something
67 644 typo/something
65 $ cd ..
68 $ cd ..
66
69
67 nested directory renames
70 nested directory renames
68
71
69 $ mkdir test-nested-dir-rename
72 $ mkdir test-nested-dir-rename
70 $ cd test-nested-dir-rename
73 $ cd test-nested-dir-rename
71 $ bzr init -q source
74 $ bzr init -q source
72 $ cd source
75 $ cd source
73 $ mkdir -p firstlevel/secondlevel/thirdlevel
76 $ mkdir -p firstlevel/secondlevel/thirdlevel
74 $ echo content > firstlevel/secondlevel/file
77 $ echo content > firstlevel/secondlevel/file
75 $ echo this_needs_to_be_there_too > firstlevel/secondlevel/thirdlevel/stuff
78 $ echo this_needs_to_be_there_too > firstlevel/secondlevel/thirdlevel/stuff
76 $ bzr add -q firstlevel
79 $ bzr add -q firstlevel
77 $ bzr commit -q -m 'Added nested directories'
80 $ bzr commit -q -m 'Added nested directories'
78 $ bzr mv firstlevel/secondlevel secondlevel
81 $ bzr mv firstlevel/secondlevel secondlevel
79 firstlevel/secondlevel => secondlevel
82 firstlevel/secondlevel => secondlevel
80 $ bzr commit -q -m 'Moved secondlevel one level up'
83 $ bzr commit -q -m 'Moved secondlevel one level up'
81 $ cd ..
84 $ cd ..
82 $ hg convert source source-hg
85 $ hg convert source source-hg
83 initializing destination source-hg repository
86 initializing destination source-hg repository
84 scanning source...
87 scanning source...
85 sorting...
88 sorting...
86 converting...
89 converting...
87 1 Added nested directories
90 1 Added nested directories
88 0 Moved secondlevel one level up
91 0 Moved secondlevel one level up
89 $ manifest source-hg tip
92 $ manifest source-hg tip
90 % manifest of tip
93 % manifest of tip
91 644 secondlevel/file
94 644 secondlevel/file
92 644 secondlevel/thirdlevel/stuff
95 644 secondlevel/thirdlevel/stuff
93 $ cd ..
96 $ cd ..
94
97
95 directory remove
98 directory remove
96
99
97 $ mkdir test-dir-remove
100 $ mkdir test-dir-remove
98 $ cd test-dir-remove
101 $ cd test-dir-remove
99 $ bzr init -q source
102 $ bzr init -q source
100 $ cd source
103 $ cd source
101 $ mkdir src
104 $ mkdir src
102 $ echo content > src/sourcecode
105 $ echo content > src/sourcecode
103 $ bzr add -q src
106 $ bzr add -q src
104 $ bzr commit -q -m 'Added directory'
107 $ bzr commit -q -m 'Added directory'
105 $ bzr rm -q src
108 $ bzr rm -q src
106 $ bzr commit -q -m 'Removed directory'
109 $ bzr commit -q -m 'Removed directory'
107 $ cd ..
110 $ cd ..
108 $ hg convert source source-hg
111 $ hg convert source source-hg
109 initializing destination source-hg repository
112 initializing destination source-hg repository
110 scanning source...
113 scanning source...
111 sorting...
114 sorting...
112 converting...
115 converting...
113 1 Added directory
116 1 Added directory
114 0 Removed directory
117 0 Removed directory
115 $ manifest source-hg 0
118 $ manifest source-hg 0
116 % manifest of 0
119 % manifest of 0
117 644 src/sourcecode
120 644 src/sourcecode
118 $ manifest source-hg tip
121 $ manifest source-hg tip
119 % manifest of tip
122 % manifest of tip
120 $ cd ..
123 $ cd ..
121
124
122 directory replace
125 directory replace
123
126
124 $ mkdir test-dir-replace
127 $ mkdir test-dir-replace
125 $ cd test-dir-replace
128 $ cd test-dir-replace
126 $ bzr init -q source
129 $ bzr init -q source
127 $ cd source
130 $ cd source
128 $ mkdir first second
131 $ mkdir first second
129 $ echo content > first/file
132 $ echo content > first/file
130 $ echo morecontent > first/dummy
133 $ echo morecontent > first/dummy
131 $ echo othercontent > second/something
134 $ echo othercontent > second/something
132 $ bzr add -q first second
135 $ bzr add -q first second
133 $ bzr commit -q -m 'Initial layout'
136 $ bzr commit -q -m 'Initial layout'
134 $ bzr mv first/file second/file
137 $ bzr mv first/file second/file
135 first/file => second/file
138 first/file => second/file
136 $ bzr mv first third
139 $ bzr mv first third
137 first => third
140 first => third
138 $ bzr commit -q -m 'Some conflicting moves'
141 $ bzr commit -q -m 'Some conflicting moves'
139 $ cd ..
142 $ cd ..
140 $ hg convert source source-hg
143 $ hg convert source source-hg
141 initializing destination source-hg repository
144 initializing destination source-hg repository
142 scanning source...
145 scanning source...
143 sorting...
146 sorting...
144 converting...
147 converting...
145 1 Initial layout
148 1 Initial layout
146 0 Some conflicting moves
149 0 Some conflicting moves
147 $ manifest source-hg tip
150 $ manifest source-hg tip
148 % manifest of tip
151 % manifest of tip
149 644 second/file
152 644 second/file
150 644 second/something
153 644 second/something
151 644 third/dummy
154 644 third/dummy
152 $ cd ..
155 $ cd ..
153
156
154 divergent nested renames (issue3089)
157 divergent nested renames (issue3089)
155
158
156 $ mkdir test-divergent-renames
159 $ mkdir test-divergent-renames
157 $ cd test-divergent-renames
160 $ cd test-divergent-renames
158 $ bzr init -q source
161 $ bzr init -q source
159 $ cd source
162 $ cd source
160 $ mkdir -p a/c
163 $ mkdir -p a/c
161 $ echo a > a/fa
164 $ echo a > a/fa
162 $ echo c > a/c/fc
165 $ echo c > a/c/fc
163 $ bzr add -q a
166 $ bzr add -q a
164 $ bzr commit -q -m 'Initial layout'
167 $ bzr commit -q -m 'Initial layout'
165 $ bzr mv a b
168 $ bzr mv a b
166 a => b
169 a => b
167 $ mkdir a
170 $ mkdir a
168 $ bzr add a
171 $ bzr add a
169 add(ed|ing) a (re)
172 add(ed|ing) a (re)
170 $ bzr mv b/c a/c
173 $ bzr mv b/c a/c
171 b/c => a/c
174 b/c => a/c
172 $ bzr status
175 $ bzr status
173 added:
176 added:
174 a/
177 a/
175 renamed:
178 renamed:
176 a/? => b/? (re)
179 a/? => b/? (re)
177 a/c/? => a/c/? (re)
180 a/c/? => a/c/? (re)
178 $ bzr commit -q -m 'Divergent renames'
181 $ bzr commit -q -m 'Divergent renames'
179 $ cd ..
182 $ cd ..
180 $ hg convert source source-hg
183 $ hg convert source source-hg
181 initializing destination source-hg repository
184 initializing destination source-hg repository
182 scanning source...
185 scanning source...
183 sorting...
186 sorting...
184 converting...
187 converting...
185 1 Initial layout
188 1 Initial layout
186 0 Divergent renames
189 0 Divergent renames
187 $ hg -R source-hg st -C --change 1
190 $ hg -R source-hg st -C --change 1
188 A b/fa
191 A b/fa
189 a/fa
192 a/fa
190 R a/fa
193 R a/fa
191 $ hg -R source-hg manifest -r 1
194 $ hg -R source-hg manifest -r 1
192 a/c/fc
195 a/c/fc
193 b/fa
196 b/fa
194 $ cd ..
197 $ cd ..
@@ -1,288 +1,288 b''
1 #require bzr
1 #require bzr
2
2
3 $ . "$TESTDIR/bzr-definitions"
3 $ . "$TESTDIR/bzr-definitions"
4
4
5 create and rename on the same file in the same step
5 create and rename on the same file in the same step
6
6
7 $ mkdir test-createandrename
7 $ mkdir test-createandrename
8 $ cd test-createandrename
8 $ cd test-createandrename
9 $ bzr init -q source
9 $ bzr init -q source
10
10
11 test empty repo conversion (issue3233)
11 test empty repo conversion (issue3233)
12
12
13 $ hg convert source source-hg
13 $ hg convert source source-hg
14 initializing destination source-hg repository
14 initializing destination source-hg repository
15 scanning source...
15 scanning source...
16 sorting...
16 sorting...
17 converting...
17 converting...
18
18
19 back to the rename stuff
19 back to the rename stuff
20
20
21 $ cd source
21 $ cd source
22 $ echo a > a
22 $ echo a > a
23 $ echo c > c
23 $ echo c > c
24 $ echo e > e
24 $ echo e > e
25 $ bzr add -q a c e
25 $ bzr add -q a c e
26 $ bzr commit -q -m 'Initial add: a, c, e'
26 $ bzr commit -q -m 'Initial add: a, c, e'
27 $ bzr mv a b
27 $ bzr mv a b
28 a => b
28 a => b
29 $ bzr mv c d
29 $ bzr mv c d
30 c => d
30 c => d
31 $ bzr mv e f
31 $ bzr mv e f
32 e => f
32 e => f
33 $ echo a2 >> a
33 $ echo a2 >> a
34 $ mkdir e
34 $ mkdir e
35 $ bzr add -q a e
35 $ bzr add -q a e
36 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
36 $ bzr commit -q -m 'rename a into b, create a, rename c into d'
37 $ cd ..
37 $ cd ..
38 $ hg convert source source-hg
38 $ hg convert source source-hg
39 scanning source...
39 scanning source...
40 sorting...
40 sorting...
41 converting...
41 converting...
42 1 Initial add: a, c, e
42 1 Initial add: a, c, e
43 0 rename a into b, create a, rename c into d
43 0 rename a into b, create a, rename c into d
44 $ glog -R source-hg
44 $ glog -R source-hg
45 o 1@source "rename a into b, create a, rename c into d" files+: [b d f], files-: [c e], files: [a]
45 o 1@source "rename a into b, create a, rename c into d" files+: [b d f], files-: [c e], files: [a]
46 |
46 |
47 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
47 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
48
48
49
49
50 manifest
50 manifest
51
51
52 $ hg manifest -R source-hg -r tip
52 $ hg manifest -R source-hg -r tip
53 a
53 a
54 b
54 b
55 d
55 d
56 f
56 f
57
57
58 test --rev option
58 test --rev option
59
59
60 $ hg convert -r 1 source source-1-hg
60 $ hg convert -r 1 source source-1-hg
61 initializing destination source-1-hg repository
61 initializing destination source-1-hg repository
62 scanning source...
62 scanning source...
63 sorting...
63 sorting...
64 converting...
64 converting...
65 0 Initial add: a, c, e
65 0 Initial add: a, c, e
66 $ glog -R source-1-hg
66 $ glog -R source-1-hg
67 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
67 o 0@source "Initial add: a, c, e" files+: [a c e], files-: [], files: []
68
68
69
69
70 test with filemap
70 test with filemap
71
71
72 $ cat > filemap <<EOF
72 $ cat > filemap <<EOF
73 > exclude a
73 > exclude a
74 > EOF
74 > EOF
75 $ hg convert --filemap filemap source source-filemap-hg
75 $ hg convert --filemap filemap source source-filemap-hg
76 initializing destination source-filemap-hg repository
76 initializing destination source-filemap-hg repository
77 scanning source...
77 scanning source...
78 sorting...
78 sorting...
79 converting...
79 converting...
80 1 Initial add: a, c, e
80 1 Initial add: a, c, e
81 0 rename a into b, create a, rename c into d
81 0 rename a into b, create a, rename c into d
82 $ hg -R source-filemap-hg manifest -r tip
82 $ hg -R source-filemap-hg manifest -r tip
83 b
83 b
84 d
84 d
85 f
85 f
86
86
87 convert from lightweight checkout
87 convert from lightweight checkout
88
88
89 $ bzr checkout --lightweight source source-light
89 $ bzr checkout --lightweight source source-light
90 $ hg convert -s bzr source-light source-light-hg
90 $ hg convert -s bzr source-light source-light-hg
91 initializing destination source-light-hg repository
91 initializing destination source-light-hg repository
92 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
92 warning: lightweight checkouts may cause conversion failures, try with a regular branch instead.
93 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
93 $TESTTMP/test-createandrename/source-light does not look like a Bazaar repository
94 abort: source-light: missing or unsupported repository
94 abort: source-light: missing or unsupported repository
95 [255]
95 [255]
96
96
97 extract timestamps that look just like hg's {date|isodate}:
97 extract timestamps that look just like hg's {date|isodate}:
98 yyyy-mm-dd HH:MM zzzz (no seconds!)
98 yyyy-mm-dd HH:MM zzzz (no seconds!)
99 compare timestamps
99 compare timestamps
100
100
101 $ cd source
101 $ cd source
102 $ bzr log | \
102 $ bzr log | \
103 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
103 > sed '/timestamp/!d;s/.\{15\}\([0-9: -]\{16\}\):.. \(.[0-9]\{4\}\)/\1 \2/' \
104 > > ../bzr-timestamps
104 > > ../bzr-timestamps
105 $ cd ..
105 $ cd ..
106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
106 $ hg -R source-hg log --template "{date|isodate}\n" > hg-timestamps
107 $ cmp bzr-timestamps hg-timestamps || diff -u bzr-timestamps hg-timestamps
107 $ cmp bzr-timestamps hg-timestamps || diff -u bzr-timestamps hg-timestamps
108 $ cd ..
108 $ cd ..
109
109
110 merge
110 merge
111
111
112 $ mkdir test-merge
112 $ mkdir test-merge
113 $ cd test-merge
113 $ cd test-merge
114 $ cat > helper.py <<EOF
114 $ cat > helper.py <<EOF
115 > import sys
115 > import sys
116 > from bzrlib import workingtree
116 > from bzrlib import workingtree
117 > wt = workingtree.WorkingTree.open('.')
117 > wt = workingtree.WorkingTree.open('.')
118 >
118 >
119 > message, stamp = sys.argv[1:]
119 > message, stamp = sys.argv[1:]
120 > wt.commit(message, timestamp=int(stamp))
120 > wt.commit(message, timestamp=int(stamp))
121 > EOF
121 > EOF
122 $ bzr init -q source
122 $ bzr init -q source
123 $ cd source
123 $ cd source
124 $ echo content > a
124 $ echo content > a
125 $ echo content2 > b
125 $ echo content2 > b
126 $ bzr add -q a b
126 $ bzr add -q a b
127 $ bzr commit -q -m 'Initial add'
127 $ bzr commit -q -m 'Initial add'
128 $ cd ..
128 $ cd ..
129 $ bzr branch -q source source-improve
129 $ bzr branch -q source source-improve
130 $ cd source
130 $ cd source
131 $ echo more >> a
131 $ echo more >> a
132 $ "$PYTHON" ../helper.py 'Editing a' 100
132 $ "$PYTHON" ../helper.py 'Editing a' 100
133 $ cd ../source-improve
133 $ cd ../source-improve
134 $ echo content3 >> b
134 $ echo content3 >> b
135 $ "$PYTHON" ../helper.py 'Editing b' 200
135 $ "$PYTHON" ../helper.py 'Editing b' 200
136 $ cd ../source
136 $ cd ../source
137 $ bzr merge -q ../source-improve
137 $ bzr merge -q ../source-improve
138 $ bzr commit -q -m 'Merged improve branch'
138 $ bzr commit -q -m 'Merged improve branch'
139 $ cd ..
139 $ cd ..
140 $ hg convert --datesort source source-hg
140 $ hg convert --datesort source source-hg
141 initializing destination source-hg repository
141 initializing destination source-hg repository
142 scanning source...
142 scanning source...
143 sorting...
143 sorting...
144 converting...
144 converting...
145 3 Initial add
145 3 Initial add
146 2 Editing a
146 2 Editing a
147 1 Editing b
147 1 Editing b
148 0 Merged improve branch
148 0 Merged improve branch
149 $ glog -R source-hg
149 $ glog -R source-hg
150 o 3@source "Merged improve branch" files+: [], files-: [], files: []
150 o 3@source "Merged improve branch" files+: [], files-: [], files: []
151 |\
151 |\
152 | o 2@source-improve "Editing b" files+: [], files-: [], files: [b]
152 | o 2@source-improve "Editing b" files+: [], files-: [], files: [b]
153 | |
153 | |
154 o | 1@source "Editing a" files+: [], files-: [], files: [a]
154 o | 1@source "Editing a" files+: [], files-: [], files: [a]
155 |/
155 |/
156 o 0@source "Initial add" files+: [a b], files-: [], files: []
156 o 0@source "Initial add" files+: [a b], files-: [], files: []
157
157
158 $ cd ..
158 $ cd ..
159
159
160 #if symlink execbit
160 #if symlink execbit
161
161
162 symlinks and executable files
162 symlinks and executable files
163
163
164 $ mkdir test-symlinks
164 $ mkdir test-symlinks
165 $ cd test-symlinks
165 $ cd test-symlinks
166 $ bzr init -q source
166 $ bzr init -q source
167 $ cd source
167 $ cd source
168 $ touch program
168 $ touch program
169 $ chmod +x program
169 $ chmod +x program
170 $ ln -s program altname
170 $ ln -s program altname
171 $ mkdir d
171 $ mkdir d
172 $ echo a > d/a
172 $ echo a > d/a
173 $ ln -s a syma
173 $ ln -s a syma
174 $ bzr add -q altname program syma d/a
174 $ bzr add -q altname program syma d/a
175 $ bzr commit -q -m 'Initial setup'
175 $ bzr commit -q -m 'Initial setup'
176 $ touch newprog
176 $ touch newprog
177 $ chmod +x newprog
177 $ chmod +x newprog
178 $ rm altname
178 $ rm altname
179 $ ln -s newprog altname
179 $ ln -s newprog altname
180 $ chmod -x program
180 $ chmod -x program
181 $ bzr add -q newprog
181 $ bzr add -q newprog
182 $ bzr commit -q -m 'Symlink changed, x bits changed'
182 $ bzr commit -q -m 'Symlink changed, x bits changed'
183 $ cd ..
183 $ cd ..
184 $ hg convert source source-hg
184 $ hg convert source source-hg
185 initializing destination source-hg repository
185 initializing destination source-hg repository
186 scanning source...
186 scanning source...
187 sorting...
187 sorting...
188 converting...
188 converting...
189 1 Initial setup
189 1 Initial setup
190 0 Symlink changed, x bits changed
190 0 Symlink changed, x bits changed
191 $ manifest source-hg 0
191 $ manifest source-hg 0
192 % manifest of 0
192 % manifest of 0
193 644 @ altname
193 644 @ altname
194 644 d/a
194 644 d/a
195 755 * program
195 755 * program
196 644 @ syma
196 644 @ syma
197 $ manifest source-hg tip
197 $ manifest source-hg tip
198 % manifest of tip
198 % manifest of tip
199 644 @ altname
199 644 @ altname
200 644 d/a
200 644 d/a
201 755 * newprog
201 755 * newprog
202 644 program
202 644 program
203 644 @ syma
203 644 @ syma
204
204
205 test the symlinks can be recreated
205 test the symlinks can be recreated
206
206
207 $ cd source-hg
207 $ cd source-hg
208 $ hg up
208 $ hg up
209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 $ hg cat syma; echo
210 $ hg cat syma; echo
211 a
211 a
212 $ cd ../..
212 $ cd ../..
213
213
214 #endif
214 #endif
215
215
216 Multiple branches
216 Multiple branches
217
217
218 $ bzr init-repo -q --no-trees repo
218 $ bzr init-repo -q --no-trees repo
219 $ bzr init -q repo/trunk
219 $ bzr init -q repo/trunk
220 $ bzr co repo/trunk repo-trunk
220 $ bzr co repo/trunk repo-trunk
221 $ cd repo-trunk
221 $ cd repo-trunk
222 $ echo a > a
222 $ echo a > a
223 $ bzr add -q a
223 $ bzr add -q a
224 $ bzr ci -qm adda
224 $ bzr ci -qm adda
225 $ bzr tag trunk-tag
225 $ bzr tag trunk-tag
226 Created tag trunk-tag.
226 Created tag trunk-tag.
227 $ bzr switch -b branch
227 $ bzr switch -b branch
228 Tree is up to date at revision 1.
228 Tree is up to date at revision 1.
229 Switched to branch: *repo/branch/ (glob)
229 Switched to branch*repo/branch/ (glob)
230 $ sleep 1
230 $ sleep 1
231 $ echo b > b
231 $ echo b > b
232 $ bzr add -q b
232 $ bzr add -q b
233 $ bzr ci -qm addb
233 $ bzr ci -qm addb
234 $ bzr tag branch-tag
234 $ bzr tag branch-tag
235 Created tag branch-tag.
235 Created tag branch-tag.
236 $ bzr switch --force ../repo/trunk
236 $ bzr switch --force ../repo/trunk
237 Updated to revision 1.
237 Updated to revision 1.
238 Switched to branch: */repo/trunk/ (glob)
238 Switched to branch*/repo/trunk/ (glob)
239 $ sleep 1
239 $ sleep 1
240 $ echo a >> a
240 $ echo a >> a
241 $ bzr ci -qm changea
241 $ bzr ci -qm changea
242 $ cd ..
242 $ cd ..
243 $ hg convert --datesort repo repo-bzr
243 $ hg convert --datesort repo repo-bzr
244 initializing destination repo-bzr repository
244 initializing destination repo-bzr repository
245 scanning source...
245 scanning source...
246 sorting...
246 sorting...
247 converting...
247 converting...
248 2 adda
248 2 adda
249 1 addb
249 1 addb
250 0 changea
250 0 changea
251 updating tags
251 updating tags
252 $ (cd repo-bzr; glog)
252 $ (cd repo-bzr; glog)
253 o 3@default "update tags" files+: [.hgtags], files-: [], files: []
253 o 3@default "update tags" files+: [.hgtags], files-: [], files: []
254 |
254 |
255 o 2@default "changea" files+: [], files-: [], files: [a]
255 o 2@default "changea" files+: [], files-: [], files: [a]
256 |
256 |
257 | o 1@branch "addb" files+: [b], files-: [], files: []
257 | o 1@branch "addb" files+: [b], files-: [], files: []
258 |/
258 |/
259 o 0@default "adda" files+: [a], files-: [], files: []
259 o 0@default "adda" files+: [a], files-: [], files: []
260
260
261
261
262 Test tags (converted identifiers are not stable because bzr ones are
262 Test tags (converted identifiers are not stable because bzr ones are
263 not and get incorporated in extra fields).
263 not and get incorporated in extra fields).
264
264
265 $ hg -R repo-bzr tags
265 $ hg -R repo-bzr tags
266 tip 3:* (glob)
266 tip 3:* (glob)
267 branch-tag 1:* (glob)
267 branch-tag 1:* (glob)
268 trunk-tag 0:* (glob)
268 trunk-tag 0:* (glob)
269
269
270 Nested repositories (issue3254)
270 Nested repositories (issue3254)
271
271
272 $ bzr init-repo -q --no-trees repo/inner
272 $ bzr init-repo -q --no-trees repo/inner
273 $ bzr init -q repo/inner/trunk
273 $ bzr init -q repo/inner/trunk
274 $ bzr co repo/inner/trunk inner-trunk
274 $ bzr co repo/inner/trunk inner-trunk
275 $ cd inner-trunk
275 $ cd inner-trunk
276 $ echo b > b
276 $ echo b > b
277 $ bzr add -q b
277 $ bzr add -q b
278 $ bzr ci -qm addb
278 $ bzr ci -qm addb
279 $ cd ..
279 $ cd ..
280 $ hg convert --datesort repo noinner-bzr
280 $ hg convert --datesort repo noinner-bzr
281 initializing destination noinner-bzr repository
281 initializing destination noinner-bzr repository
282 scanning source...
282 scanning source...
283 sorting...
283 sorting...
284 converting...
284 converting...
285 2 adda
285 2 adda
286 1 addb
286 1 addb
287 0 changea
287 0 changea
288 updating tags
288 updating tags
@@ -1,29 +1,29 b''
1 #require no-pure
1 #require no-pure
2
2
3 A script to generate nasty diff worst-case scenarios:
3 A script to generate nasty diff worst-case scenarios:
4
4
5 $ cat > s.py <<EOF
5 $ cat > s.py <<EOF
6 > import random
6 > import random
7 > for x in range(100000):
7 > for x in range(100000):
8 > print
8 > print
9 > if random.randint(0, 100) >= 50:
9 > if random.randint(0, 100) >= 50:
10 > x += 1
10 > x += 1
11 > print(hex(x))
11 > print(hex(x))
12 > EOF
12 > EOF
13
13
14 $ hg init a
14 $ hg init a
15 $ cd a
15 $ cd a
16
16
17 Check in a big file:
17 Check in a big file:
18
18
19 $ "$PYTHON" ../s.py > a
19 $ "$PYTHON" ../s.py > a
20 $ hg ci -qAm0
20 $ hg ci -qAm0
21
21
22 Modify it:
22 Modify it:
23
23
24 $ "$PYTHON" ../s.py > a
24 $ "$PYTHON" ../s.py > a
25
25
26 Time a check-in, should never take more than 10 seconds user time:
26 Time a check-in, should never take more than 10 seconds user time:
27
27
28 $ hg ci --time -m1
28 $ hg ci --time -m1 --config worker.enabled=no
29 time: real .* secs .user [0-9][.].* sys .* (re)
29 time: real .* secs .user [0-9][.].* sys .* (re)
@@ -1,345 +1,357 b''
1 #require no-windows
1 #require no-windows
2
2
3 $ . "$TESTDIR/remotefilelog-library.sh"
3 $ . "$TESTDIR/remotefilelog-library.sh"
4 $ cat >> $HGRCPATH <<EOF
4 $ cat >> $HGRCPATH <<EOF
5 > [devel]
5 > [devel]
6 > remotefilelog.bg-wait=True
6 > remotefilelog.bg-wait=True
7 > EOF
7 > EOF
8
8
9 $ hg init master
9 $ hg init master
10 $ cd master
10 $ cd master
11 $ cat >> .hg/hgrc <<EOF
11 $ cat >> .hg/hgrc <<EOF
12 > [remotefilelog]
12 > [remotefilelog]
13 > server=True
13 > server=True
14 > EOF
14 > EOF
15 $ echo x > x
15 $ echo x > x
16 $ echo z > z
16 $ echo z > z
17 $ hg commit -qAm x
17 $ hg commit -qAm x
18 $ echo x2 > x
18 $ echo x2 > x
19 $ echo y > y
19 $ echo y > y
20 $ hg commit -qAm y
20 $ hg commit -qAm y
21 $ echo w > w
21 $ echo w > w
22 $ rm z
22 $ rm z
23 $ hg commit -qAm w
23 $ hg commit -qAm w
24 $ hg bookmark foo
24 $ hg bookmark foo
25
25
26 $ cd ..
26 $ cd ..
27
27
28 # clone the repo
28 # clone the repo
29
29
30 $ hgcloneshallow ssh://user@dummy/master shallow --noupdate
30 $ hgcloneshallow ssh://user@dummy/master shallow --noupdate
31 streaming all changes
31 streaming all changes
32 2 files to transfer, 776 bytes of data
32 2 files to transfer, 776 bytes of data
33 transferred 776 bytes in * seconds (*/sec) (glob)
33 transferred 776 bytes in * seconds (*/sec) (glob)
34 searching for changes
34 searching for changes
35 no changes found
35 no changes found
36
36
37 # Set the prefetchdays config to zero so that all commits are prefetched
37 # Set the prefetchdays config to zero so that all commits are prefetched
38 # no matter what their creation date is. Also set prefetchdelay config
38 # no matter what their creation date is. Also set prefetchdelay config
39 # to zero so that there is no delay between prefetches.
39 # to zero so that there is no delay between prefetches.
40 $ cd shallow
40 $ cd shallow
41 $ cat >> .hg/hgrc <<EOF
41 $ cat >> .hg/hgrc <<EOF
42 > [remotefilelog]
42 > [remotefilelog]
43 > prefetchdays=0
43 > prefetchdays=0
44 > prefetchdelay=0
44 > prefetchdelay=0
45 > EOF
45 > EOF
46 $ cd ..
46 $ cd ..
47
47
48 # prefetch a revision
48 # prefetch a revision
49 $ cd shallow
49 $ cd shallow
50
50
51 $ hg prefetch -r 0
51 $ hg prefetch -r 0
52 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
52 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
53
53
54 $ hg cat -r 0 x
54 $ hg cat -r 0 x
55 x
55 x
56
56
57 # background prefetch on pull when configured
57 # background prefetch on pull when configured
58
58
59 $ cat >> .hg/hgrc <<EOF
59 $ cat >> .hg/hgrc <<EOF
60 > [remotefilelog]
60 > [remotefilelog]
61 > pullprefetch=bookmark()
61 > pullprefetch=bookmark()
62 > backgroundprefetch=True
62 > backgroundprefetch=True
63 > EOF
63 > EOF
64 $ hg strip tip
64 $ hg strip tip
65 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
65 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
66
66
67 $ clearcache
67 $ clearcache
68 $ hg pull
68 $ hg pull
69 pulling from ssh://user@dummy/master
69 pulling from ssh://user@dummy/master
70 searching for changes
70 searching for changes
71 adding changesets
71 adding changesets
72 adding manifests
72 adding manifests
73 adding file changes
73 adding file changes
74 updating bookmark foo
74 updating bookmark foo
75 added 1 changesets with 0 changes to 0 files
75 added 1 changesets with 0 changes to 0 files
76 new changesets 6b4b6f66ef8c
76 new changesets 6b4b6f66ef8c
77 (run 'hg update' to get a working copy)
77 (run 'hg update' to get a working copy)
78 prefetching file contents
78 prefetching file contents
79 $ find $CACHEDIR -type f | sort
79 $ find $CACHEDIR -type f | sort
80 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/ef95c5376f34698742fe34f315fd82136f8f68c0
80 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/ef95c5376f34698742fe34f315fd82136f8f68c0
81 $TESTTMP/hgcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca
81 $TESTTMP/hgcache/master/95/cb0bfd2977c761298d9624e4b4d4c72a39974a/076f5e2225b3ff0400b98c92aa6cdf403ee24cca
82 $TESTTMP/hgcache/master/af/f024fe4ab0fece4091de044c58c9ae4233383a/bb6ccd5dceaa5e9dc220e0dad65e051b94f69a2c
82 $TESTTMP/hgcache/master/af/f024fe4ab0fece4091de044c58c9ae4233383a/bb6ccd5dceaa5e9dc220e0dad65e051b94f69a2c
83 $TESTTMP/hgcache/repos
83 $TESTTMP/hgcache/repos
84
84
85 # background prefetch with repack on pull when configured
85 # background prefetch with repack on pull when configured
86
86
87 $ cat >> .hg/hgrc <<EOF
87 $ cat >> .hg/hgrc <<EOF
88 > [remotefilelog]
88 > [remotefilelog]
89 > backgroundrepack=True
89 > backgroundrepack=True
90 > EOF
90 > EOF
91 $ hg strip tip
91 $ hg strip tip
92 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
92 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/6b4b6f66ef8c-b4b8bdaf-backup.hg (glob)
93
93
94 $ clearcache
94 $ clearcache
95 $ hg pull
95 $ hg pull
96 pulling from ssh://user@dummy/master
96 pulling from ssh://user@dummy/master
97 searching for changes
97 searching for changes
98 adding changesets
98 adding changesets
99 adding manifests
99 adding manifests
100 adding file changes
100 adding file changes
101 updating bookmark foo
101 updating bookmark foo
102 added 1 changesets with 0 changes to 0 files
102 added 1 changesets with 0 changes to 0 files
103 new changesets 6b4b6f66ef8c
103 new changesets 6b4b6f66ef8c
104 (run 'hg update' to get a working copy)
104 (run 'hg update' to get a working copy)
105 prefetching file contents
105 prefetching file contents
106 $ find $CACHEDIR -type f | sort
106 $ find $CACHEDIR -type f | sort
107 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histidx
107 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histidx
108 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histpack
108 $TESTTMP/hgcache/master/packs/6e8633deba6e544e5f8edbd7b996d6e31a2c42ae.histpack
109 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.dataidx
109 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.dataidx
110 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.datapack
110 $TESTTMP/hgcache/master/packs/8ce5ab3745465ab83bba30a7b9c295e0c8404652.datapack
111 $TESTTMP/hgcache/repos
111 $TESTTMP/hgcache/repos
112
112
113 # background prefetch with repack on update when wcprevset configured
113 # background prefetch with repack on update when wcprevset configured
114
114
115 $ clearcache
115 $ clearcache
116 $ hg up -r 0
116 $ hg up -r 0
117 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
118 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
118 2 files fetched over 1 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
119 $ find $CACHEDIR -type f | sort
119 $ find $CACHEDIR -type f | sort
120 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0
120 $TESTTMP/hgcache/master/11/f6ad8ec52a2984abaafd7c3b516503785c2072/1406e74118627694268417491f018a4a883152f0
121 $TESTTMP/hgcache/master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a
121 $TESTTMP/hgcache/master/39/5df8f7c51f007019cb30201c49e884b46b92fa/69a1b67522704ec122181c0890bd16e9d3e7516a
122 $TESTTMP/hgcache/repos
122 $TESTTMP/hgcache/repos
123
123
124 $ hg up -r 1
124 $ hg up -r 1
125 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
125 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
126 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
126 2 files fetched over 2 fetches - (2 misses, 0.00% hit ratio) over *s (glob)
127
127
128 $ cat >> .hg/hgrc <<EOF
128 $ cat >> .hg/hgrc <<EOF
129 > [remotefilelog]
129 > [remotefilelog]
130 > bgprefetchrevs=.::
130 > bgprefetchrevs=.::
131 > EOF
131 > EOF
132
132
133 $ clearcache
133 $ clearcache
134 $ hg up -r 0
134 $ hg up -r 0
135 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
135 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
136 * files fetched over * fetches - (* misses, 0.00% hit ratio) over *s (glob)
136 * files fetched over * fetches - (* misses, 0.00% hit ratio) over *s (glob)
137 $ find $CACHEDIR -type f | sort
137 $ find $CACHEDIR -type f | sort
138 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
138 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
139 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
139 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
140 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
140 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
141 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
141 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
142 $TESTTMP/hgcache/repos
142 $TESTTMP/hgcache/repos
143
143
144 # Ensure that file 'w' was prefetched - it was not part of the update operation and therefore
144 # Ensure that file 'w' was prefetched - it was not part of the update operation and therefore
145 # could only be downloaded by the background prefetch
145 # could only be downloaded by the background prefetch
146
146
147 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
147 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
148 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
148 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
149 w:
149 w:
150 Node Delta Base Delta Length Blob Size
150 Node Delta Base Delta Length Blob Size
151 bb6ccd5dceaa 000000000000 2 2
151 bb6ccd5dceaa 000000000000 2 2
152
152
153 Total: 2 2 (0.0% bigger)
153 Total: 2 2 (0.0% bigger)
154 x:
154 x:
155 Node Delta Base Delta Length Blob Size
155 Node Delta Base Delta Length Blob Size
156 ef95c5376f34 000000000000 3 3
156 ef95c5376f34 000000000000 3 3
157 1406e7411862 ef95c5376f34 14 2
157 1406e7411862 ef95c5376f34 14 2
158
158
159 Total: 17 5 (240.0% bigger)
159 Total: 17 5 (240.0% bigger)
160 y:
160 y:
161 Node Delta Base Delta Length Blob Size
161 Node Delta Base Delta Length Blob Size
162 076f5e2225b3 000000000000 2 2
162 076f5e2225b3 000000000000 2 2
163
163
164 Total: 2 2 (0.0% bigger)
164 Total: 2 2 (0.0% bigger)
165 z:
165 z:
166 Node Delta Base Delta Length Blob Size
166 Node Delta Base Delta Length Blob Size
167 69a1b6752270 000000000000 2 2
167 69a1b6752270 000000000000 2 2
168
168
169 Total: 2 2 (0.0% bigger)
169 Total: 2 2 (0.0% bigger)
170
170
171 # background prefetch with repack on commit when wcprevset configured
171 # background prefetch with repack on commit when wcprevset configured
172
172
173 $ cat >> .hg/hgrc <<EOF
173 $ cat >> .hg/hgrc <<EOF
174 > [remotefilelog]
174 > [remotefilelog]
175 > bgprefetchrevs=0::
175 > bgprefetchrevs=0::
176 > EOF
176 > EOF
177
177
178 $ clearcache
178 $ clearcache
179 $ find $CACHEDIR -type f | sort
179 $ find $CACHEDIR -type f | sort
180 $ echo b > b
180 $ echo b > b
181 .. The following output line about files fetches is globed because it is
182 .. flaky, the core the test is checked when checking the cache dir, so
183 .. hopefully this flakyness is not hiding any actual bug.
181 $ hg commit -qAm b
184 $ hg commit -qAm b
182 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob)
185 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
183 $ hg bookmark temporary
186 $ hg bookmark temporary
184 $ find $CACHEDIR -type f | sort
187 $ find $CACHEDIR -type f | sort
185 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
188 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
186 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
189 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
187 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
190 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
188 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
191 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
189 $TESTTMP/hgcache/repos
192 $TESTTMP/hgcache/repos
190
193
191 # Ensure that file 'w' was prefetched - it was not part of the commit operation and therefore
194 # Ensure that file 'w' was prefetched - it was not part of the commit operation and therefore
192 # could only be downloaded by the background prefetch
195 # could only be downloaded by the background prefetch
193
196
194 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
197 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
195 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
198 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
196 w:
199 w:
197 Node Delta Base Delta Length Blob Size
200 Node Delta Base Delta Length Blob Size
198 bb6ccd5dceaa 000000000000 2 2
201 bb6ccd5dceaa 000000000000 2 2
199
202
200 Total: 2 2 (0.0% bigger)
203 Total: 2 2 (0.0% bigger)
201 x:
204 x:
202 Node Delta Base Delta Length Blob Size
205 Node Delta Base Delta Length Blob Size
203 ef95c5376f34 000000000000 3 3
206 ef95c5376f34 000000000000 3 3
204 1406e7411862 ef95c5376f34 14 2
207 1406e7411862 ef95c5376f34 14 2
205
208
206 Total: 17 5 (240.0% bigger)
209 Total: 17 5 (240.0% bigger)
207 y:
210 y:
208 Node Delta Base Delta Length Blob Size
211 Node Delta Base Delta Length Blob Size
209 076f5e2225b3 000000000000 2 2
212 076f5e2225b3 000000000000 2 2
210
213
211 Total: 2 2 (0.0% bigger)
214 Total: 2 2 (0.0% bigger)
212 z:
215 z:
213 Node Delta Base Delta Length Blob Size
216 Node Delta Base Delta Length Blob Size
214 69a1b6752270 000000000000 2 2
217 69a1b6752270 000000000000 2 2
215
218
216 Total: 2 2 (0.0% bigger)
219 Total: 2 2 (0.0% bigger)
217
220
218 # background prefetch with repack on rebase when wcprevset configured
221 # background prefetch with repack on rebase when wcprevset configured
219
222
220 $ hg up -r 2
223 $ hg up -r 2
221 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
224 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
222 (leaving bookmark temporary)
225 (leaving bookmark temporary)
223 $ clearcache
226 $ clearcache
224 $ find $CACHEDIR -type f | sort
227 $ find $CACHEDIR -type f | sort
228 .. The following output line about files fetches is globed because it is
229 .. flaky, the core the test is checked when checking the cache dir, so
230 .. hopefully this flakyness is not hiding any actual bug.
225 $ hg rebase -s temporary -d foo
231 $ hg rebase -s temporary -d foo
226 rebasing 3:d9cf06e3b5b6 "b" (temporary tip)
232 rebasing 3:d9cf06e3b5b6 "b" (temporary tip)
227 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/d9cf06e3b5b6-e5c3dc63-rebase.hg
233 saved backup bundle to $TESTTMP/shallow/.hg/strip-backup/d9cf06e3b5b6-e5c3dc63-rebase.hg
228 3 files fetched over 1 fetches - (3 misses, 0.00% hit ratio) over *s (glob)
234 ? files fetched over ? fetches - (? misses, 0.00% hit ratio) over *s (glob)
235 $ find $CACHEDIR -type f | sort
236 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
237 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
238 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
239 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
240 $TESTTMP/hgcache/repos
229
241
230 # Ensure that file 'y' was prefetched - it was not part of the rebase operation and therefore
242 # Ensure that file 'y' was prefetched - it was not part of the rebase operation and therefore
231 # could only be downloaded by the background prefetch
243 # could only be downloaded by the background prefetch
232
244
233 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
245 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
234 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
246 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
235 w:
247 w:
236 Node Delta Base Delta Length Blob Size
248 Node Delta Base Delta Length Blob Size
237 bb6ccd5dceaa 000000000000 2 2
249 bb6ccd5dceaa 000000000000 2 2
238
250
239 Total: 2 2 (0.0% bigger)
251 Total: 2 2 (0.0% bigger)
240 x:
252 x:
241 Node Delta Base Delta Length Blob Size
253 Node Delta Base Delta Length Blob Size
242 ef95c5376f34 000000000000 3 3
254 ef95c5376f34 000000000000 3 3
243 1406e7411862 ef95c5376f34 14 2
255 1406e7411862 ef95c5376f34 14 2
244
256
245 Total: 17 5 (240.0% bigger)
257 Total: 17 5 (240.0% bigger)
246 y:
258 y:
247 Node Delta Base Delta Length Blob Size
259 Node Delta Base Delta Length Blob Size
248 076f5e2225b3 000000000000 2 2
260 076f5e2225b3 000000000000 2 2
249
261
250 Total: 2 2 (0.0% bigger)
262 Total: 2 2 (0.0% bigger)
251 z:
263 z:
252 Node Delta Base Delta Length Blob Size
264 Node Delta Base Delta Length Blob Size
253 69a1b6752270 000000000000 2 2
265 69a1b6752270 000000000000 2 2
254
266
255 Total: 2 2 (0.0% bigger)
267 Total: 2 2 (0.0% bigger)
256
268
257 # Check that foregound prefetch with no arguments blocks until background prefetches finish
269 # Check that foregound prefetch with no arguments blocks until background prefetches finish
258
270
259 $ hg up -r 3
271 $ hg up -r 3
260 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
272 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
261 $ clearcache
273 $ clearcache
262 $ hg prefetch --repack
274 $ hg prefetch --repack
263 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
275 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
264 got lock after * seconds (glob) (?)
276 got lock after * seconds (glob) (?)
265 (running background incremental repack)
277 (running background incremental repack)
266 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
278 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
267
279
268 $ find $CACHEDIR -type f | sort
280 $ find $CACHEDIR -type f | sort
269 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
281 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
270 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
282 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
271 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
283 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
272 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
284 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
273 $TESTTMP/hgcache/repos
285 $TESTTMP/hgcache/repos
274
286
275 # Ensure that files were prefetched
287 # Ensure that files were prefetched
276 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
288 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
277 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
289 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
278 w:
290 w:
279 Node Delta Base Delta Length Blob Size
291 Node Delta Base Delta Length Blob Size
280 bb6ccd5dceaa 000000000000 2 2
292 bb6ccd5dceaa 000000000000 2 2
281
293
282 Total: 2 2 (0.0% bigger)
294 Total: 2 2 (0.0% bigger)
283 x:
295 x:
284 Node Delta Base Delta Length Blob Size
296 Node Delta Base Delta Length Blob Size
285 ef95c5376f34 000000000000 3 3
297 ef95c5376f34 000000000000 3 3
286 1406e7411862 ef95c5376f34 14 2
298 1406e7411862 ef95c5376f34 14 2
287
299
288 Total: 17 5 (240.0% bigger)
300 Total: 17 5 (240.0% bigger)
289 y:
301 y:
290 Node Delta Base Delta Length Blob Size
302 Node Delta Base Delta Length Blob Size
291 076f5e2225b3 000000000000 2 2
303 076f5e2225b3 000000000000 2 2
292
304
293 Total: 2 2 (0.0% bigger)
305 Total: 2 2 (0.0% bigger)
294 z:
306 z:
295 Node Delta Base Delta Length Blob Size
307 Node Delta Base Delta Length Blob Size
296 69a1b6752270 000000000000 2 2
308 69a1b6752270 000000000000 2 2
297
309
298 Total: 2 2 (0.0% bigger)
310 Total: 2 2 (0.0% bigger)
299
311
300 # Check that foreground prefetch fetches revs specified by '. + draft() + bgprefetchrevs + pullprefetch'
312 # Check that foreground prefetch fetches revs specified by '. + draft() + bgprefetchrevs + pullprefetch'
301
313
302 $ clearcache
314 $ clearcache
303 $ hg prefetch --repack
315 $ hg prefetch --repack
304 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
316 waiting for lock on prefetching in $TESTTMP/shallow held by process * on host * (glob) (?)
305 got lock after * seconds (glob) (?)
317 got lock after * seconds (glob) (?)
306 (running background incremental repack)
318 (running background incremental repack)
307 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
319 * files fetched over 1 fetches - (* misses, 0.00% hit ratio) over *s (glob) (?)
308
320
309 $ find $CACHEDIR -type f | sort
321 $ find $CACHEDIR -type f | sort
310 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
322 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histidx
311 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
323 $TESTTMP/hgcache/master/packs/8f1443d44e57fec96f72fb2412e01d2818767ef2.histpack
312 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
324 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.dataidx
313 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
325 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407.datapack
314 $TESTTMP/hgcache/repos
326 $TESTTMP/hgcache/repos
315
327
316 # Ensure that files were prefetched
328 # Ensure that files were prefetched
317 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
329 $ hg debugdatapack `ls -ct $TESTTMP/hgcache/master/packs/*.datapack | head -n 1`
318 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
330 $TESTTMP/hgcache/master/packs/f4d50848e0b465e9bfd2875f213044c06cfd7407:
319 w:
331 w:
320 Node Delta Base Delta Length Blob Size
332 Node Delta Base Delta Length Blob Size
321 bb6ccd5dceaa 000000000000 2 2
333 bb6ccd5dceaa 000000000000 2 2
322
334
323 Total: 2 2 (0.0% bigger)
335 Total: 2 2 (0.0% bigger)
324 x:
336 x:
325 Node Delta Base Delta Length Blob Size
337 Node Delta Base Delta Length Blob Size
326 ef95c5376f34 000000000000 3 3
338 ef95c5376f34 000000000000 3 3
327 1406e7411862 ef95c5376f34 14 2
339 1406e7411862 ef95c5376f34 14 2
328
340
329 Total: 17 5 (240.0% bigger)
341 Total: 17 5 (240.0% bigger)
330 y:
342 y:
331 Node Delta Base Delta Length Blob Size
343 Node Delta Base Delta Length Blob Size
332 076f5e2225b3 000000000000 2 2
344 076f5e2225b3 000000000000 2 2
333
345
334 Total: 2 2 (0.0% bigger)
346 Total: 2 2 (0.0% bigger)
335 z:
347 z:
336 Node Delta Base Delta Length Blob Size
348 Node Delta Base Delta Length Blob Size
337 69a1b6752270 000000000000 2 2
349 69a1b6752270 000000000000 2 2
338
350
339 Total: 2 2 (0.0% bigger)
351 Total: 2 2 (0.0% bigger)
340
352
341 # Test that if data was prefetched and repacked we dont need to prefetch it again
353 # Test that if data was prefetched and repacked we dont need to prefetch it again
342 # It ensures that Mercurial looks not only in loose files but in packs as well
354 # It ensures that Mercurial looks not only in loose files but in packs as well
343
355
344 $ hg prefetch --repack
356 $ hg prefetch --repack
345 (running background incremental repack)
357 (running background incremental repack)
General Comments 0
You need to be logged in to leave comments. Login now