##// END OF EJS Templates
git-lfs: enable support for detection of git-lfs requests type...
marcink -
r1565:8dba6b09 default
parent child Browse files
Show More
@@ -1,85 +1,153 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2017 RhodeCode GmbH
3 # Copyright (C) 2010-2017 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 SimpleGit middleware for handling git protocol request (push/clone etc.)
22 SimpleGit middleware for handling git protocol request (push/clone etc.)
23 It's implemented with basic auth function
23 It's implemented with basic auth function
24 """
24 """
25 import os
25 import re
26 import re
26 import logging
27 import logging
27 import urlparse
28 import urlparse
28
29
29 import rhodecode
30 import rhodecode
30 from rhodecode.lib import utils2
31 from rhodecode.lib import utils2
31 from rhodecode.lib.middleware import simplevcs
32 from rhodecode.lib.middleware import simplevcs
32
33
33 log = logging.getLogger(__name__)
34 log = logging.getLogger(__name__)
34
35
35
36
36 GIT_PROTO_PAT = re.compile(
37 GIT_PROTO_PAT = re.compile(
37 r'^/(.+)/(info/refs|git-upload-pack|git-receive-pack)')
38 r'^/(.+)/(info/refs|info/lfs/(.+)|git-upload-pack|git-receive-pack)')
39 GIT_LFS_PROTO_PAT = re.compile(r'^/(.+)/(info/lfs/(.+))')
40
41
42 def default_lfs_store():
43 """
44 Default lfs store location, it's consistent with Mercurials large file
45 store which is in .cache/largefiles
46 """
47 from rhodecode.lib.vcs.backends.git import lfs_store
48 user_home = os.path.expanduser("~")
49 return lfs_store(user_home)
38
50
39
51
40 class SimpleGit(simplevcs.SimpleVCS):
52 class SimpleGit(simplevcs.SimpleVCS):
41
53
42 SCM = 'git'
54 SCM = 'git'
43
55
44 def _get_repository_name(self, environ):
56 def _get_repository_name(self, environ):
45 """
57 """
46 Gets repository name out of PATH_INFO header
58 Gets repository name out of PATH_INFO header
47
59
48 :param environ: environ where PATH_INFO is stored
60 :param environ: environ where PATH_INFO is stored
49 """
61 """
50 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
62 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
63 # for GIT LFS, and bare format strip .git suffix from names
64 if repo_name.endswith('.git'):
65 repo_name = repo_name[:-4]
51 return repo_name
66 return repo_name
52
67
68 def _get_lfs_action(self, path, request_method):
69 """
70 return an action based on LFS requests type.
71 Those routes are handled inside vcsserver app.
72
73 batch -> POST to /info/lfs/objects/batch => PUSH/PULL
74 batch is based on the `operation.
75 that could be download or upload, but those are only
76 instructions to fetch so we return pull always
77
78 download -> GET to /info/lfs/{oid} => PULL
79 upload -> PUT to /info/lfs/{oid} => PUSH
80
81 verification -> POST to /info/lfs/verify => PULL
82
83 """
84
85 match_obj = GIT_LFS_PROTO_PAT.match(path)
86 _parts = match_obj.groups()
87 repo_name, path, operation = _parts
88 log.debug(
89 'LFS: detecting operation based on following '
90 'data: %s, req_method:%s', _parts, request_method)
91
92 if operation == 'verify':
93 return 'pull'
94 elif operation == 'objects/batch':
95 # batch sends back instructions for API to dl/upl we report it
96 # as pull
97 if request_method == 'POST':
98 return 'pull'
99
100 elif operation:
101 # probably a OID, upload is PUT, download a GET
102 if request_method == 'GET':
103 return 'pull'
104 else:
105 return 'push'
106
107 # if default not found require push, as action
108 return 'push'
109
53 _ACTION_MAPPING = {
110 _ACTION_MAPPING = {
54 'git-receive-pack': 'push',
111 'git-receive-pack': 'push',
55 'git-upload-pack': 'pull',
112 'git-upload-pack': 'pull',
56 }
113 }
57
114
58 def _get_action(self, environ):
115 def _get_action(self, environ):
59 """
116 """
60 Maps git request commands into a pull or push command.
117 Maps git request commands into a pull or push command.
61 In case of unknown/unexpected data, it returns 'pull' to be safe.
118 In case of unknown/unexpected data, it returns 'pull' to be safe.
62
119
63 :param environ:
120 :param environ:
64 """
121 """
65 path = environ['PATH_INFO']
122 path = environ['PATH_INFO']
66
123
67 if path.endswith('/info/refs'):
124 if path.endswith('/info/refs'):
68 query = urlparse.parse_qs(environ['QUERY_STRING'])
125 query = urlparse.parse_qs(environ['QUERY_STRING'])
69 service_cmd = query.get('service', [''])[0]
126 service_cmd = query.get('service', [''])[0]
70 return self._ACTION_MAPPING.get(service_cmd, 'pull')
127 return self._ACTION_MAPPING.get(service_cmd, 'pull')
128
129 elif GIT_LFS_PROTO_PAT.match(environ['PATH_INFO']):
130 return self._get_lfs_action(
131 environ['PATH_INFO'], environ['REQUEST_METHOD'])
132
71 elif path.endswith('/git-receive-pack'):
133 elif path.endswith('/git-receive-pack'):
72 return 'push'
134 return 'push'
73 elif path.endswith('/git-upload-pack'):
135 elif path.endswith('/git-upload-pack'):
74 return 'pull'
136 return 'pull'
75
137
76 return 'pull'
138 return 'pull'
77
139
78 def _create_wsgi_app(self, repo_path, repo_name, config):
140 def _create_wsgi_app(self, repo_path, repo_name, config):
79 return self.scm_app.create_git_wsgi_app(
141 return self.scm_app.create_git_wsgi_app(
80 repo_path, repo_name, config)
142 repo_path, repo_name, config)
81
143
82 def _create_config(self, extras, repo_name):
144 def _create_config(self, extras, repo_name):
83 extras['git_update_server_info'] = utils2.str2bool(
145 extras['git_update_server_info'] = utils2.str2bool(
84 rhodecode.CONFIG.get('git_update_server_info'))
146 rhodecode.CONFIG.get('git_update_server_info'))
147
148 # TODO(marcink): controll this via DB settings, store and enabled-per
149 # repo settings
150
151 extras['git_lfs_enabled'] = True
152 extras['git_lfs_store_path'] = default_lfs_store()
85 return extras
153 return extras
General Comments 0
You need to be logged in to leave comments. Login now