mercurial/chgserver.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43087 66f2cc210a29
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    73     return node.hex(hashlib.sha1(stringutil.pprint(items)).digest())
    73     return node.hex(hashlib.sha1(stringutil.pprint(items)).digest())
    74 
    74 
    75 
    75 
    76 # sensitive config sections affecting confighash
    76 # sensitive config sections affecting confighash
    77 _configsections = [
    77 _configsections = [
    78     'alias',  # affects global state commands.table
    78     b'alias',  # affects global state commands.table
    79     'eol',  # uses setconfig('eol', ...)
    79     b'eol',  # uses setconfig('eol', ...)
    80     'extdiff',  # uisetup will register new commands
    80     b'extdiff',  # uisetup will register new commands
    81     'extensions',
    81     b'extensions',
    82 ]
    82 ]
    83 
    83 
    84 _configsectionitems = [
    84 _configsectionitems = [
    85     ('commands', 'show.aliasprefix'),  # show.py reads it in extsetup
    85     (b'commands', b'show.aliasprefix'),  # show.py reads it in extsetup
    86 ]
    86 ]
    87 
    87 
    88 # sensitive environment variables affecting confighash
    88 # sensitive environment variables affecting confighash
    89 _envre = re.compile(
    89 _envre = re.compile(
    90     br'''\A(?:
    90     br'''\A(?:
   119         sectionitems.append(ui.configitems(section))
   119         sectionitems.append(ui.configitems(section))
   120     for section, item in _configsectionitems:
   120     for section, item in _configsectionitems:
   121         sectionitems.append(ui.config(section, item))
   121         sectionitems.append(ui.config(section, item))
   122     sectionhash = _hashlist(sectionitems)
   122     sectionhash = _hashlist(sectionitems)
   123     # If $CHGHG is set, the change to $HG should not trigger a new chg server
   123     # If $CHGHG is set, the change to $HG should not trigger a new chg server
   124     if 'CHGHG' in encoding.environ:
   124     if b'CHGHG' in encoding.environ:
   125         ignored = {'HG'}
   125         ignored = {b'HG'}
   126     else:
   126     else:
   127         ignored = set()
   127         ignored = set()
   128     envitems = [
   128     envitems = [
   129         (k, v)
   129         (k, v)
   130         for k, v in encoding.environ.iteritems()
   130         for k, v in encoding.environ.iteritems()
   202         if mtimepaths is None:
   202         if mtimepaths is None:
   203             mtimepaths = _getmtimepaths(ui)
   203             mtimepaths = _getmtimepaths(ui)
   204         confighash = _confighash(ui)
   204         confighash = _confighash(ui)
   205         mtimehash = _mtimehash(mtimepaths)
   205         mtimehash = _mtimehash(mtimepaths)
   206         ui.log(
   206         ui.log(
   207             'cmdserver',
   207             b'cmdserver',
   208             'confighash = %s mtimehash = %s\n',
   208             b'confighash = %s mtimehash = %s\n',
   209             confighash,
   209             confighash,
   210             mtimehash,
   210             mtimehash,
   211         )
   211         )
   212         return hashstate(confighash, mtimehash, mtimepaths)
   212         return hashstate(confighash, mtimehash, mtimepaths)
   213 
   213 
   227             #  b. or stdout is redirected by protectfinout(),
   227             #  b. or stdout is redirected by protectfinout(),
   228             # because the chg client is not aware of these situations and
   228             # because the chg client is not aware of these situations and
   229             # will behave differently (i.e. write to stdout).
   229             # will behave differently (i.e. write to stdout).
   230             if (
   230             if (
   231                 out is not self.fout
   231                 out is not self.fout
   232                 or not util.safehasattr(self.fout, 'fileno')
   232                 or not util.safehasattr(self.fout, b'fileno')
   233                 or self.fout.fileno() != procutil.stdout.fileno()
   233                 or self.fout.fileno() != procutil.stdout.fileno()
   234                 or self._finoutredirected
   234                 or self._finoutredirected
   235             ):
   235             ):
   236                 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
   236                 return procutil.system(cmd, environ=environ, cwd=cwd, out=out)
   237             self.flush()
   237             self.flush()
   239 
   239 
   240         def _runpager(self, cmd, env=None):
   240         def _runpager(self, cmd, env=None):
   241             self._csystem(
   241             self._csystem(
   242                 cmd,
   242                 cmd,
   243                 procutil.shellenviron(env),
   243                 procutil.shellenviron(env),
   244                 type='pager',
   244                 type=b'pager',
   245                 cmdtable={'attachio': attachio},
   245                 cmdtable={b'attachio': attachio},
   246             )
   246             )
   247             return True
   247             return True
   248 
   248 
   249     return chgui(srcui)
   249     return chgui(srcui)
   250 
   250 
   251 
   251 
   252 def _loadnewui(srcui, args, cdebug):
   252 def _loadnewui(srcui, args, cdebug):
   253     from . import dispatch  # avoid cycle
   253     from . import dispatch  # avoid cycle
   254 
   254 
   255     newui = srcui.__class__.load()
   255     newui = srcui.__class__.load()
   256     for a in ['fin', 'fout', 'ferr', 'environ']:
   256     for a in [b'fin', b'fout', b'ferr', b'environ']:
   257         setattr(newui, a, getattr(srcui, a))
   257         setattr(newui, a, getattr(srcui, a))
   258     if util.safehasattr(srcui, '_csystem'):
   258     if util.safehasattr(srcui, b'_csystem'):
   259         newui._csystem = srcui._csystem
   259         newui._csystem = srcui._csystem
   260 
   260 
   261     # command line args
   261     # command line args
   262     options = dispatch._earlyparseopts(newui, args)
   262     options = dispatch._earlyparseopts(newui, args)
   263     dispatch._parseconfig(newui, options['config'])
   263     dispatch._parseconfig(newui, options[b'config'])
   264 
   264 
   265     # stolen from tortoisehg.util.copydynamicconfig()
   265     # stolen from tortoisehg.util.copydynamicconfig()
   266     for section, name, value in srcui.walkconfig():
   266     for section, name, value in srcui.walkconfig():
   267         source = srcui.configsource(section, name)
   267         source = srcui.configsource(section, name)
   268         if ':' in source or source == '--config' or source.startswith('$'):
   268         if b':' in source or source == b'--config' or source.startswith(b'$'):
   269             # path:line or command line, or environ
   269             # path:line or command line, or environ
   270             continue
   270             continue
   271         newui.setconfig(section, name, value, source)
   271         newui.setconfig(section, name, value, source)
   272 
   272 
   273     # load wd and repo config, copied from dispatch.py
   273     # load wd and repo config, copied from dispatch.py
   274     cwd = options['cwd']
   274     cwd = options[b'cwd']
   275     cwd = cwd and os.path.realpath(cwd) or None
   275     cwd = cwd and os.path.realpath(cwd) or None
   276     rpath = options['repository']
   276     rpath = options[b'repository']
   277     path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
   277     path, newlui = dispatch._getlocal(newui, rpath, wd=cwd)
   278 
   278 
   279     extensions.populateui(newui)
   279     extensions.populateui(newui)
   280     commandserver.setuplogging(newui, fp=cdebug)
   280     commandserver.setuplogging(newui, fp=cdebug)
   281     if newui is not newlui:
   281     if newui is not newlui:
   309     def __init__(self, in_, out, channel):
   309     def __init__(self, in_, out, channel):
   310         self.in_ = in_
   310         self.in_ = in_
   311         self.out = out
   311         self.out = out
   312         self.channel = channel
   312         self.channel = channel
   313 
   313 
   314     def __call__(self, cmd, environ, cwd=None, type='system', cmdtable=None):
   314     def __call__(self, cmd, environ, cwd=None, type=b'system', cmdtable=None):
   315         args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or '.')]
   315         args = [type, procutil.quotecommand(cmd), os.path.abspath(cwd or b'.')]
   316         args.extend('%s=%s' % (k, v) for k, v in environ.iteritems())
   316         args.extend(b'%s=%s' % (k, v) for k, v in environ.iteritems())
   317         data = '\0'.join(args)
   317         data = b'\0'.join(args)
   318         self.out.write(struct.pack('>cI', self.channel, len(data)))
   318         self.out.write(struct.pack(b'>cI', self.channel, len(data)))
   319         self.out.write(data)
   319         self.out.write(data)
   320         self.out.flush()
   320         self.out.flush()
   321 
   321 
   322         if type == 'system':
   322         if type == b'system':
   323             length = self.in_.read(4)
   323             length = self.in_.read(4)
   324             (length,) = struct.unpack('>I', length)
   324             (length,) = struct.unpack(b'>I', length)
   325             if length != 4:
   325             if length != 4:
   326                 raise error.Abort(_('invalid response'))
   326                 raise error.Abort(_(b'invalid response'))
   327             (rc,) = struct.unpack('>i', self.in_.read(4))
   327             (rc,) = struct.unpack(b'>i', self.in_.read(4))
   328             return rc
   328             return rc
   329         elif type == 'pager':
   329         elif type == b'pager':
   330             while True:
   330             while True:
   331                 cmd = self.in_.readline()[:-1]
   331                 cmd = self.in_.readline()[:-1]
   332                 if not cmd:
   332                 if not cmd:
   333                     break
   333                     break
   334                 if cmdtable and cmd in cmdtable:
   334                 if cmdtable and cmd in cmdtable:
   335                     cmdtable[cmd]()
   335                     cmdtable[cmd]()
   336                 else:
   336                 else:
   337                     raise error.Abort(_('unexpected command: %s') % cmd)
   337                     raise error.Abort(_(b'unexpected command: %s') % cmd)
   338         else:
   338         else:
   339             raise error.ProgrammingError('invalid S channel type: %s' % type)
   339             raise error.ProgrammingError(b'invalid S channel type: %s' % type)
   340 
   340 
   341 
   341 
   342 _iochannels = [
   342 _iochannels = [
   343     # server.ch, ui.fp, mode
   343     # server.ch, ui.fp, mode
   344     ('cin', 'fin', r'rb'),
   344     (b'cin', b'fin', r'rb'),
   345     ('cout', 'fout', r'wb'),
   345     (b'cout', b'fout', r'wb'),
   346     ('cerr', 'ferr', r'wb'),
   346     (b'cerr', b'ferr', r'wb'),
   347 ]
   347 ]
   348 
   348 
   349 
   349 
   350 class chgcmdserver(commandserver.server):
   350 class chgcmdserver(commandserver.server):
   351     def __init__(
   351     def __init__(
   352         self, ui, repo, fin, fout, sock, prereposetups, hashstate, baseaddress
   352         self, ui, repo, fin, fout, sock, prereposetups, hashstate, baseaddress
   353     ):
   353     ):
   354         super(chgcmdserver, self).__init__(
   354         super(chgcmdserver, self).__init__(
   355             _newchgui(ui, channeledsystem(fin, fout, 'S'), self.attachio),
   355             _newchgui(ui, channeledsystem(fin, fout, b'S'), self.attachio),
   356             repo,
   356             repo,
   357             fin,
   357             fin,
   358             fout,
   358             fout,
   359             prereposetups,
   359             prereposetups,
   360         )
   360         )
   363         self._oldios = []  # original (self.ch, ui.fp, fd) before "attachio"
   363         self._oldios = []  # original (self.ch, ui.fp, fd) before "attachio"
   364         self.hashstate = hashstate
   364         self.hashstate = hashstate
   365         self.baseaddress = baseaddress
   365         self.baseaddress = baseaddress
   366         if hashstate is not None:
   366         if hashstate is not None:
   367             self.capabilities = self.capabilities.copy()
   367             self.capabilities = self.capabilities.copy()
   368             self.capabilities['validate'] = chgcmdserver.validate
   368             self.capabilities[b'validate'] = chgcmdserver.validate
   369 
   369 
   370     def cleanup(self):
   370     def cleanup(self):
   371         super(chgcmdserver, self).cleanup()
   371         super(chgcmdserver, self).cleanup()
   372         # dispatch._runcatch() does not flush outputs if exception is not
   372         # dispatch._runcatch() does not flush outputs if exception is not
   373         # handled by dispatch._dispatch()
   373         # handled by dispatch._dispatch()
   379         """Attach to client's stdio passed via unix domain socket; all
   379         """Attach to client's stdio passed via unix domain socket; all
   380         channels except cresult will no longer be used
   380         channels except cresult will no longer be used
   381         """
   381         """
   382         # tell client to sendmsg() with 1-byte payload, which makes it
   382         # tell client to sendmsg() with 1-byte payload, which makes it
   383         # distinctive from "attachio\n" command consumed by client.read()
   383         # distinctive from "attachio\n" command consumed by client.read()
   384         self.clientsock.sendall(struct.pack('>cI', 'I', 1))
   384         self.clientsock.sendall(struct.pack(b'>cI', b'I', 1))
   385         clientfds = util.recvfds(self.clientsock.fileno())
   385         clientfds = util.recvfds(self.clientsock.fileno())
   386         self.ui.log('chgserver', 'received fds: %r\n', clientfds)
   386         self.ui.log(b'chgserver', b'received fds: %r\n', clientfds)
   387 
   387 
   388         ui = self.ui
   388         ui = self.ui
   389         ui.flush()
   389         ui.flush()
   390         self._saveio()
   390         self._saveio()
   391         for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
   391         for fd, (cn, fn, mode) in zip(clientfds, _iochannels):
   397                 continue
   397                 continue
   398             # reset buffering mode when client is first attached. as we want
   398             # reset buffering mode when client is first attached. as we want
   399             # to see output immediately on pager, the mode stays unchanged
   399             # to see output immediately on pager, the mode stays unchanged
   400             # when client re-attached. ferr is unchanged because it should
   400             # when client re-attached. ferr is unchanged because it should
   401             # be unbuffered no matter if it is a tty or not.
   401             # be unbuffered no matter if it is a tty or not.
   402             if fn == 'ferr':
   402             if fn == b'ferr':
   403                 newfp = fp
   403                 newfp = fp
   404             else:
   404             else:
   405                 # make it line buffered explicitly because the default is
   405                 # make it line buffered explicitly because the default is
   406                 # decided on first write(), where fout could be a pager.
   406                 # decided on first write(), where fout could be a pager.
   407                 if fp.isatty():
   407                 if fp.isatty():
   411                 newfp = os.fdopen(fp.fileno(), mode, bufsize)
   411                 newfp = os.fdopen(fp.fileno(), mode, bufsize)
   412                 setattr(ui, fn, newfp)
   412                 setattr(ui, fn, newfp)
   413             setattr(self, cn, newfp)
   413             setattr(self, cn, newfp)
   414 
   414 
   415         self._ioattached = True
   415         self._ioattached = True
   416         self.cresult.write(struct.pack('>i', len(clientfds)))
   416         self.cresult.write(struct.pack(b'>i', len(clientfds)))
   417 
   417 
   418     def _saveio(self):
   418     def _saveio(self):
   419         if self._oldios:
   419         if self._oldios:
   420             return
   420             return
   421         ui = self.ui
   421         ui = self.ui
   466         try:
   466         try:
   467             self.ui, lui = _loadnewui(self.ui, args, self.cdebug)
   467             self.ui, lui = _loadnewui(self.ui, args, self.cdebug)
   468         except error.ParseError as inst:
   468         except error.ParseError as inst:
   469             dispatch._formatparse(self.ui.warn, inst)
   469             dispatch._formatparse(self.ui.warn, inst)
   470             self.ui.flush()
   470             self.ui.flush()
   471             self.cresult.write('exit 255')
   471             self.cresult.write(b'exit 255')
   472             return
   472             return
   473         except error.Abort as inst:
   473         except error.Abort as inst:
   474             self.ui.error(_("abort: %s\n") % inst)
   474             self.ui.error(_(b"abort: %s\n") % inst)
   475             if inst.hint:
   475             if inst.hint:
   476                 self.ui.error(_("(%s)\n") % inst.hint)
   476                 self.ui.error(_(b"(%s)\n") % inst.hint)
   477             self.ui.flush()
   477             self.ui.flush()
   478             self.cresult.write('exit 255')
   478             self.cresult.write(b'exit 255')
   479             return
   479             return
   480         newhash = hashstate.fromui(lui, self.hashstate.mtimepaths)
   480         newhash = hashstate.fromui(lui, self.hashstate.mtimepaths)
   481         insts = []
   481         insts = []
   482         if newhash.mtimehash != self.hashstate.mtimehash:
   482         if newhash.mtimehash != self.hashstate.mtimehash:
   483             addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
   483             addr = _hashaddress(self.baseaddress, self.hashstate.confighash)
   484             insts.append('unlink %s' % addr)
   484             insts.append(b'unlink %s' % addr)
   485             # mtimehash is empty if one or more extensions fail to load.
   485             # mtimehash is empty if one or more extensions fail to load.
   486             # to be compatible with hg, still serve the client this time.
   486             # to be compatible with hg, still serve the client this time.
   487             if self.hashstate.mtimehash:
   487             if self.hashstate.mtimehash:
   488                 insts.append('reconnect')
   488                 insts.append(b'reconnect')
   489         if newhash.confighash != self.hashstate.confighash:
   489         if newhash.confighash != self.hashstate.confighash:
   490             addr = _hashaddress(self.baseaddress, newhash.confighash)
   490             addr = _hashaddress(self.baseaddress, newhash.confighash)
   491             insts.append('redirect %s' % addr)
   491             insts.append(b'redirect %s' % addr)
   492         self.ui.log('chgserver', 'validate: %s\n', stringutil.pprint(insts))
   492         self.ui.log(b'chgserver', b'validate: %s\n', stringutil.pprint(insts))
   493         self.cresult.write('\0'.join(insts) or '\0')
   493         self.cresult.write(b'\0'.join(insts) or b'\0')
   494 
   494 
   495     def chdir(self):
   495     def chdir(self):
   496         """Change current directory
   496         """Change current directory
   497 
   497 
   498         Note that the behavior of --cwd option is bit different from this.
   498         Note that the behavior of --cwd option is bit different from this.
   499         It does not affect --config parameter.
   499         It does not affect --config parameter.
   500         """
   500         """
   501         path = self._readstr()
   501         path = self._readstr()
   502         if not path:
   502         if not path:
   503             return
   503             return
   504         self.ui.log('chgserver', 'chdir to %r\n', path)
   504         self.ui.log(b'chgserver', b'chdir to %r\n', path)
   505         os.chdir(path)
   505         os.chdir(path)
   506 
   506 
   507     def setumask(self):
   507     def setumask(self):
   508         """Change umask (DEPRECATED)"""
   508         """Change umask (DEPRECATED)"""
   509         # BUG: this does not follow the message frame structure, but kept for
   509         # BUG: this does not follow the message frame structure, but kept for
   512 
   512 
   513     def setumask2(self):
   513     def setumask2(self):
   514         """Change umask"""
   514         """Change umask"""
   515         data = self._readstr()
   515         data = self._readstr()
   516         if len(data) != 4:
   516         if len(data) != 4:
   517             raise ValueError('invalid mask length in setumask2 request')
   517             raise ValueError(b'invalid mask length in setumask2 request')
   518         self._setumask(data)
   518         self._setumask(data)
   519 
   519 
   520     def _setumask(self, data):
   520     def _setumask(self, data):
   521         mask = struct.unpack('>I', data)[0]
   521         mask = struct.unpack(b'>I', data)[0]
   522         self.ui.log('chgserver', 'setumask %r\n', mask)
   522         self.ui.log(b'chgserver', b'setumask %r\n', mask)
   523         os.umask(mask)
   523         os.umask(mask)
   524 
   524 
   525     def runcommand(self):
   525     def runcommand(self):
   526         # pager may be attached within the runcommand session, which should
   526         # pager may be attached within the runcommand session, which should
   527         # be detached at the end of the session. otherwise the pager wouldn't
   527         # be detached at the end of the session. otherwise the pager wouldn't
   539 
   539 
   540         Note that not all variables can make an effect on the running process.
   540         Note that not all variables can make an effect on the running process.
   541         """
   541         """
   542         l = self._readlist()
   542         l = self._readlist()
   543         try:
   543         try:
   544             newenv = dict(s.split('=', 1) for s in l)
   544             newenv = dict(s.split(b'=', 1) for s in l)
   545         except ValueError:
   545         except ValueError:
   546             raise ValueError('unexpected value in setenv request')
   546             raise ValueError(b'unexpected value in setenv request')
   547         self.ui.log('chgserver', 'setenv: %r\n', sorted(newenv.keys()))
   547         self.ui.log(b'chgserver', b'setenv: %r\n', sorted(newenv.keys()))
   548         encoding.environ.clear()
   548         encoding.environ.clear()
   549         encoding.environ.update(newenv)
   549         encoding.environ.update(newenv)
   550 
   550 
   551     capabilities = commandserver.server.capabilities.copy()
   551     capabilities = commandserver.server.capabilities.copy()
   552     capabilities.update(
   552     capabilities.update(
   553         {
   553         {
   554             'attachio': attachio,
   554             b'attachio': attachio,
   555             'chdir': chdir,
   555             b'chdir': chdir,
   556             'runcommand': runcommand,
   556             b'runcommand': runcommand,
   557             'setenv': setenv,
   557             b'setenv': setenv,
   558             'setumask': setumask,
   558             b'setumask': setumask,
   559             'setumask2': setumask2,
   559             b'setumask2': setumask2,
   560         }
   560         }
   561     )
   561     )
   562 
   562 
   563     if util.safehasattr(procutil, 'setprocname'):
   563     if util.safehasattr(procutil, b'setprocname'):
   564 
   564 
   565         def setprocname(self):
   565         def setprocname(self):
   566             """Change process title"""
   566             """Change process title"""
   567             name = self._readstr()
   567             name = self._readstr()
   568             self.ui.log('chgserver', 'setprocname: %r\n', name)
   568             self.ui.log(b'chgserver', b'setprocname: %r\n', name)
   569             procutil.setprocname(name)
   569             procutil.setprocname(name)
   570 
   570 
   571         capabilities['setprocname'] = setprocname
   571         capabilities[b'setprocname'] = setprocname
   572 
   572 
   573 
   573 
   574 def _tempaddress(address):
   574 def _tempaddress(address):
   575     return '%s.%d.tmp' % (address, os.getpid())
   575     return b'%s.%d.tmp' % (address, os.getpid())
   576 
   576 
   577 
   577 
   578 def _hashaddress(address, hashstr):
   578 def _hashaddress(address, hashstr):
   579     # if the basename of address contains '.', use only the left part. this
   579     # if the basename of address contains '.', use only the left part. this
   580     # makes it possible for the client to pass 'server.tmp$PID' and follow by
   580     # makes it possible for the client to pass 'server.tmp$PID' and follow by
   581     # an atomic rename to avoid locking when spawning new servers.
   581     # an atomic rename to avoid locking when spawning new servers.
   582     dirname, basename = os.path.split(address)
   582     dirname, basename = os.path.split(address)
   583     basename = basename.split('.', 1)[0]
   583     basename = basename.split(b'.', 1)[0]
   584     return '%s-%s' % (os.path.join(dirname, basename), hashstr)
   584     return b'%s-%s' % (os.path.join(dirname, basename), hashstr)
   585 
   585 
   586 
   586 
   587 class chgunixservicehandler(object):
   587 class chgunixservicehandler(object):
   588     """Set of operations for chg services"""
   588     """Set of operations for chg services"""
   589 
   589 
   590     pollinterval = 1  # [sec]
   590     pollinterval = 1  # [sec]
   591 
   591 
   592     def __init__(self, ui):
   592     def __init__(self, ui):
   593         self.ui = ui
   593         self.ui = ui
   594         self._idletimeout = ui.configint('chgserver', 'idletimeout')
   594         self._idletimeout = ui.configint(b'chgserver', b'idletimeout')
   595         self._lastactive = time.time()
   595         self._lastactive = time.time()
   596 
   596 
   597     def bindsocket(self, sock, address):
   597     def bindsocket(self, sock, address):
   598         self._inithashstate(address)
   598         self._inithashstate(address)
   599         self._checkextensions()
   599         self._checkextensions()
   601         self._createsymlink()
   601         self._createsymlink()
   602         # no "listening at" message should be printed to simulate hg behavior
   602         # no "listening at" message should be printed to simulate hg behavior
   603 
   603 
   604     def _inithashstate(self, address):
   604     def _inithashstate(self, address):
   605         self._baseaddress = address
   605         self._baseaddress = address
   606         if self.ui.configbool('chgserver', 'skiphash'):
   606         if self.ui.configbool(b'chgserver', b'skiphash'):
   607             self._hashstate = None
   607             self._hashstate = None
   608             self._realaddress = address
   608             self._realaddress = address
   609             return
   609             return
   610         self._hashstate = hashstate.fromui(self.ui)
   610         self._hashstate = hashstate.fromui(self.ui)
   611         self._realaddress = _hashaddress(address, self._hashstate.confighash)
   611         self._realaddress = _hashaddress(address, self._hashstate.confighash)
   615             return
   615             return
   616         if extensions.notloaded():
   616         if extensions.notloaded():
   617             # one or more extensions failed to load. mtimehash becomes
   617             # one or more extensions failed to load. mtimehash becomes
   618             # meaningless because we do not know the paths of those extensions.
   618             # meaningless because we do not know the paths of those extensions.
   619             # set mtimehash to an illegal hash value to invalidate the server.
   619             # set mtimehash to an illegal hash value to invalidate the server.
   620             self._hashstate.mtimehash = ''
   620             self._hashstate.mtimehash = b''
   621 
   621 
   622     def _bind(self, sock):
   622     def _bind(self, sock):
   623         # use a unique temp address so we can stat the file and do ownership
   623         # use a unique temp address so we can stat the file and do ownership
   624         # check later
   624         # check later
   625         tempaddress = _tempaddress(self._realaddress)
   625         tempaddress = _tempaddress(self._realaddress)
   687     # CHGINTERNALMARK is set by chg client. It is an indication of things are
   687     # CHGINTERNALMARK is set by chg client. It is an indication of things are
   688     # started by chg so other code can do things accordingly, like disabling
   688     # started by chg so other code can do things accordingly, like disabling
   689     # demandimport or detecting chg client started by chg client. When executed
   689     # demandimport or detecting chg client started by chg client. When executed
   690     # here, CHGINTERNALMARK is no longer useful and hence dropped to make
   690     # here, CHGINTERNALMARK is no longer useful and hence dropped to make
   691     # environ cleaner.
   691     # environ cleaner.
   692     if 'CHGINTERNALMARK' in encoding.environ:
   692     if b'CHGINTERNALMARK' in encoding.environ:
   693         del encoding.environ['CHGINTERNALMARK']
   693         del encoding.environ[b'CHGINTERNALMARK']
   694 
   694 
   695     if repo:
   695     if repo:
   696         # one chgserver can serve multiple repos. drop repo information
   696         # one chgserver can serve multiple repos. drop repo information
   697         ui.setconfig('bundle', 'mainreporoot', '', 'repo')
   697         ui.setconfig(b'bundle', b'mainreporoot', b'', b'repo')
   698     h = chgunixservicehandler(ui)
   698     h = chgunixservicehandler(ui)
   699     return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)
   699     return commandserver.unixforkingservice(ui, repo=None, opts=opts, handler=h)