##// END OF EJS Templates
py3: use `except error as e` instead of `except error, e`...
py3: use `except error as e` instead of `except error, e` The latter throws SyntaxError on Python 3. Differential Revision: https://phab.mercurial-scm.org/D3613

File last commit:

r37233:d2bd29df default
r38100:f0fadc5b default
Show More
server.py
211 lines | 6.8 KiB | text/x-python | PythonLexer
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 # 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 os
import tempfile
from .i18n import _
from . import (
Yuya Nishihara
chgserver: make it a core module and drop extension flags...
r30513 chgserver,
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005 cmdutil,
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 commandserver,
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 error,
Yuya Nishihara
server: move service factory from hgweb
r30509 hgweb,
Augie Fackler
server: use pycompat to get argv
r32530 pycompat,
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 util,
)
Yuya Nishihara
procutil: bulk-replace util.std* to point to new module
r37137 from .utils import (
procutil,
)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 def runservice(opts, parentfn=None, initfn=None, runfn=None, logfile=None,
runargs=None, appendpid=False):
'''Run a command as a service.'''
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 postexecargs = {}
if opts['daemon_postexec']:
for inst in opts['daemon_postexec']:
if inst.startswith('unlink:'):
postexecargs['unlink'] = inst[7:]
elif inst.startswith('chdir:'):
postexecargs['chdir'] = inst[6:]
elif inst != 'none':
raise error.Abort(_('invalid value for --daemon-postexec: %s')
% inst)
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229 # When daemonized on Windows, redirect stdout/stderr to the lockfile (which
# gets cleaned up after the child is up and running), so that the parent can
# read and print the error if this child dies early. See 594dd384803c. On
# other platforms, the child can write to the parent's stdio directly, until
# it is redirected prior to runfn().
if pycompat.iswindows and opts['daemon_postexec']:
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 if 'unlink' in postexecargs and os.path.exists(postexecargs['unlink']):
procutil.stdout.flush()
procutil.stderr.flush()
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 fd = os.open(postexecargs['unlink'],
os.O_WRONLY | os.O_APPEND | os.O_BINARY)
try:
Matt Harbison
server: minor code cleanup...
r37233 os.dup2(fd, procutil.stdout.fileno())
os.dup2(fd, procutil.stderr.fileno())
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 finally:
os.close(fd)
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 def writepid(pid):
if opts['pid_file']:
if appendpid:
Augie Fackler
server: write out pid using bytes IO instead of str IO
r32548 mode = 'ab'
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 else:
Augie Fackler
server: write out pid using bytes IO instead of str IO
r32548 mode = 'wb'
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 fp = open(opts['pid_file'], mode)
Yuya Nishihara
py3: simply use b'%d\n' to format pid in server.py...
r32617 fp.write('%d\n' % pid)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 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:
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 runargs = procutil.hgcmd() + pycompat.sysargv[1:]
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 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)
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 pid = procutil.rundetached(runargs, condfn)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 if pid < 0:
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229 # If the daemonized process managed to write out an error msg,
# report it.
if pycompat.iswindows and os.path.exists(lockpath):
Matt Harbison
server: minor code cleanup...
r37233 with open(lockpath, 'rb') as log:
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229 for line in log:
procutil.stderr.write(line)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 raise error.Abort(_('child process failed to start'))
writepid(pid)
finally:
Ryan McElroy
server: use tryunlink
r31548 util.tryunlink(lockpath)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 if parentfn:
return parentfn(pid)
else:
return
if initfn:
initfn()
if not opts['daemon']:
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 writepid(procutil.getpid())
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506
if opts['daemon_postexec']:
try:
os.setsid()
except AttributeError:
pass
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 if 'chdir' in postexecargs:
os.chdir(postexecargs['chdir'])
Yuya Nishihara
procutil: bulk-replace function calls to point to new module
r37138 procutil.hidewindow()
Yuya Nishihara
procutil: bulk-replace util.std* to point to new module
r37137 procutil.stdout.flush()
procutil.stderr.flush()
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506
nullfd = os.open(os.devnull, os.O_RDWR)
logfilefd = nullfd
if logfile:
Yuya Nishihara
server: drop executable bit from daemon log file...
r34925 logfilefd = os.open(logfile, os.O_RDWR | os.O_CREAT | os.O_APPEND,
0o666)
Matt Harbison
server: minor code cleanup...
r37233 os.dup2(nullfd, procutil.stdin.fileno())
os.dup2(logfilefd, procutil.stdout.fileno())
os.dup2(logfilefd, procutil.stderr.fileno())
stdio = (procutil.stdin.fileno(), procutil.stdout.fileno(),
procutil.stderr.fileno())
if nullfd not in stdio:
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 os.close(nullfd)
Matt Harbison
server: minor code cleanup...
r37233 if logfile and logfilefd not in stdio:
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 os.close(logfilefd)
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229 # Only unlink after redirecting stdout/stderr, so Windows doesn't
# complain about a sharing violation.
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 if 'unlink' in postexecargs:
os.unlink(postexecargs['unlink'])
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 if runfn:
return runfn()
Yuya Nishihara
server: move service table and factory from commandserver...
r30507
_cmdservicemap = {
Yuya Nishihara
chgserver: make it a core module and drop extension flags...
r30513 'chgunix': chgserver.chgunixservice,
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 'pipe': commandserver.pipeservice,
'unix': commandserver.unixforkingservice,
}
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510 def _createcmdservice(ui, repo, opts):
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 mode = opts['cmdserver']
try:
return _cmdservicemap[mode](ui, repo, opts)
except KeyError:
raise error.Abort(_('unknown mode %s') % mode)
Yuya Nishihara
server: move service factory from hgweb
r30509
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510 def _createhgwebservice(ui, repo, opts):
Yuya Nishihara
server: move service factory from hgweb
r30509 # this way we can check if something was given in the command-line
if opts.get('port'):
opts['port'] = util.getport(opts.get('port'))
Martin von Zweigbergk
cleanup: use set literals...
r32291 alluis = {ui}
Yuya Nishihara
server: move service factory from hgweb
r30509 if repo:
baseui = repo.baseui
alluis.update([repo.baseui, repo.ui])
else:
baseui = ui
webconf = opts.get('web_conf') or opts.get('webdir_conf')
if webconf:
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005 if opts.get('subrepos'):
raise error.Abort(_('--web-conf cannot be used with --subrepos'))
Yuya Nishihara
server: move service factory from hgweb
r30509 # load server settings (e.g. web.port) to "copied" ui, which allows
# hgwebdir to reload webconf cleanly
servui = ui.copy()
servui.readconfig(webconf, sections=['web'])
alluis.add(servui)
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005 elif opts.get('subrepos'):
servui = ui
# If repo is None, hgweb.createapp() already raises a proper abort
# message as long as webconf is None.
if repo:
webconf = dict()
cmdutil.addwebdirpath(repo, "", webconf)
Yuya Nishihara
server: move service factory from hgweb
r30509 else:
servui = ui
optlist = ("name templates style address port prefix ipv6"
" accesslog errorlog certificate encoding")
for o in optlist.split():
val = opts.get(o, '')
if val in (None, ''): # should check against default options instead
continue
for u in alluis:
u.setconfig("web", o, val, 'serve')
app = hgweb.createapp(baseui, repo, webconf)
return hgweb.httpservice(servui, app, opts)
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510
def createservice(ui, repo, opts):
if opts["cmdserver"]:
return _createcmdservice(ui, repo, opts)
else:
return _createhgwebservice(ui, repo, opts)