mercurial/server.py
changeset 30506 d9d8d78e6bc9
child 30507 dd539e2d89aa
equal deleted inserted replaced
30505:158b41842fd2 30506:d9d8d78e6bc9
       
     1 # server.py - utility and factory of server
       
     2 #
       
     3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
       
     4 #
       
     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.
       
     7 
       
     8 from __future__ import absolute_import
       
     9 
       
    10 import errno
       
    11 import os
       
    12 import sys
       
    13 import tempfile
       
    14 
       
    15 from .i18n import _
       
    16 
       
    17 from . import (
       
    18     error,
       
    19     util,
       
    20 )
       
    21 
       
    22 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
       
    23                runargs=None, appendpid=False):
       
    24     '''Run a command as a service.'''
       
    25 
       
    26     def writepid(pid):
       
    27         if opts['pid_file']:
       
    28             if appendpid:
       
    29                 mode = 'a'
       
    30             else:
       
    31                 mode = 'w'
       
    32             fp = open(opts['pid_file'], mode)
       
    33             fp.write(str(pid) + '\n')
       
    34             fp.close()
       
    35 
       
    36     if opts['daemon'] and not opts['daemon_postexec']:
       
    37         # Signal child process startup with file removal
       
    38         lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
       
    39         os.close(lockfd)
       
    40         try:
       
    41             if not runargs:
       
    42                 runargs = util.hgcmd() + sys.argv[1:]
       
    43             runargs.append('--daemon-postexec=unlink:%s' % lockpath)
       
    44             # Don't pass --cwd to the child process, because we've already
       
    45             # changed directory.
       
    46             for i in xrange(1, len(runargs)):
       
    47                 if runargs[i].startswith('--cwd='):
       
    48                     del runargs[i]
       
    49                     break
       
    50                 elif runargs[i].startswith('--cwd'):
       
    51                     del runargs[i:i + 2]
       
    52                     break
       
    53             def condfn():
       
    54                 return not os.path.exists(lockpath)
       
    55             pid = util.rundetached(runargs, condfn)
       
    56             if pid < 0:
       
    57                 raise error.Abort(_('child process failed to start'))
       
    58             writepid(pid)
       
    59         finally:
       
    60             try:
       
    61                 os.unlink(lockpath)
       
    62             except OSError as e:
       
    63                 if e.errno != errno.ENOENT:
       
    64                     raise
       
    65         if parentfn:
       
    66             return parentfn(pid)
       
    67         else:
       
    68             return
       
    69 
       
    70     if initfn:
       
    71         initfn()
       
    72 
       
    73     if not opts['daemon']:
       
    74         writepid(util.getpid())
       
    75 
       
    76     if opts['daemon_postexec']:
       
    77         try:
       
    78             os.setsid()
       
    79         except AttributeError:
       
    80             pass
       
    81         for inst in opts['daemon_postexec']:
       
    82             if inst.startswith('unlink:'):
       
    83                 lockpath = inst[7:]
       
    84                 os.unlink(lockpath)
       
    85             elif inst.startswith('chdir:'):
       
    86                 os.chdir(inst[6:])
       
    87             elif inst != 'none':
       
    88                 raise error.Abort(_('invalid value for --daemon-postexec: %s')
       
    89                                   % inst)
       
    90         util.hidewindow()
       
    91         util.stdout.flush()
       
    92         util.stderr.flush()
       
    93 
       
    94         nullfd = os.open(os.devnull, os.O_RDWR)
       
    95         logfilefd = nullfd
       
    96         if logfile:
       
    97             logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
       
    98         os.dup2(nullfd, 0)
       
    99         os.dup2(logfilefd, 1)
       
   100         os.dup2(logfilefd, 2)
       
   101         if nullfd not in (0, 1, 2):
       
   102             os.close(nullfd)
       
   103         if logfile and logfilefd not in (0, 1, 2):
       
   104             os.close(logfilefd)
       
   105 
       
   106     if runfn:
       
   107         return runfn()