##// END OF EJS Templates
git-lfs: push settings to git-lfs backend stored inside our rhodecode settings...
marcink -
r1571:de4b3926 default
parent child Browse files
Show More
@@ -1,153 +1,155 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 os
26 import re
26 import re
27 import logging
27 import logging
28 import urlparse
28 import urlparse
29
29
30 import rhodecode
30 import rhodecode
31 from rhodecode.lib import utils
31 from rhodecode.lib import utils2
32 from rhodecode.lib import utils2
32 from rhodecode.lib.middleware import simplevcs
33 from rhodecode.lib.middleware import simplevcs
33
34
34 log = logging.getLogger(__name__)
35 log = logging.getLogger(__name__)
35
36
36
37
37 GIT_PROTO_PAT = re.compile(
38 GIT_PROTO_PAT = re.compile(
38 r'^/(.+)/(info/refs|info/lfs/(.+)|git-upload-pack|git-receive-pack)')
39 r'^/(.+)/(info/refs|info/lfs/(.+)|git-upload-pack|git-receive-pack)')
39 GIT_LFS_PROTO_PAT = re.compile(r'^/(.+)/(info/lfs/(.+))')
40 GIT_LFS_PROTO_PAT = re.compile(r'^/(.+)/(info/lfs/(.+))')
40
41
41
42
42 def default_lfs_store():
43 def default_lfs_store():
43 """
44 """
44 Default lfs store location, it's consistent with Mercurials large file
45 Default lfs store location, it's consistent with Mercurials large file
45 store which is in .cache/largefiles
46 store which is in .cache/largefiles
46 """
47 """
47 from rhodecode.lib.vcs.backends.git import lfs_store
48 from rhodecode.lib.vcs.backends.git import lfs_store
48 user_home = os.path.expanduser("~")
49 user_home = os.path.expanduser("~")
49 return lfs_store(user_home)
50 return lfs_store(user_home)
50
51
51
52
52 class SimpleGit(simplevcs.SimpleVCS):
53 class SimpleGit(simplevcs.SimpleVCS):
53
54
54 SCM = 'git'
55 SCM = 'git'
55
56
56 def _get_repository_name(self, environ):
57 def _get_repository_name(self, environ):
57 """
58 """
58 Gets repository name out of PATH_INFO header
59 Gets repository name out of PATH_INFO header
59
60
60 :param environ: environ where PATH_INFO is stored
61 :param environ: environ where PATH_INFO is stored
61 """
62 """
62 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
63 repo_name = GIT_PROTO_PAT.match(environ['PATH_INFO']).group(1)
63 # for GIT LFS, and bare format strip .git suffix from names
64 # for GIT LFS, and bare format strip .git suffix from names
64 if repo_name.endswith('.git'):
65 if repo_name.endswith('.git'):
65 repo_name = repo_name[:-4]
66 repo_name = repo_name[:-4]
66 return repo_name
67 return repo_name
67
68
68 def _get_lfs_action(self, path, request_method):
69 def _get_lfs_action(self, path, request_method):
69 """
70 """
70 return an action based on LFS requests type.
71 return an action based on LFS requests type.
71 Those routes are handled inside vcsserver app.
72 Those routes are handled inside vcsserver app.
72
73
73 batch -> POST to /info/lfs/objects/batch => PUSH/PULL
74 batch -> POST to /info/lfs/objects/batch => PUSH/PULL
74 batch is based on the `operation.
75 batch is based on the `operation.
75 that could be download or upload, but those are only
76 that could be download or upload, but those are only
76 instructions to fetch so we return pull always
77 instructions to fetch so we return pull always
77
78
78 download -> GET to /info/lfs/{oid} => PULL
79 download -> GET to /info/lfs/{oid} => PULL
79 upload -> PUT to /info/lfs/{oid} => PUSH
80 upload -> PUT to /info/lfs/{oid} => PUSH
80
81
81 verification -> POST to /info/lfs/verify => PULL
82 verification -> POST to /info/lfs/verify => PULL
82
83
83 """
84 """
84
85
85 match_obj = GIT_LFS_PROTO_PAT.match(path)
86 match_obj = GIT_LFS_PROTO_PAT.match(path)
86 _parts = match_obj.groups()
87 _parts = match_obj.groups()
87 repo_name, path, operation = _parts
88 repo_name, path, operation = _parts
88 log.debug(
89 log.debug(
89 'LFS: detecting operation based on following '
90 'LFS: detecting operation based on following '
90 'data: %s, req_method:%s', _parts, request_method)
91 'data: %s, req_method:%s', _parts, request_method)
91
92
92 if operation == 'verify':
93 if operation == 'verify':
93 return 'pull'
94 return 'pull'
94 elif operation == 'objects/batch':
95 elif operation == 'objects/batch':
95 # batch sends back instructions for API to dl/upl we report it
96 # batch sends back instructions for API to dl/upl we report it
96 # as pull
97 # as pull
97 if request_method == 'POST':
98 if request_method == 'POST':
98 return 'pull'
99 return 'pull'
99
100
100 elif operation:
101 elif operation:
101 # probably a OID, upload is PUT, download a GET
102 # probably a OID, upload is PUT, download a GET
102 if request_method == 'GET':
103 if request_method == 'GET':
103 return 'pull'
104 return 'pull'
104 else:
105 else:
105 return 'push'
106 return 'push'
106
107
107 # if default not found require push, as action
108 # if default not found require push, as action
108 return 'push'
109 return 'push'
109
110
110 _ACTION_MAPPING = {
111 _ACTION_MAPPING = {
111 'git-receive-pack': 'push',
112 'git-receive-pack': 'push',
112 'git-upload-pack': 'pull',
113 'git-upload-pack': 'pull',
113 }
114 }
114
115
115 def _get_action(self, environ):
116 def _get_action(self, environ):
116 """
117 """
117 Maps git request commands into a pull or push command.
118 Maps git request commands into a pull or push command.
118 In case of unknown/unexpected data, it returns 'pull' to be safe.
119 In case of unknown/unexpected data, it returns 'pull' to be safe.
119
120
120 :param environ:
121 :param environ:
121 """
122 """
122 path = environ['PATH_INFO']
123 path = environ['PATH_INFO']
123
124
124 if path.endswith('/info/refs'):
125 if path.endswith('/info/refs'):
125 query = urlparse.parse_qs(environ['QUERY_STRING'])
126 query = urlparse.parse_qs(environ['QUERY_STRING'])
126 service_cmd = query.get('service', [''])[0]
127 service_cmd = query.get('service', [''])[0]
127 return self._ACTION_MAPPING.get(service_cmd, 'pull')
128 return self._ACTION_MAPPING.get(service_cmd, 'pull')
128
129
129 elif GIT_LFS_PROTO_PAT.match(environ['PATH_INFO']):
130 elif GIT_LFS_PROTO_PAT.match(environ['PATH_INFO']):
130 return self._get_lfs_action(
131 return self._get_lfs_action(
131 environ['PATH_INFO'], environ['REQUEST_METHOD'])
132 environ['PATH_INFO'], environ['REQUEST_METHOD'])
132
133
133 elif path.endswith('/git-receive-pack'):
134 elif path.endswith('/git-receive-pack'):
134 return 'push'
135 return 'push'
135 elif path.endswith('/git-upload-pack'):
136 elif path.endswith('/git-upload-pack'):
136 return 'pull'
137 return 'pull'
137
138
138 return 'pull'
139 return 'pull'
139
140
140 def _create_wsgi_app(self, repo_path, repo_name, config):
141 def _create_wsgi_app(self, repo_path, repo_name, config):
141 return self.scm_app.create_git_wsgi_app(
142 return self.scm_app.create_git_wsgi_app(
142 repo_path, repo_name, config)
143 repo_path, repo_name, config)
143
144
144 def _create_config(self, extras, repo_name):
145 def _create_config(self, extras, repo_name):
145 extras['git_update_server_info'] = utils2.str2bool(
146 extras['git_update_server_info'] = utils2.str2bool(
146 rhodecode.CONFIG.get('git_update_server_info'))
147 rhodecode.CONFIG.get('git_update_server_info'))
147
148
148 # TODO(marcink): controll this via DB settings, store and enabled-per
149 config = utils.make_db_config(repo=repo_name)
149 # repo settings
150 custom_store = config.get('vcs_git_lfs', 'store_location')
150
151
151 extras['git_lfs_enabled'] = True
152 extras['git_lfs_enabled'] = utils2.str2bool(
152 extras['git_lfs_store_path'] = default_lfs_store()
153 config.get('vcs_git_lfs', 'enabled'))
154 extras['git_lfs_store_path'] = custom_store or default_lfs_store()
153 return extras
155 return extras
General Comments 0
You need to be logged in to leave comments. Login now