comparison mercurial/cmdutil.py @ 30515:d9d8d78e6bc9

server: move cmdutil.service() to new module (API) And call it runservice() because I'll soon add createservice(). The main reason I'm going to introduce the 'server' module is to solve future dependency cycle between chgserver.py and commandserver.py. The 'server' module sits at the same layer as the cmdutil. I believe it's generally good to get rid of things from the big cmdutil module.
author Yuya Nishihara <yuya@tcha.org>
date Sat, 15 Oct 2016 13:47:43 +0900
parents 002fa4d79466
children 20a42325fdef
comparison
equal deleted inserted replaced
30514:158b41842fd2 30515:d9d8d78e6bc9
8 from __future__ import absolute_import 8 from __future__ import absolute_import
9 9
10 import errno 10 import errno
11 import os 11 import os
12 import re 12 import re
13 import sys
14 import tempfile 13 import tempfile
15 14
16 from .i18n import _ 15 from .i18n import _
17 from .node import ( 16 from .node import (
18 bin, 17 bin,
818 817
819 if errors: 818 if errors:
820 ui.warn(_('(consider using --after)\n')) 819 ui.warn(_('(consider using --after)\n'))
821 820
822 return errors != 0 821 return errors != 0
823
824 def service(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
825 runargs=None, appendpid=False):
826 '''Run a command as a service.'''
827
828 def writepid(pid):
829 if opts['pid_file']:
830 if appendpid:
831 mode = 'a'
832 else:
833 mode = 'w'
834 fp = open(opts['pid_file'], mode)
835 fp.write(str(pid) + '\n')
836 fp.close()
837
838 if opts['daemon'] and not opts['daemon_postexec']:
839 # Signal child process startup with file removal
840 lockfd, lockpath = tempfile.mkstemp(prefix='hg-service-')
841 os.close(lockfd)
842 try:
843 if not runargs:
844 runargs = util.hgcmd() + sys.argv[1:]
845 runargs.append('--daemon-postexec=unlink:%s' % lockpath)
846 # Don't pass --cwd to the child process, because we've already
847 # changed directory.
848 for i in xrange(1, len(runargs)):
849 if runargs[i].startswith('--cwd='):
850 del runargs[i]
851 break
852 elif runargs[i].startswith('--cwd'):
853 del runargs[i:i + 2]
854 break
855 def condfn():
856 return not os.path.exists(lockpath)
857 pid = util.rundetached(runargs, condfn)
858 if pid < 0:
859 raise error.Abort(_('child process failed to start'))
860 writepid(pid)
861 finally:
862 try:
863 os.unlink(lockpath)
864 except OSError as e:
865 if e.errno != errno.ENOENT:
866 raise
867 if parentfn:
868 return parentfn(pid)
869 else:
870 return
871
872 if initfn:
873 initfn()
874
875 if not opts['daemon']:
876 writepid(util.getpid())
877
878 if opts['daemon_postexec']:
879 try:
880 os.setsid()
881 except AttributeError:
882 pass
883 for inst in opts['daemon_postexec']:
884 if inst.startswith('unlink:'):
885 lockpath = inst[7:]
886 os.unlink(lockpath)
887 elif inst.startswith('chdir:'):
888 os.chdir(inst[6:])
889 elif inst != 'none':
890 raise error.Abort(_('invalid value for --daemon-postexec: %s')
891 % inst)
892 util.hidewindow()
893 util.stdout.flush()
894 util.stderr.flush()
895
896 nullfd = os.open(os.devnull, os.O_RDWR)
897 logfilefd = nullfd
898 if logfile:
899 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND)
900 os.dup2(nullfd, 0)
901 os.dup2(logfilefd, 1)
902 os.dup2(logfilefd, 2)
903 if nullfd not in (0, 1, 2):
904 os.close(nullfd)
905 if logfile and logfilefd not in (0, 1, 2):
906 os.close(logfilefd)
907
908 if runfn:
909 return runfn()
910 822
911 ## facility to let extension process additional data into an import patch 823 ## facility to let extension process additional data into an import patch
912 # list of identifier to be executed in order 824 # list of identifier to be executed in order
913 extrapreimport = [] # run before commit 825 extrapreimport = [] # run before commit
914 extrapostimport = [] # run after commit 826 extrapostimport = [] # run after commit