mercurial/server.py
changeset 43077 687b865b95ad
parent 43076 2372284d9457
child 43085 eef9a2d67051
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
    35 ):
    35 ):
    36     '''Run a command as a service.'''
    36     '''Run a command as a service.'''
    37 
    37 
    38     postexecargs = {}
    38     postexecargs = {}
    39 
    39 
    40     if opts['daemon_postexec']:
    40     if opts[b'daemon_postexec']:
    41         for inst in opts['daemon_postexec']:
    41         for inst in opts[b'daemon_postexec']:
    42             if inst.startswith('unlink:'):
    42             if inst.startswith(b'unlink:'):
    43                 postexecargs['unlink'] = inst[7:]
    43                 postexecargs[b'unlink'] = inst[7:]
    44             elif inst.startswith('chdir:'):
    44             elif inst.startswith(b'chdir:'):
    45                 postexecargs['chdir'] = inst[6:]
    45                 postexecargs[b'chdir'] = inst[6:]
    46             elif inst != 'none':
    46             elif inst != b'none':
    47                 raise error.Abort(
    47                 raise error.Abort(
    48                     _('invalid value for --daemon-postexec: %s') % inst
    48                     _(b'invalid value for --daemon-postexec: %s') % inst
    49                 )
    49                 )
    50 
    50 
    51     # When daemonized on Windows, redirect stdout/stderr to the lockfile (which
    51     # When daemonized on Windows, redirect stdout/stderr to the lockfile (which
    52     # gets cleaned up after the child is up and running), so that the parent can
    52     # gets cleaned up after the child is up and running), so that the parent can
    53     # read and print the error if this child dies early.  See 594dd384803c.  On
    53     # read and print the error if this child dies early.  See 594dd384803c.  On
    54     # other platforms, the child can write to the parent's stdio directly, until
    54     # other platforms, the child can write to the parent's stdio directly, until
    55     # it is redirected prior to runfn().
    55     # it is redirected prior to runfn().
    56     if pycompat.iswindows and opts['daemon_postexec']:
    56     if pycompat.iswindows and opts[b'daemon_postexec']:
    57         if 'unlink' in postexecargs and os.path.exists(postexecargs['unlink']):
    57         if b'unlink' in postexecargs and os.path.exists(
       
    58             postexecargs[b'unlink']
       
    59         ):
    58             procutil.stdout.flush()
    60             procutil.stdout.flush()
    59             procutil.stderr.flush()
    61             procutil.stderr.flush()
    60 
    62 
    61             fd = os.open(
    63             fd = os.open(
    62                 postexecargs['unlink'], os.O_WRONLY | os.O_APPEND | os.O_BINARY
    64                 postexecargs[b'unlink'], os.O_WRONLY | os.O_APPEND | os.O_BINARY
    63             )
    65             )
    64             try:
    66             try:
    65                 os.dup2(fd, procutil.stdout.fileno())
    67                 os.dup2(fd, procutil.stdout.fileno())
    66                 os.dup2(fd, procutil.stderr.fileno())
    68                 os.dup2(fd, procutil.stderr.fileno())
    67             finally:
    69             finally:
    68                 os.close(fd)
    70                 os.close(fd)
    69 
    71 
    70     def writepid(pid):
    72     def writepid(pid):
    71         if opts['pid_file']:
    73         if opts[b'pid_file']:
    72             if appendpid:
    74             if appendpid:
    73                 mode = 'ab'
    75                 mode = b'ab'
    74             else:
    76             else:
    75                 mode = 'wb'
    77                 mode = b'wb'
    76             fp = open(opts['pid_file'], mode)
    78             fp = open(opts[b'pid_file'], mode)
    77             fp.write('%d\n' % pid)
    79             fp.write(b'%d\n' % pid)
    78             fp.close()
    80             fp.close()
    79 
    81 
    80     if opts['daemon'] and not opts['daemon_postexec']:
    82     if opts[b'daemon'] and not opts[b'daemon_postexec']:
    81         # Signal child process startup with file removal
    83         # Signal child process startup with file removal
    82         lockfd, lockpath = pycompat.mkstemp(prefix='hg-service-')
    84         lockfd, lockpath = pycompat.mkstemp(prefix=b'hg-service-')
    83         os.close(lockfd)
    85         os.close(lockfd)
    84         try:
    86         try:
    85             if not runargs:
    87             if not runargs:
    86                 runargs = procutil.hgcmd() + pycompat.sysargv[1:]
    88                 runargs = procutil.hgcmd() + pycompat.sysargv[1:]
    87             runargs.append('--daemon-postexec=unlink:%s' % lockpath)
    89             runargs.append(b'--daemon-postexec=unlink:%s' % lockpath)
    88             # Don't pass --cwd to the child process, because we've already
    90             # Don't pass --cwd to the child process, because we've already
    89             # changed directory.
    91             # changed directory.
    90             for i in pycompat.xrange(1, len(runargs)):
    92             for i in pycompat.xrange(1, len(runargs)):
    91                 if runargs[i].startswith('--cwd='):
    93                 if runargs[i].startswith(b'--cwd='):
    92                     del runargs[i]
    94                     del runargs[i]
    93                     break
    95                     break
    94                 elif runargs[i].startswith('--cwd'):
    96                 elif runargs[i].startswith(b'--cwd'):
    95                     del runargs[i : i + 2]
    97                     del runargs[i : i + 2]
    96                     break
    98                     break
    97 
    99 
    98             def condfn():
   100             def condfn():
    99                 return not os.path.exists(lockpath)
   101                 return not os.path.exists(lockpath)
   101             pid = procutil.rundetached(runargs, condfn)
   103             pid = procutil.rundetached(runargs, condfn)
   102             if pid < 0:
   104             if pid < 0:
   103                 # If the daemonized process managed to write out an error msg,
   105                 # If the daemonized process managed to write out an error msg,
   104                 # report it.
   106                 # report it.
   105                 if pycompat.iswindows and os.path.exists(lockpath):
   107                 if pycompat.iswindows and os.path.exists(lockpath):
   106                     with open(lockpath, 'rb') as log:
   108                     with open(lockpath, b'rb') as log:
   107                         for line in log:
   109                         for line in log:
   108                             procutil.stderr.write(line)
   110                             procutil.stderr.write(line)
   109                 raise error.Abort(_('child process failed to start'))
   111                 raise error.Abort(_(b'child process failed to start'))
   110             writepid(pid)
   112             writepid(pid)
   111         finally:
   113         finally:
   112             util.tryunlink(lockpath)
   114             util.tryunlink(lockpath)
   113         if parentfn:
   115         if parentfn:
   114             return parentfn(pid)
   116             return parentfn(pid)
   116             return
   118             return
   117 
   119 
   118     if initfn:
   120     if initfn:
   119         initfn()
   121         initfn()
   120 
   122 
   121     if not opts['daemon']:
   123     if not opts[b'daemon']:
   122         writepid(procutil.getpid())
   124         writepid(procutil.getpid())
   123 
   125 
   124     if opts['daemon_postexec']:
   126     if opts[b'daemon_postexec']:
   125         try:
   127         try:
   126             os.setsid()
   128             os.setsid()
   127         except AttributeError:
   129         except AttributeError:
   128             pass
   130             pass
   129 
   131 
   130         if 'chdir' in postexecargs:
   132         if b'chdir' in postexecargs:
   131             os.chdir(postexecargs['chdir'])
   133             os.chdir(postexecargs[b'chdir'])
   132         procutil.hidewindow()
   134         procutil.hidewindow()
   133         procutil.stdout.flush()
   135         procutil.stdout.flush()
   134         procutil.stderr.flush()
   136         procutil.stderr.flush()
   135 
   137 
   136         nullfd = os.open(os.devnull, os.O_RDWR)
   138         nullfd = os.open(os.devnull, os.O_RDWR)
   152         if logfile and logfilefd not in stdio:
   154         if logfile and logfilefd not in stdio:
   153             os.close(logfilefd)
   155             os.close(logfilefd)
   154 
   156 
   155         # Only unlink after redirecting stdout/stderr, so Windows doesn't
   157         # Only unlink after redirecting stdout/stderr, so Windows doesn't
   156         # complain about a sharing violation.
   158         # complain about a sharing violation.
   157         if 'unlink' in postexecargs:
   159         if b'unlink' in postexecargs:
   158             os.unlink(postexecargs['unlink'])
   160             os.unlink(postexecargs[b'unlink'])
   159 
   161 
   160     if runfn:
   162     if runfn:
   161         return runfn()
   163         return runfn()
   162 
   164 
   163 
   165 
   164 _cmdservicemap = {
   166 _cmdservicemap = {
   165     'chgunix': chgserver.chgunixservice,
   167     b'chgunix': chgserver.chgunixservice,
   166     'pipe': commandserver.pipeservice,
   168     b'pipe': commandserver.pipeservice,
   167     'unix': commandserver.unixforkingservice,
   169     b'unix': commandserver.unixforkingservice,
   168 }
   170 }
   169 
   171 
   170 
   172 
   171 def _createcmdservice(ui, repo, opts):
   173 def _createcmdservice(ui, repo, opts):
   172     mode = opts['cmdserver']
   174     mode = opts[b'cmdserver']
   173     try:
   175     try:
   174         servicefn = _cmdservicemap[mode]
   176         servicefn = _cmdservicemap[mode]
   175     except KeyError:
   177     except KeyError:
   176         raise error.Abort(_('unknown mode %s') % mode)
   178         raise error.Abort(_(b'unknown mode %s') % mode)
   177     commandserver.setuplogging(ui, repo)
   179     commandserver.setuplogging(ui, repo)
   178     return servicefn(ui, repo, opts)
   180     return servicefn(ui, repo, opts)
   179 
   181 
   180 
   182 
   181 def _createhgwebservice(ui, repo, opts):
   183 def _createhgwebservice(ui, repo, opts):
   182     # this way we can check if something was given in the command-line
   184     # this way we can check if something was given in the command-line
   183     if opts.get('port'):
   185     if opts.get(b'port'):
   184         opts['port'] = util.getport(opts.get('port'))
   186         opts[b'port'] = util.getport(opts.get(b'port'))
   185 
   187 
   186     alluis = {ui}
   188     alluis = {ui}
   187     if repo:
   189     if repo:
   188         baseui = repo.baseui
   190         baseui = repo.baseui
   189         alluis.update([repo.baseui, repo.ui])
   191         alluis.update([repo.baseui, repo.ui])
   190     else:
   192     else:
   191         baseui = ui
   193         baseui = ui
   192     webconf = opts.get('web_conf') or opts.get('webdir_conf')
   194     webconf = opts.get(b'web_conf') or opts.get(b'webdir_conf')
   193     if webconf:
   195     if webconf:
   194         if opts.get('subrepos'):
   196         if opts.get(b'subrepos'):
   195             raise error.Abort(_('--web-conf cannot be used with --subrepos'))
   197             raise error.Abort(_(b'--web-conf cannot be used with --subrepos'))
   196 
   198 
   197         # load server settings (e.g. web.port) to "copied" ui, which allows
   199         # load server settings (e.g. web.port) to "copied" ui, which allows
   198         # hgwebdir to reload webconf cleanly
   200         # hgwebdir to reload webconf cleanly
   199         servui = ui.copy()
   201         servui = ui.copy()
   200         servui.readconfig(webconf, sections=['web'])
   202         servui.readconfig(webconf, sections=[b'web'])
   201         alluis.add(servui)
   203         alluis.add(servui)
   202     elif opts.get('subrepos'):
   204     elif opts.get(b'subrepos'):
   203         servui = ui
   205         servui = ui
   204 
   206 
   205         # If repo is None, hgweb.createapp() already raises a proper abort
   207         # If repo is None, hgweb.createapp() already raises a proper abort
   206         # message as long as webconf is None.
   208         # message as long as webconf is None.
   207         if repo:
   209         if repo:
   208             webconf = dict()
   210             webconf = dict()
   209             cmdutil.addwebdirpath(repo, "", webconf)
   211             cmdutil.addwebdirpath(repo, b"", webconf)
   210     else:
   212     else:
   211         servui = ui
   213         servui = ui
   212 
   214 
   213     optlist = (
   215     optlist = (
   214         "name templates style address port prefix ipv6"
   216         b"name templates style address port prefix ipv6"
   215         " accesslog errorlog certificate encoding"
   217         b" accesslog errorlog certificate encoding"
   216     )
   218     )
   217     for o in optlist.split():
   219     for o in optlist.split():
   218         val = opts.get(o, '')
   220         val = opts.get(o, b'')
   219         if val in (None, ''):  # should check against default options instead
   221         if val in (None, b''):  # should check against default options instead
   220             continue
   222             continue
   221         for u in alluis:
   223         for u in alluis:
   222             u.setconfig("web", o, val, 'serve')
   224             u.setconfig(b"web", o, val, b'serve')
   223 
   225 
   224     app = hgweb.createapp(baseui, repo, webconf)
   226     app = hgweb.createapp(baseui, repo, webconf)
   225     return hgweb.httpservice(servui, app, opts)
   227     return hgweb.httpservice(servui, app, opts)
   226 
   228 
   227 
   229 
   228 def createservice(ui, repo, opts):
   230 def createservice(ui, repo, opts):
   229     if opts["cmdserver"]:
   231     if opts[b"cmdserver"]:
   230         return _createcmdservice(ui, repo, opts)
   232         return _createcmdservice(ui, repo, opts)
   231     else:
   233     else:
   232         return _createhgwebservice(ui, repo, opts)
   234         return _createhgwebservice(ui, repo, opts)