##// END OF EJS Templates
lfs: move the initialization of the upload request into the try block...
lfs: move the initialization of the upload request into the try block This (almost) guarantees that the file is closed in the case of an exception. The one hole is if the `seek(SEEK_END)`/`tell()`/`seek(0)` sequence fails. But that's going to go away when subclassing `httpconnection.httpsendfile` to fix the worker problem, so I'm not going to worry too much. (And that class appears to have the same problem.) Differential Revision: https://phab.mercurial-scm.org/D7959

File last commit:

r43355:eef9a2d6 default
r44599:46c8f15f default
Show More
server.py
235 lines | 7.0 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
from .i18n import _
Gregory Szorc
py3: manually import pycompat.open into files that need it...
r43355 from .pycompat import open
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506
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,
)
Augie Fackler
formatting: blacken the codebase...
r43346 from .utils import procutil
Yuya Nishihara
procutil: bulk-replace util.std* to point to new module
r37137
Augie Fackler
formatting: blacken the codebase...
r43346 def runservice(
opts,
parentfn=None,
initfn=None,
runfn=None,
logfile=None,
runargs=None,
appendpid=False,
):
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 '''Run a command as a service.'''
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 postexecargs = {}
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b'daemon_postexec']:
for inst in opts[b'daemon_postexec']:
if inst.startswith(b'unlink:'):
postexecargs[b'unlink'] = inst[7:]
elif inst.startswith(b'chdir:'):
postexecargs[b'chdir'] = inst[6:]
elif inst != b'none':
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'invalid value for --daemon-postexec: %s') % inst
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232
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().
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if pycompat.iswindows and opts[b'daemon_postexec']:
if b'unlink' in postexecargs and os.path.exists(
postexecargs[b'unlink']
):
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 procutil.stdout.flush()
procutil.stderr.flush()
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Augie Fackler
formatting: blacken the codebase...
r43346 fd = os.open(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 postexecargs[b'unlink'], os.O_WRONLY | os.O_APPEND | os.O_BINARY
Augie Fackler
formatting: blacken the codebase...
r43346 )
Matt Harbison
server: refactor 'daemon_postexec' instructions into a dictionary
r37232 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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b'pid_file']:
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 if appendpid:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mode = b'ab'
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mode = b'wb'
fp = open(opts[b'pid_file'], mode)
fp.write(b'%d\n' % pid)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 fp.close()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b'daemon'] and not opts[b'daemon_postexec']:
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 # Signal child process startup with file removal
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 lockfd, lockpath = pycompat.mkstemp(prefix=b'hg-service-')
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 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:]
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 runargs.append(b'--daemon-postexec=unlink:%s' % lockpath)
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 # Don't pass --cwd to the child process, because we've already
# changed directory.
Gregory Szorc
global: use pycompat.xrange()...
r38806 for i in pycompat.xrange(1, len(runargs)):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if runargs[i].startswith(b'--cwd='):
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 del runargs[i]
break
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif runargs[i].startswith(b'--cwd'):
Augie Fackler
formatting: blacken the codebase...
r43346 del runargs[i : i + 2]
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 break
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 def condfn():
return not os.path.exists(lockpath)
Augie Fackler
formatting: blacken the codebase...
r43346
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):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with open(lockpath, b'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)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'child process failed to start'))
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if not opts[b'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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b'daemon_postexec']:
Yuya Nishihara
server: move cmdutil.service() to new module (API)...
r30506 try:
os.setsid()
except AttributeError:
pass
Matt Harbison
server: add an error feedback mechanism for when the daemon fails to launch...
r37229
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'chdir' in postexecargs:
os.chdir(postexecargs[b'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:
Augie Fackler
formatting: blacken the codebase...
r43346 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())
Augie Fackler
formatting: blacken the codebase...
r43346 stdio = (
procutil.stdin.fileno(),
procutil.stdout.fileno(),
procutil.stderr.fileno(),
)
Matt Harbison
server: minor code cleanup...
r37233 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.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'unlink' in postexecargs:
os.unlink(postexecargs[b'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
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 _cmdservicemap = {
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'chgunix': chgserver.chgunixservice,
b'pipe': commandserver.pipeservice,
b'unix': commandserver.unixforkingservice,
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 }
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510 def _createcmdservice(ui, repo, opts):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 mode = opts[b'cmdserver']
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 try:
Yuya Nishihara
commandserver: enable logging when server process started...
r40858 servicefn = _cmdservicemap[mode]
Yuya Nishihara
server: move service table and factory from commandserver...
r30507 except KeyError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'unknown mode %s') % mode)
Yuya Nishihara
commandserver: install logger to record server events through canonical API...
r40859 commandserver.setuplogging(ui, repo)
Yuya Nishihara
commandserver: enable logging when server process started...
r40858 return servicefn(ui, repo, opts)
Yuya Nishihara
server: move service factory from hgweb
r30509
Augie Fackler
formatting: blacken the codebase...
r43346
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'port'):
opts[b'port'] = util.getport(opts.get(b'port'))
Yuya Nishihara
server: move service factory from hgweb
r30509
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
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 webconf = opts.get(b'web_conf') or opts.get(b'webdir_conf')
Yuya Nishihara
server: move service factory from hgweb
r30509 if webconf:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'subrepos'):
raise error.Abort(_(b'--web-conf cannot be used with --subrepos'))
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005
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()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 servui.readconfig(webconf, sections=[b'web'])
Yuya Nishihara
server: move service factory from hgweb
r30509 alluis.add(servui)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif opts.get(b'subrepos'):
Matt Harbison
serve: add support for Mercurial subrepositories...
r32005 servui = ui
# If repo is None, hgweb.createapp() already raises a proper abort
# message as long as webconf is None.
if repo:
webconf = dict()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 cmdutil.addwebdirpath(repo, b"", webconf)
Yuya Nishihara
server: move service factory from hgweb
r30509 else:
servui = ui
Augie Fackler
formatting: blacken the codebase...
r43346 optlist = (
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"name templates style address port prefix ipv6"
b" accesslog errorlog certificate encoding"
Augie Fackler
formatting: blacken the codebase...
r43346 )
Yuya Nishihara
server: move service factory from hgweb
r30509 for o in optlist.split():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 val = opts.get(o, b'')
if val in (None, b''): # should check against default options instead
Yuya Nishihara
server: move service factory from hgweb
r30509 continue
for u in alluis:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 u.setconfig(b"web", o, val, b'serve')
Yuya Nishihara
server: move service factory from hgweb
r30509
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
Augie Fackler
formatting: blacken the codebase...
r43346
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510 def createservice(ui, repo, opts):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts[b"cmdserver"]:
Yuya Nishihara
server: add public function to select either cmdserver or hgweb
r30510 return _createcmdservice(ui, repo, opts)
else:
return _createhgwebservice(ui, repo, opts)