mercurial/server.py
changeset 30506 d9d8d78e6bc9
child 30507 dd539e2d89aa
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mercurial/server.py	Sat Oct 15 13:47:43 2016 +0900
@@ -0,0 +1,107 @@
+# server.py - utility and factory of server
+#
+# Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from __future__ import absolute_import
+
+import errno
+import os
+import sys
+import tempfile
+
+from .i18n import _
+
+from . import (
+    error,
+    util,
+)
+
+def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
+               runargs=None, appendpid=False):
+    '''Run a command as a service.'''
+
+    def writepid(pid):
+        if opts['pid_file']:
+            if appendpid:
+                mode = 'a'
+            else:
+                mode = 'w'
+            fp = open(opts['pid_file'], mode)
+            fp.write(str(pid) + '\n')
+            fp.close()
+
+    if opts['daemon'] and not opts['daemon_postexec']:
+        # Signal child process startup with file removal
+        lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
+        os.close(lockfd)
+        try:
+            if not runargs:
+                runargs = util.hgcmd() + sys.argv[1:]
+            runargs.append('--daemon-postexec=unlink:%s' % lockpath)
+            # Don't pass --cwd to the child process, because we've already
+            # changed directory.
+            for i in xrange(1, len(runargs)):
+                if runargs[i].startswith('--cwd='):
+                    del runargs[i]
+                    break
+                elif runargs[i].startswith('--cwd'):
+                    del runargs[i:i + 2]
+                    break
+            def condfn():
+                return not os.path.exists(lockpath)
+            pid = util.rundetached(runargs, condfn)
+            if pid < 0:
+                raise error.Abort(_('child process failed to start'))
+            writepid(pid)
+        finally:
+            try:
+                os.unlink(lockpath)
+            except OSError as e:
+                if e.errno != errno.ENOENT:
+                    raise
+        if parentfn:
+            return parentfn(pid)
+        else:
+            return
+
+    if initfn:
+        initfn()
+
+    if not opts['daemon']:
+        writepid(util.getpid())
+
+    if opts['daemon_postexec']:
+        try:
+            os.setsid()
+        except AttributeError:
+            pass
+        for inst in opts['daemon_postexec']:
+            if inst.startswith('unlink:'):
+                lockpath = inst[7:]
+                os.unlink(lockpath)
+            elif inst.startswith('chdir:'):
+                os.chdir(inst[6:])
+            elif inst != 'none':
+                raise error.Abort(_('invalid value for --daemon-postexec: %s')
+                                  % inst)
+        util.hidewindow()
+        util.stdout.flush()
+        util.stderr.flush()
+
+        nullfd = os.open(os.devnull, os.O_RDWR)
+        logfilefd = nullfd
+        if logfile:
+            logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
+        os.dup2(nullfd, 0)
+        os.dup2(logfilefd, 1)
+        os.dup2(logfilefd, 2)
+        if nullfd not in (0, 1, 2):
+            os.close(nullfd)
+        if logfile and logfilefd not in (0, 1, 2):
+            os.close(logfilefd)
+
+    if runfn:
+        return runfn()