view mercurial/hgweb/__init__.py @ 35460:8652ab4046e4

osutil: add a function to unblock signals Signals could be blocked by something like: #include <unistd.h> #include <signal.h> int main(int argc, char * const argv[]) { sigset_t set; sigfillset(&set); sigprocmask(SIG_BLOCK, &set, NULL); execv("/bin/hg", argv); return 0; } One of the problems is if SIGCHLD is blocked, chgserver would not reap zombie workers since it depends on SIGCHLD handler entirely. While it's the parent process to blame but it seems a good idea to just unblock the signal from hg. FWIW git does that for SIGPIPE already [1]. Unfortunately Python 2 does not reset or provide APIs to change signal masks. Therefore let's add one in osutil. Note: Python 3.3 introduced `signal.pthread_sigmask` which solves the problem. `sigprocmask` is part of POSIX [2] so there is no feature testing in `setup.py`. [1]: https://github.com/git/git/commit/7559a1be8a0afb10df41d25e4cf4c5285a5faef1 [2]: http://pubs.opengroup.org/onlinepubs/7908799/xsh/sigprocmask.html Differential Revision: https://phab.mercurial-scm.org/D1736
author Jun Wu <quark@fb.com>
date Wed, 20 Dec 2017 02:13:35 -0800
parents c51380879054
children a8a902d7176e
line wrap: on
line source

# hgweb/__init__.py - web interface to a mercurial repository
#
# Copyright 21 May 2005 - (c) 2005 Jake Edge <jake@edge2.net>
# Copyright 2005 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 _

from .. import (
    error,
    pycompat,
    util,
)

from . import (
    hgweb_mod,
    hgwebdir_mod,
    server,
)

def hgweb(config, name=None, baseui=None):
    '''create an hgweb wsgi object

    config can be one of:
    - repo object (single repo view)
    - path to repo (single repo view)
    - path to config file (multi-repo view)
    - dict of virtual:real pairs (multi-repo view)
    - list of virtual:real tuples (multi-repo view)
    '''

    if ((isinstance(config, str) and not os.path.isdir(config)) or
        isinstance(config, dict) or isinstance(config, list)):
        # create a multi-dir interface
        return hgwebdir_mod.hgwebdir(config, baseui=baseui)
    return hgweb_mod.hgweb(config, name=name, baseui=baseui)

def hgwebdir(config, baseui=None):
    return hgwebdir_mod.hgwebdir(config, baseui=baseui)

class httpservice(object):
    def __init__(self, ui, app, opts):
        self.ui = ui
        self.app = app
        self.opts = opts

    def init(self):
        util.setsignalhandler()
        self.httpd = server.create_server(self.ui, self.app)

        if self.opts['port'] and not self.ui.verbose:
            return

        if self.httpd.prefix:
            prefix = self.httpd.prefix.strip('/') + '/'
        else:
            prefix = ''

        port = r':%d' % self.httpd.port
        if port == r':80':
            port = r''

        bindaddr = self.httpd.addr
        if bindaddr == r'0.0.0.0':
            bindaddr = r'*'
        elif r':' in bindaddr: # IPv6
            bindaddr = r'[%s]' % bindaddr

        fqaddr = self.httpd.fqaddr
        if r':' in fqaddr:
            fqaddr = r'[%s]' % fqaddr
        if self.opts['port']:
            write = self.ui.status
        else:
            write = self.ui.write
        write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
              (pycompat.sysbytes(fqaddr), pycompat.sysbytes(port),
               prefix, pycompat.sysbytes(bindaddr), self.httpd.port))
        self.ui.flush()  # avoid buffering of status message

    def run(self):
        self.httpd.serve_forever()

def createapp(baseui, repo, webconf):
    if webconf:
        return hgwebdir_mod.hgwebdir(webconf, baseui=baseui)
    else:
        if not repo:
            raise error.RepoError(_("there is no Mercurial repository"
                                    " here (.hg not found)"))
        return hgweb_mod.hgweb(repo, baseui=baseui)