/docs/MercurialApp Gawel's repository

author Gael Pasgrimaud <gael@gawel.org>
Fri Mar 12 19:58:49 2010 +0100 (6 months ago)
changeset 115 78cd1888a2c1
parent 114 f166b03b2a43
child 117 cf5c8d31cf34
permissions -rw-r--r--
fix tests
     1 # -*- coding: utf-8 -*-
     2 from ConfigObject import ConfigObject
     3 from mercurial import config
     4 from mercurial import ui
     5 from webob import exc
     6 from hgapp import config as hgconfig
     7 import subprocess
     8 import logging
     9 import sys
    10 import os
    12 log = logging.getLogger(__name__)
    14 def check_perm(req, op):
    15     '''Check permission for operation based on request data (including
    16     authentication info). Return if op allowed, else raise an ErrorResponse
    17     exception.'''
    19     user = req.environ.get('REMOTE_USER')
    20     c = req.environ['baseui']
    21     credentials = req.environ.get('repoze.what.credentials', {})
    22     permissions = credentials.get('permissions', ())
    24     if user and permissions:
    25         log.debug('%(PATH_INFO)s: %(REMOTE_USER)s - %(repoze.what.credentials)s',
    26                   req.environ)
    27     elif user:
    28         log.debug('%(PATH_INFO)s: %(REMOTE_USER)s', req.environ)
    30     def append(option):
    31         if user:
    32             value = c.configlist('web', option)
    33             value.append(user)
    34             value = ' '.join([i for i in value if i and i not in '-'])
    35             log.debug('Setting value %s to %r', option, value)
    36             c.setconfig('web', option, value)
    38     if user and 'allow_read' in permissions:
    39         append('allow_read')
    40     elif user and 'allow_read' not in permissions:
    41         deny_read = c.configlist('web', 'deny_read')
    42         if deny_read and (not user or deny_read == ['*'] or user in deny_read):
    43             log.debug('deny_read success')
    44             resp = exc.HTTPUnauthorized()
    45             resp.status = '%s %s' % (resp.code, 'read not authorized')
    46             raise resp
    48         allow_read = c.configlist('web', 'allow_read')
    49         result = (not allow_read) or (allow_read == ['*'])
    50         if not (result or user in allow_read):
    51             resp = exc.HTTPUnauthorized()
    52             resp.status = '%s %s' % (resp.code, 'read not authorized')
    53             raise resp
    54     else:
    55         allow_read = c.configlist('web', 'allow_read')
    56         if allow_read != ['*'] and user not in allow_read:
    57             log.debug('allow_read failed')
    58             resp = exc.HTTPUnauthorized()
    59             resp.status = '%s %s' % (resp.code, 'read not authorized')
    60             raise resp
    62     if op == 'pull' and not c.configbool('web', 'allowpull', True):
    63         log.debug('allow_pull failed')
    64         resp = exc.HTTPUnauthorized()
    65         resp.status = '%s %s' % (resp.code, 'pull not authorized')
    66         raise resp
    67     elif op == 'pull' or op is None: # op is None for interface requests
    68         return
    70     # enforce that you can only push using POST requests
    71     if req.environ['REQUEST_METHOD'] != 'POST':
    72         resp = exc.HTTPUnauthorized()
    73         resp.status = '%s %s' % (resp.code, 'push requires POST request')
    74         raise resp
    76     # require ssl by default for pushing, auth info cannot be sniffed
    77     # and replayed
    78     if c.configbool('web', 'push_ssl', True) and req.scheme != 'https':
    79         log.debug('puch_ssl fail')
    80         resp = exc.HTTPMethodNotAllowed()
    81         resp.status = '%s %s' % (resp.code, 'ssl required')
    82         raise resp
    84     if not user:
    85         resp = exc.HTTPUnauthorized()
    86         resp.status = '%s %s' % (resp.code, 'push not allowed')
    87         raise resp
    89     if 'allow_push' in permissions:
    90         append('allow_push')
    91     elif 'allow_push' not in permissions:
    92         deny = c.configlist('web', 'deny_push')
    93         if deny and (not user or deny == ['*'] or user in deny):
    94             log.debug('deny_push success')
    95             resp = exc.HTTPUnauthorized()
    96             resp.status = '%s %s' % (resp.code, 'push not allowed')
    97             raise resp
    99         allow = c.configlist('web', 'allow_push')
   100         result = allow and (allow == ['*'] or user in allow)
   101         if not result:
   102             log.debug('allow_push fail')
   103             resp = exc.HTTPUnauthorized()
   104             resp.status = '%s %s' % (resp.code, 'push not allowed')
   105             raise resp
   106     else:
   107         allow_push = c.configlist('web', 'allow_push')
   108         if allow_push != ['*'] and user not in allow_read:
   109             append('allow_push')
   111 def get_binary(suffix=None):
   112     binary = os.path.abspath(sys.argv[0])
   113     dirname = os.path.dirname(binary)
   114     if os.path.isfile(os.path.join(dirname, 'hgapp')):
   115         binary = os.path.join(dirname, 'hgapp')
   116     else:
   117         binary = binary.split('-')[0]
   118     if suffix:
   119         binary += '-%s' % suffix
   120     return binary
   122 def cmd(*args, **kwargs):
   123     binary = kwargs.get('binary', get_binary())
   124     cwd = os.getcwd()
   125     os.chdir(kwargs.get('dirname', os.getcwd()))
   126     cmd = [binary]+list(args)
   127     if subprocess.call(cmd) != 0:
   128         print 'Error while running %s' % ' '.join(cmd)
   129     os.chdir(cwd)
   131 def run(*args, **kwargs):
   132     cwd = os.getcwd()
   133     os.chdir(kwargs.get('dirname', os.getcwd()))
   134     if subprocess.call(list(args)) != 0:
   135         print 'Error while running %s' % ' '.join(cmd)
   136     os.chdir(cwd)
   138 def hgrc(dirname):
   139     filename = os.path.join(dirname, '.hg', 'hgrc')
   140     return filename
   142 def is_repository(dirname):
   143     for name in ('data', 'store'):
   144         exist = os.path.join(dirname, '.hg', name)
   145         if os.path.isdir(exist):
   146             return True
   147     return False
   149 def get_repo(path_info, user=None, cmd=''):
   150     path_info = path_info.strip('/')
   151     if '/' in path_info:
   152         name, path_info = path_info.split('/', 1)
   153     else:
   154         name = 'main'
   156     if name == 'config':
   157         return None, None, None
   159     repo = ui = c = None
   161     userdir = hgconfig['hg:config'].userdir
   162     if user and userdir:
   163         home = os.path.join(userdir, user)
   164         if not os.path.isdir(home):
   165             os.makedirs(home)
   166             cfg = ConfigObject()
   167             cfg.web = dict(allow_read='*', allow_push=user)
   168             fd = open(os.path.join(home, '.hgrc'), 'w')
   169             cfg.write(fd)
   170             fd.close()
   171         userdir = os.path.join(userdir, name)
   173     if userdir and os.path.isdir(userdir):
   174         c = hgconfig['hg:%s' % name]
   175         c.hgwebdir = userdir
   176         c.allow_push = name
   177         c.allow_read = name
   178     else:
   179         c = hgconfig['hg:%s' % name]
   180         c.name = name
   182     c.path_info = path_info
   183     if c.get('hgweb', None) and c.hgweb.endswith(path_info):
   184         repo = c.hgweb
   185     elif c.get('hgwebdir', None):
   186         path = os.path.join(c.hgwebdir, path_info)
   187         if is_repository(path):
   188             repo = path
   189         elif cmd.startswith('hg init'):
   190             repo = path
   192     ui = get_ui(c)
   194     return repo, ui, c
   196 def get_ui(section):
   197     baseui = ui.ui()
   199     baseui.setconfig('ui', 'username', 'unknown')
   200     for k in ('report_untrusted', 'interactive'):
   201         baseui.setconfig('ui', k, section.get(k, 'off').as_bool('on', 'off'))
   203     baseui.setconfig('web', 'style', 'gitweb')
   204     baseui.setconfig('web', 'encoding', 'utf-8')
   205     baseui.setconfig('web', 'push_ssl', section.push_ssl.as_bool('on', 'off'))
   206     baseui.setconfig('web', 'allowpull', section.get('allowpull', 'on').as_bool('on', 'off'))
   208     for k in ('allow_read', 'allow_push', 'deny_read', 'deny_push'):
   209         v = section.get(k).as_list(sep=' ')
   210         if v:
   211             baseui.setconfig('web', k, ' '.join(v))
   213     baseui.setconfig('hooks', 'changegroup.hgapp_sphinx',
   214                           'python:hgapp.hooks.sphinx_update')
   216     filename = ''
   217     if section.hgweb:
   218         filename = isfile(hgrc(section.hgweb))
   219     elif section.hgwebdir:
   220         filename = isfile(section.hgwebdir, '.hgrc')
   221         sphinxroot = os.path.join(section.hgwebdir, '.sphinx')
   222         baseui.setconfig('hgapp', 'sphinxroot', sphinxroot)
   223         section.sphinx_docs = os.path.join(sphinxroot, 'html')
   225     if filename:
   226         cfg = config.config()
   227         cfg.read(filename)
   228         for k, v in cfg.items('web'):
   229             baseui.setconfig('web', k, v)
   231     return baseui
   233 def isfile(*args):
   234      filename = os.path.join(*args)
   235      filename = os.path.realpath(filename)
   236      if os.path.isfile(filename):
   237          return filename
   238      return False
   240 def load_config(*filenames):
   241     if not filenames:
   242         filenames = ['/etc/hgapp/hgapp.ini', os.path.expanduser('~/hgapp.ini'), 'hgapp.ini']
   243         filenames = [filename for filename in filenames if os.path.isfile(filename)]
   244         if not filenames:
   245             raise RuntimeError("Cannot find a hgapp.ini")
   246     filename = os.path.abspath(filenames[-1])
   247     cfg = ConfigObject(dict(here=os.path.dirname(filename),
   248                             __file__=filename))
   249     cfg.read([filename])
   250     cfg.__file__ = filename
   251     return cfg