##// END OF EJS Templates
added latest changes
added latest changes

File last commit:

r5608:6d33e504 default
r5658:a109f5ac merge default
Show More
simplegit.py
145 lines | 4.9 KiB | text/x-python | PythonLexer
# Copyright (C) 2010-2024 RhodeCode GmbH
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License, version 3
# (only), as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This program is dual-licensed. If you wish to learn more about the
# RhodeCode Enterprise Edition, including its added features, Support services,
# and proprietary license terms, please see https://rhodecode.com/licenses/
"""
SimpleGit middleware for handling git protocol request (push/clone etc.)
It's implemented with basic auth function
"""
import os
import re
import logging
import urllib.parse
import rhodecode
from rhodecode.lib import utils
from rhodecode.lib import utils2
from rhodecode.lib.middleware import simplevcs
from rhodecode.lib.middleware.utils import get_path_info
log = logging.getLogger(__name__)
GIT_PROTO_PAT = re.compile(
r'^/(.+)/(info/refs|info/lfs/(.+)|git-upload-pack|git-receive-pack)')
GIT_LFS_PROTO_PAT = re.compile(r'^/(.+)/(info/lfs/(.+))')
class SimpleGit(simplevcs.SimpleVCS):
SCM = 'git'
def _get_repository_name(self, environ):
"""
Gets repository name out of PATH_INFO header
:param environ: environ where PATH_INFO is stored
"""
path_info = get_path_info(environ)
repo_name = GIT_PROTO_PAT.match(path_info).group(1)
# for GIT LFS, and bare format strip .git suffix from names
if repo_name.endswith('.git'):
repo_name = repo_name[:-4]
return repo_name
def _get_lfs_action(self, path, request_method):
"""
return an action based on LFS requests type.
Those routes are handled inside vcsserver app.
batch -> POST to /info/lfs/objects/batch => PUSH/PULL
batch is based on the `operation.
that could be download or upload, but those are only
instructions to fetch so we return pull always
download -> GET to /info/lfs/{oid} => PULL
upload -> PUT to /info/lfs/{oid} => PUSH
verification -> POST to /info/lfs/verify => PULL
"""
match_obj = GIT_LFS_PROTO_PAT.match(path)
_parts = match_obj.groups()
repo_name, path, operation = _parts
log.debug(
'LFS: detecting operation based on following '
'data: %s, req_method:%s', _parts, request_method)
if operation == 'verify':
return 'pull'
elif operation == 'objects/batch':
# batch sends back instructions for API to dl/upl we report it
# as pull
if request_method == 'POST':
return 'pull'
elif operation:
# probably a OID, upload is PUT, download a GET
if request_method == 'GET':
return 'pull'
else:
return 'push'
# if default not found require push, as action
return 'push'
_ACTION_MAPPING = {
'git-receive-pack': 'push',
'git-upload-pack': 'pull',
}
def _get_action(self, environ):
"""
Maps git request commands into a pull or push command.
In case of unknown/unexpected data, it returns 'pull' to be safe.
:param environ:
"""
path = get_path_info(environ)
if path.endswith('/info/refs'):
query = urllib.parse.parse_qs(environ['QUERY_STRING'])
service_cmd = query.get('service', [''])[0]
return self._ACTION_MAPPING.get(service_cmd, 'pull')
elif GIT_LFS_PROTO_PAT.match(path):
return self._get_lfs_action(path, environ['REQUEST_METHOD'])
elif path.endswith('/git-receive-pack'):
return 'push'
elif path.endswith('/git-upload-pack'):
return 'pull'
return 'pull'
def _create_wsgi_app(self, repo_path, repo_name, config):
return self.scm_app.create_git_wsgi_app(
repo_path, repo_name, config)
def _create_config(self, extras, repo_name, scheme='http'):
extras['git_update_server_info'] = utils2.str2bool(
rhodecode.CONFIG.get('git_update_server_info'))
config = utils.make_db_config(repo=repo_name)
custom_store = config.get('vcs_git_lfs', 'store_location')
extras['git_lfs_enabled'] = utils2.str2bool(
config.get('vcs_git_lfs', 'enabled'))
extras['git_lfs_store_path'] = custom_store
extras['git_lfs_http_scheme'] = scheme
return extras