contrib/win32/hgwebdir_wsgi.py
author Augie Fackler <augie@google.com>
Mon, 24 Jul 2017 14:38:40 -0400
changeset 33839 7d5bc0e5b88f
parent 29385 aa1d56003872
child 41849 d22198b4b3dd
permissions -rw-r--r--
py3: introduce a wrapper for __builtins__.{raw_,}input() In order to make this work, we have to wrap the io streams in a TextIOWrapper so that __builtins__.input() can do unicode IO on Python 3. We can't just restore the original (unicode) sys.std* because we might be running a cmdserver, and if we blindly restore sys.* to the original values then we end up breaking the cmdserver. Sadly, TextIOWrapper tries to close the underlying stream during its __del__, so we have to make a sublcass to prevent that. If you see errors like: TypeError: a bytes-like object is required, not 'str' On an input() or print() call on Python 3, the substitution of sys.std* is probably the root cause. A previous version of this change tried to put the bytesinput() method in pycompat - it turns out we need to do some encoding handling, so we have to be in a higher layer that's allowed to use mercurial.encoding.encoding. As a result, this is in util for now, with the TextIOWrapper subclass hiding in encoding.py. I'm not sure of a better place for the time being. Differential Revision: https://phab.mercurial-scm.org/D299

# An example WSGI script for IIS/isapi-wsgi to export multiple hgweb repos
# Copyright 2010-2016 Sune Foldager <cyano@me.com>
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
#
# Requirements:
# - Python 2.7, preferably 64 bit
# - PyWin32 for Python 2.7 (32 or 64 bit)
# - Mercurial installed from source (python setup.py install) or download the
#   python module installer from https://www.mercurial-scm.org/wiki/Download
# - IIS 7 or newer
#
#
# Installation and use:
#
# - Download or clone the isapi-wsgi source and run python setup.py install.
#   https://github.com/hexdump42/isapi-wsgi
#
# - Create a directory to hold the shim dll, config files etc. This can reside
#   inside the standard IIS directory, C:\inetpub, or anywhere else. Copy this
#   script there.
#
# - Run this script (i.e. python hgwebdir_wsgi.py) to get a shim dll. The
#   shim is identical for all scripts, so you can just copy and rename one
#   from an earlier run, if you wish. The shim needs to reside in the same
#   directory as this script.
#
# - Start IIS manager and create a new app pool:
#   .NET CLR Version: No Managed Code
#   Advanced Settings: Enable 32 Bit Applications, if using 32 bit Python.
#   You can adjust the identity and maximum worker processes if you wish. This
#   setup works fine with multiple worker processes.
#
# - Create an IIS application where your hgwebdir is to be served from.
#   Assign it the app pool you just created and point its physical path to the
#   directory you created.
#
# - In the application, remove all handler mappings and setup a wildcard script
#   handler mapping of type IsapiModule with the shim dll as its executable.
#   This file MUST reside in the same directory as the shim. The easiest way
#   to do all this is to close IIS manager, place a web.config file in your
#   directory and start IIS manager again. The file should contain:
#
#   <?xml version="1.0" encoding="UTF-8"?>
#   <configuration>
#       <system.webServer>
#           <handlers accessPolicy="Read, Script">
#               <clear />
#               <add name="hgwebdir" path="*" verb="*" modules="IsapiModule"
#                    scriptProcessor="C:\your\directory\_hgwebdir_wsgi.dll"
#                    resourceType="Unspecified" requireAccess="None"
#                    preCondition="bitness64" />
#           </handlers>
#       </system.webServer>
#   </configuration>
#
#   Where "bitness64" should be replaced with "bitness32" for 32 bit Python.
#
# - Edit ISAPI And CGI Restrictions on the web server (global setting). Add a
#   restriction pointing to your shim dll and allow it to run.
#
# - Create a configuration file in your directory and adjust the configuration
#   variables below to match your needs. Example configuration:
#
#   [web]
#   style = gitweb
#   push_ssl = false
#   allow_push = *
#   encoding = utf8
#
#   [server]
#   validate = true
#
#   [paths]
#   repo1 = c:\your\directory\repo1
#   repo2 = c:\your\directory\repo2
#
# - Restart the web server and see if things are running.
#

from __future__ import absolute_import

# Configuration file location
hgweb_config = r'c:\your\directory\wsgi.config'

# Global settings for IIS path translation
path_strip = 0   # Strip this many path elements off (when using url rewrite)
path_prefix = 1  # This many path elements are prefixes (depends on the
                 # virtual path of the IIS application).

import sys

# Adjust python path if this is not a system-wide install
#sys.path.insert(0, r'C:\your\custom\hg\build\lib.win32-2.7')

# Enable tracing. Run 'python -m win32traceutil' to debug
if getattr(sys, 'isapidllhandle', None) is not None:
    import win32traceutil
    win32traceutil.SetupForPrint # silence unused import warning

import isapi_wsgi
from mercurial.hgweb.hgwebdir_mod import hgwebdir

# Example tweak: Replace isapi_wsgi's handler to provide better error message
# Other stuff could also be done here, like logging errors etc.
class WsgiHandler(isapi_wsgi.IsapiWsgiHandler):
    error_status = '500 Internal Server Error' # less silly error message

isapi_wsgi.IsapiWsgiHandler = WsgiHandler

# Only create the hgwebdir instance once
application = hgwebdir(hgweb_config)

def handler(environ, start_response):

    # Translate IIS's weird URLs
    url = environ['SCRIPT_NAME'] + environ['PATH_INFO']
    paths = url[1:].split('/')[path_strip:]
    script_name = '/' + '/'.join(paths[:path_prefix])
    path_info = '/'.join(paths[path_prefix:])
    if path_info:
        path_info = '/' + path_info
    environ['SCRIPT_NAME'] = script_name
    environ['PATH_INFO'] = path_info

    return application(environ, start_response)

def __ExtensionFactory__():
    return isapi_wsgi.ISAPISimpleHandler(handler)

if __name__=='__main__':
    from isapi.install import ISAPIParameters, HandleCommandLine
    params = ISAPIParameters()
    HandleCommandLine(params)