view contrib/win32/hgwebdir_wsgi.py @ 37518:092eff6833a7

lfs: infer the blob store URL from paths.default If `lfs.url` is specified, it takes precedence. However, now that we support serving blobs via hgweb, we shouldn't *require* this setting. Less configuration is better (things will work out of the box once this is sorted out), and git has similar functionality. This is not a complete solution- it isn't able to infer the blob store from an explicitly supplied path, and it should consider `paths.default-push` for push. The pull solution for that is a bit hacky, and this alone is an improvement for the vast majority of cases. Even though there are only a handful of references to the saved remote store, the location of them makes things complicated. 1) downloading files on demand in the revlog flag processor 2) copying to readonlyvfs with bundlerepo 3) downloading in the file prefetch hook 4) the canupload()/skipdownload() checks 5) uploading blobs Since revlog doesn't have a repo or ui reference, we can't avoid creating a remote store when the extension is loaded. While the long term goal is to make sure the prefetch hook is invoked early for every command for efficiency, this handling in the flag processor is needed as a last ditch fetch. In order to support the clone command, the remote store needs to be created later than when the extension loads, since `paths.default` isn't set until just before the files are checked out. Therefore, this patch changes the prefetch hook to ignore the saved reference, and build a new one. The canupload()/skipdownload() checks simply check if the stored instance is a `_nullremote`. Since this can only be set via `lfs.url` (which is reflected in the saved reference), checking only the instance created when the extension loaded is fine. The blob uploading function is called from several places: 1) a prepush hook 2) when writing a new bundle 3) from infinitepush The prepush hook gets an exchange.pushop, so it has a path to where the push is going. The bundle writer and infinitepush don't. Further, bundle creation for things like strip and amend are causing blobs to be uploaded. This seems wrong, but I don't want to side track this sorting that out, so punt on trying to handle explicit push paths or `paths.default-push`. I also think that sending blobs to a remote store when pushing to a local repo is wrong. This functionality predates the usercache, so perhaps that's the reason for it. I've got some patches floating around to stop sending blobs remotely in this case, and instead write directly to the other repo's blob store. But the tests for corruption handling weren't happy with this change, and I don't have time to rewrite them. So exclude filesystem based paths from this for now. I don't think there's much of a chance to implement `paths.remote:lfsurl` style configs, given how early these are resolved vs how late the remote store is created. But git has it, so I threw a TODO in there, in case anyone has ideas. I have no idea why this is now doing http auth twice when it wasn't before. I don't think the original blobstore's url is ever being used in these cases.
author Matt Harbison <matt_harbison@yahoo.com>
date Sat, 07 Apr 2018 22:22:20 -0400
parents aa1d56003872
children d22198b4b3dd
line wrap: on
line source

# 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)