Show More
The requested changes are too big and content was truncated. Show full diff
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: new file 100644 | |
The requested commit or file is too big and content was truncated. Show full diff |
@@ -1,1169 +1,1169 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2010-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | """ |
|
22 | 22 | Routes configuration |
|
23 | 23 | |
|
24 | 24 | The more specific and detailed routes should be defined first so they |
|
25 | 25 | may take precedent over the more generic routes. For more information |
|
26 | 26 | refer to the routes manual at http://routes.groovie.org/docs/ |
|
27 | 27 | |
|
28 | 28 | IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py |
|
29 | 29 | and _route_name variable which uses some of stored naming here to do redirects. |
|
30 | 30 | """ |
|
31 | 31 | import os |
|
32 | 32 | import re |
|
33 | 33 | from routes import Mapper |
|
34 | 34 | |
|
35 | 35 | from rhodecode.config import routing_links |
|
36 | 36 | |
|
37 | 37 | # prefix for non repository related links needs to be prefixed with `/` |
|
38 | 38 | ADMIN_PREFIX = '/_admin' |
|
39 | 39 | STATIC_FILE_PREFIX = '/_static' |
|
40 | 40 | |
|
41 | 41 | # Default requirements for URL parts |
|
42 | 42 | URL_NAME_REQUIREMENTS = { |
|
43 | 43 | # group name can have a slash in them, but they must not end with a slash |
|
44 | 44 | 'group_name': r'.*?[^/]', |
|
45 | 45 | 'repo_group_name': r'.*?[^/]', |
|
46 | 46 | # repo names can have a slash in them, but they must not end with a slash |
|
47 | 47 | 'repo_name': r'.*?[^/]', |
|
48 | 48 | # file path eats up everything at the end |
|
49 | 49 | 'f_path': r'.*', |
|
50 | 50 | # reference types |
|
51 | 51 | 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)', |
|
52 | 52 | 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)', |
|
53 | 53 | } |
|
54 | 54 | |
|
55 | 55 | |
|
56 | 56 | def add_route_requirements(route_path, requirements): |
|
57 | 57 | """ |
|
58 | 58 | Adds regex requirements to pyramid routes using a mapping dict |
|
59 | 59 | |
|
60 | 60 | >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'}) |
|
61 | 61 | '/{action}/{id:\d+}' |
|
62 | 62 | |
|
63 | 63 | """ |
|
64 | 64 | for key, regex in requirements.items(): |
|
65 | 65 | route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex)) |
|
66 | 66 | return route_path |
|
67 | 67 | |
|
68 | 68 | |
|
69 | 69 | class JSRoutesMapper(Mapper): |
|
70 | 70 | """ |
|
71 | 71 | Wrapper for routes.Mapper to make pyroutes compatible url definitions |
|
72 | 72 | """ |
|
73 | 73 | _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$') |
|
74 | 74 | _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)') |
|
75 | 75 | def __init__(self, *args, **kw): |
|
76 | 76 | super(JSRoutesMapper, self).__init__(*args, **kw) |
|
77 | 77 | self._jsroutes = [] |
|
78 | 78 | |
|
79 | 79 | def connect(self, *args, **kw): |
|
80 | 80 | """ |
|
81 | 81 | Wrapper for connect to take an extra argument jsroute=True |
|
82 | 82 | |
|
83 | 83 | :param jsroute: boolean, if True will add the route to the pyroutes list |
|
84 | 84 | """ |
|
85 | 85 | if kw.pop('jsroute', False): |
|
86 | 86 | if not self._named_route_regex.match(args[0]): |
|
87 | 87 | raise Exception('only named routes can be added to pyroutes') |
|
88 | 88 | self._jsroutes.append(args[0]) |
|
89 | 89 | |
|
90 | 90 | super(JSRoutesMapper, self).connect(*args, **kw) |
|
91 | 91 | |
|
92 | 92 | def _extract_route_information(self, route): |
|
93 | 93 | """ |
|
94 | 94 | Convert a route into tuple(name, path, args), eg: |
|
95 | 95 | ('user_profile', '/profile/%(username)s', ['username']) |
|
96 | 96 | """ |
|
97 | 97 | routepath = route.routepath |
|
98 | 98 | def replace(matchobj): |
|
99 | 99 | if matchobj.group(1): |
|
100 | 100 | return "%%(%s)s" % matchobj.group(1).split(':')[0] |
|
101 | 101 | else: |
|
102 | 102 | return "%%(%s)s" % matchobj.group(2) |
|
103 | 103 | |
|
104 | 104 | routepath = self._argument_prog.sub(replace, routepath) |
|
105 | 105 | return ( |
|
106 | 106 | route.name, |
|
107 | 107 | routepath, |
|
108 | 108 | [(arg[0].split(':')[0] if arg[0] != '' else arg[1]) |
|
109 | 109 | for arg in self._argument_prog.findall(route.routepath)] |
|
110 | 110 | ) |
|
111 | 111 | |
|
112 | 112 | def jsroutes(self): |
|
113 | 113 | """ |
|
114 | 114 | Return a list of pyroutes.js compatible routes |
|
115 | 115 | """ |
|
116 | 116 | for route_name in self._jsroutes: |
|
117 | 117 | yield self._extract_route_information(self._routenames[route_name]) |
|
118 | 118 | |
|
119 | 119 | |
|
120 | 120 | def make_map(config): |
|
121 | 121 | """Create, configure and return the routes Mapper""" |
|
122 | 122 | rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'], |
|
123 | 123 | always_scan=config['debug']) |
|
124 | 124 | rmap.minimization = False |
|
125 | 125 | rmap.explicit = False |
|
126 | 126 | |
|
127 | 127 | from rhodecode.lib.utils2 import str2bool |
|
128 | 128 | from rhodecode.model import repo, repo_group |
|
129 | 129 | |
|
130 | 130 | def check_repo(environ, match_dict): |
|
131 | 131 | """ |
|
132 | 132 | check for valid repository for proper 404 handling |
|
133 | 133 | |
|
134 | 134 | :param environ: |
|
135 | 135 | :param match_dict: |
|
136 | 136 | """ |
|
137 | 137 | repo_name = match_dict.get('repo_name') |
|
138 | 138 | |
|
139 | 139 | if match_dict.get('f_path'): |
|
140 | 140 | # fix for multiple initial slashes that causes errors |
|
141 | 141 | match_dict['f_path'] = match_dict['f_path'].lstrip('/') |
|
142 | 142 | repo_model = repo.RepoModel() |
|
143 | 143 | by_name_match = repo_model.get_by_repo_name(repo_name) |
|
144 | 144 | # if we match quickly from database, short circuit the operation, |
|
145 | 145 | # and validate repo based on the type. |
|
146 | 146 | if by_name_match: |
|
147 | 147 | return True |
|
148 | 148 | |
|
149 | 149 | by_id_match = repo_model.get_repo_by_id(repo_name) |
|
150 | 150 | if by_id_match: |
|
151 | 151 | repo_name = by_id_match.repo_name |
|
152 | 152 | match_dict['repo_name'] = repo_name |
|
153 | 153 | return True |
|
154 | 154 | |
|
155 | 155 | return False |
|
156 | 156 | |
|
157 | 157 | def check_group(environ, match_dict): |
|
158 | 158 | """ |
|
159 | 159 | check for valid repository group path for proper 404 handling |
|
160 | 160 | |
|
161 | 161 | :param environ: |
|
162 | 162 | :param match_dict: |
|
163 | 163 | """ |
|
164 | 164 | repo_group_name = match_dict.get('group_name') |
|
165 | 165 | repo_group_model = repo_group.RepoGroupModel() |
|
166 | 166 | by_name_match = repo_group_model.get_by_group_name(repo_group_name) |
|
167 | 167 | if by_name_match: |
|
168 | 168 | return True |
|
169 | 169 | |
|
170 | 170 | return False |
|
171 | 171 | |
|
172 | 172 | def check_user_group(environ, match_dict): |
|
173 | 173 | """ |
|
174 | 174 | check for valid user group for proper 404 handling |
|
175 | 175 | |
|
176 | 176 | :param environ: |
|
177 | 177 | :param match_dict: |
|
178 | 178 | """ |
|
179 | 179 | return True |
|
180 | 180 | |
|
181 | 181 | def check_int(environ, match_dict): |
|
182 | 182 | return match_dict.get('id').isdigit() |
|
183 | 183 | |
|
184 | 184 | |
|
185 | 185 | #========================================================================== |
|
186 | 186 | # CUSTOM ROUTES HERE |
|
187 | 187 | #========================================================================== |
|
188 | 188 | |
|
189 | 189 | # MAIN PAGE |
|
190 | 190 | rmap.connect('home', '/', controller='home', action='index', jsroute=True) |
|
191 | 191 | rmap.connect('goto_switcher_data', '/_goto_data', controller='home', |
|
192 | 192 | action='goto_switcher_data') |
|
193 | 193 | rmap.connect('repo_list_data', '/_repos', controller='home', |
|
194 | 194 | action='repo_list_data') |
|
195 | 195 | |
|
196 | 196 | rmap.connect('user_autocomplete_data', '/_users', controller='home', |
|
197 | 197 | action='user_autocomplete_data', jsroute=True) |
|
198 | 198 | rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home', |
|
199 | 199 | action='user_group_autocomplete_data', jsroute=True) |
|
200 | 200 | |
|
201 | 201 | rmap.connect( |
|
202 | 202 | 'user_profile', '/_profiles/{username}', controller='users', |
|
203 | 203 | action='user_profile') |
|
204 | 204 | |
|
205 | 205 | # TODO: johbo: Static links, to be replaced by our redirection mechanism |
|
206 | 206 | rmap.connect('rst_help', |
|
207 | 207 | 'http://docutils.sourceforge.net/docs/user/rst/quickref.html', |
|
208 | 208 | _static=True) |
|
209 | 209 | rmap.connect('markdown_help', |
|
210 | 210 | 'http://daringfireball.net/projects/markdown/syntax', |
|
211 | 211 | _static=True) |
|
212 | 212 | rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True) |
|
213 | 213 | rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True) |
|
214 | 214 | rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True) |
|
215 | 215 | # TODO: anderson - making this a static link since redirect won't play |
|
216 | 216 | # nice with POST requests |
|
217 | 217 | rmap.connect('enterprise_license_convert_from_old', |
|
218 | 218 | 'https://rhodecode.com/u/license-upgrade', |
|
219 | 219 | _static=True) |
|
220 | 220 | |
|
221 | 221 | routing_links.connect_redirection_links(rmap) |
|
222 | 222 | |
|
223 | 223 | rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping') |
|
224 | 224 | rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test') |
|
225 | 225 | |
|
226 | 226 | # ADMIN REPOSITORY ROUTES |
|
227 | 227 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
228 | 228 | controller='admin/repos') as m: |
|
229 | 229 | m.connect('repos', '/repos', |
|
230 | 230 | action='create', conditions={'method': ['POST']}) |
|
231 | 231 | m.connect('repos', '/repos', |
|
232 | 232 | action='index', conditions={'method': ['GET']}) |
|
233 | 233 | m.connect('new_repo', '/create_repository', jsroute=True, |
|
234 | 234 | action='create_repository', conditions={'method': ['GET']}) |
|
235 | 235 | m.connect('/repos/{repo_name}', |
|
236 | 236 | action='update', conditions={'method': ['PUT'], |
|
237 | 237 | 'function': check_repo}, |
|
238 | 238 | requirements=URL_NAME_REQUIREMENTS) |
|
239 | 239 | m.connect('delete_repo', '/repos/{repo_name}', |
|
240 | 240 | action='delete', conditions={'method': ['DELETE']}, |
|
241 | 241 | requirements=URL_NAME_REQUIREMENTS) |
|
242 | 242 | m.connect('repo', '/repos/{repo_name}', |
|
243 | 243 | action='show', conditions={'method': ['GET'], |
|
244 | 244 | 'function': check_repo}, |
|
245 | 245 | requirements=URL_NAME_REQUIREMENTS) |
|
246 | 246 | |
|
247 | 247 | # ADMIN REPOSITORY GROUPS ROUTES |
|
248 | 248 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
249 | 249 | controller='admin/repo_groups') as m: |
|
250 | 250 | m.connect('repo_groups', '/repo_groups', |
|
251 | 251 | action='create', conditions={'method': ['POST']}) |
|
252 | 252 | m.connect('repo_groups', '/repo_groups', |
|
253 | 253 | action='index', conditions={'method': ['GET']}) |
|
254 | 254 | m.connect('new_repo_group', '/repo_groups/new', |
|
255 | 255 | action='new', conditions={'method': ['GET']}) |
|
256 | 256 | m.connect('update_repo_group', '/repo_groups/{group_name}', |
|
257 | 257 | action='update', conditions={'method': ['PUT'], |
|
258 | 258 | 'function': check_group}, |
|
259 | 259 | requirements=URL_NAME_REQUIREMENTS) |
|
260 | 260 | |
|
261 | 261 | # EXTRAS REPO GROUP ROUTES |
|
262 | 262 | m.connect('edit_repo_group', '/repo_groups/{group_name}/edit', |
|
263 | 263 | action='edit', |
|
264 | 264 | conditions={'method': ['GET'], 'function': check_group}, |
|
265 | 265 | requirements=URL_NAME_REQUIREMENTS) |
|
266 | 266 | m.connect('edit_repo_group', '/repo_groups/{group_name}/edit', |
|
267 | 267 | action='edit', |
|
268 | 268 | conditions={'method': ['PUT'], 'function': check_group}, |
|
269 | 269 | requirements=URL_NAME_REQUIREMENTS) |
|
270 | 270 | |
|
271 | 271 | m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced', |
|
272 | 272 | action='edit_repo_group_advanced', |
|
273 | 273 | conditions={'method': ['GET'], 'function': check_group}, |
|
274 | 274 | requirements=URL_NAME_REQUIREMENTS) |
|
275 | 275 | m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced', |
|
276 | 276 | action='edit_repo_group_advanced', |
|
277 | 277 | conditions={'method': ['PUT'], 'function': check_group}, |
|
278 | 278 | requirements=URL_NAME_REQUIREMENTS) |
|
279 | 279 | |
|
280 | 280 | m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions', |
|
281 | 281 | action='edit_repo_group_perms', |
|
282 | 282 | conditions={'method': ['GET'], 'function': check_group}, |
|
283 | 283 | requirements=URL_NAME_REQUIREMENTS) |
|
284 | 284 | m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions', |
|
285 | 285 | action='update_perms', |
|
286 | 286 | conditions={'method': ['PUT'], 'function': check_group}, |
|
287 | 287 | requirements=URL_NAME_REQUIREMENTS) |
|
288 | 288 | |
|
289 | 289 | m.connect('delete_repo_group', '/repo_groups/{group_name}', |
|
290 | 290 | action='delete', conditions={'method': ['DELETE'], |
|
291 | 291 | 'function': check_group}, |
|
292 | 292 | requirements=URL_NAME_REQUIREMENTS) |
|
293 | 293 | |
|
294 | 294 | # ADMIN USER ROUTES |
|
295 | 295 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
296 | 296 | controller='admin/users') as m: |
|
297 | 297 | m.connect('users', '/users', |
|
298 | 298 | action='create', conditions={'method': ['POST']}) |
|
299 | 299 | m.connect('users', '/users', |
|
300 | 300 | action='index', conditions={'method': ['GET']}) |
|
301 | 301 | m.connect('new_user', '/users/new', |
|
302 | 302 | action='new', conditions={'method': ['GET']}) |
|
303 | 303 | m.connect('update_user', '/users/{user_id}', |
|
304 | 304 | action='update', conditions={'method': ['PUT']}) |
|
305 | 305 | m.connect('delete_user', '/users/{user_id}', |
|
306 | 306 | action='delete', conditions={'method': ['DELETE']}) |
|
307 | 307 | m.connect('edit_user', '/users/{user_id}/edit', |
|
308 | 308 | action='edit', conditions={'method': ['GET']}, jsroute=True) |
|
309 | 309 | m.connect('user', '/users/{user_id}', |
|
310 | 310 | action='show', conditions={'method': ['GET']}) |
|
311 | 311 | m.connect('force_password_reset_user', '/users/{user_id}/password_reset', |
|
312 | 312 | action='reset_password', conditions={'method': ['POST']}) |
|
313 | 313 | m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group', |
|
314 | 314 | action='create_personal_repo_group', conditions={'method': ['POST']}) |
|
315 | 315 | |
|
316 | 316 | # EXTRAS USER ROUTES |
|
317 | 317 | m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced', |
|
318 | 318 | action='edit_advanced', conditions={'method': ['GET']}) |
|
319 | 319 | m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced', |
|
320 | 320 | action='update_advanced', conditions={'method': ['PUT']}) |
|
321 | 321 | |
|
322 | 322 | m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', |
|
323 | 323 | action='edit_auth_tokens', conditions={'method': ['GET']}) |
|
324 | 324 | m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', |
|
325 | 325 | action='add_auth_token', conditions={'method': ['PUT']}) |
|
326 | 326 | m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens', |
|
327 | 327 | action='delete_auth_token', conditions={'method': ['DELETE']}) |
|
328 | 328 | |
|
329 | 329 | m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions', |
|
330 | 330 | action='edit_global_perms', conditions={'method': ['GET']}) |
|
331 | 331 | m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions', |
|
332 | 332 | action='update_global_perms', conditions={'method': ['PUT']}) |
|
333 | 333 | |
|
334 | 334 | m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary', |
|
335 | 335 | action='edit_perms_summary', conditions={'method': ['GET']}) |
|
336 | 336 | |
|
337 | 337 | m.connect('edit_user_emails', '/users/{user_id}/edit/emails', |
|
338 | 338 | action='edit_emails', conditions={'method': ['GET']}) |
|
339 | 339 | m.connect('edit_user_emails', '/users/{user_id}/edit/emails', |
|
340 | 340 | action='add_email', conditions={'method': ['PUT']}) |
|
341 | 341 | m.connect('edit_user_emails', '/users/{user_id}/edit/emails', |
|
342 | 342 | action='delete_email', conditions={'method': ['DELETE']}) |
|
343 | 343 | |
|
344 | 344 | m.connect('edit_user_ips', '/users/{user_id}/edit/ips', |
|
345 | 345 | action='edit_ips', conditions={'method': ['GET']}) |
|
346 | 346 | m.connect('edit_user_ips', '/users/{user_id}/edit/ips', |
|
347 | 347 | action='add_ip', conditions={'method': ['PUT']}) |
|
348 | 348 | m.connect('edit_user_ips', '/users/{user_id}/edit/ips', |
|
349 | 349 | action='delete_ip', conditions={'method': ['DELETE']}) |
|
350 | 350 | |
|
351 | 351 | # ADMIN USER GROUPS REST ROUTES |
|
352 | 352 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
353 | 353 | controller='admin/user_groups') as m: |
|
354 | 354 | m.connect('users_groups', '/user_groups', |
|
355 | 355 | action='create', conditions={'method': ['POST']}) |
|
356 | 356 | m.connect('users_groups', '/user_groups', |
|
357 | 357 | action='index', conditions={'method': ['GET']}) |
|
358 | 358 | m.connect('new_users_group', '/user_groups/new', |
|
359 | 359 | action='new', conditions={'method': ['GET']}) |
|
360 | 360 | m.connect('update_users_group', '/user_groups/{user_group_id}', |
|
361 | 361 | action='update', conditions={'method': ['PUT']}) |
|
362 | 362 | m.connect('delete_users_group', '/user_groups/{user_group_id}', |
|
363 | 363 | action='delete', conditions={'method': ['DELETE']}) |
|
364 | 364 | m.connect('edit_users_group', '/user_groups/{user_group_id}/edit', |
|
365 | 365 | action='edit', conditions={'method': ['GET']}, |
|
366 | 366 | function=check_user_group) |
|
367 | 367 | |
|
368 | 368 | # EXTRAS USER GROUP ROUTES |
|
369 | 369 | m.connect('edit_user_group_global_perms', |
|
370 | 370 | '/user_groups/{user_group_id}/edit/global_permissions', |
|
371 | 371 | action='edit_global_perms', conditions={'method': ['GET']}) |
|
372 | 372 | m.connect('edit_user_group_global_perms', |
|
373 | 373 | '/user_groups/{user_group_id}/edit/global_permissions', |
|
374 | 374 | action='update_global_perms', conditions={'method': ['PUT']}) |
|
375 | 375 | m.connect('edit_user_group_perms_summary', |
|
376 | 376 | '/user_groups/{user_group_id}/edit/permissions_summary', |
|
377 | 377 | action='edit_perms_summary', conditions={'method': ['GET']}) |
|
378 | 378 | |
|
379 | 379 | m.connect('edit_user_group_perms', |
|
380 | 380 | '/user_groups/{user_group_id}/edit/permissions', |
|
381 | 381 | action='edit_perms', conditions={'method': ['GET']}) |
|
382 | 382 | m.connect('edit_user_group_perms', |
|
383 | 383 | '/user_groups/{user_group_id}/edit/permissions', |
|
384 | 384 | action='update_perms', conditions={'method': ['PUT']}) |
|
385 | 385 | |
|
386 | 386 | m.connect('edit_user_group_advanced', |
|
387 | 387 | '/user_groups/{user_group_id}/edit/advanced', |
|
388 | 388 | action='edit_advanced', conditions={'method': ['GET']}) |
|
389 | 389 | |
|
390 | 390 | m.connect('edit_user_group_members', |
|
391 | 391 | '/user_groups/{user_group_id}/edit/members', jsroute=True, |
|
392 | 392 | action='user_group_members', conditions={'method': ['GET']}) |
|
393 | 393 | |
|
394 | 394 | # ADMIN PERMISSIONS ROUTES |
|
395 | 395 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
396 | 396 | controller='admin/permissions') as m: |
|
397 | 397 | m.connect('admin_permissions_application', '/permissions/application', |
|
398 | 398 | action='permission_application_update', conditions={'method': ['POST']}) |
|
399 | 399 | m.connect('admin_permissions_application', '/permissions/application', |
|
400 | 400 | action='permission_application', conditions={'method': ['GET']}) |
|
401 | 401 | |
|
402 | 402 | m.connect('admin_permissions_global', '/permissions/global', |
|
403 | 403 | action='permission_global_update', conditions={'method': ['POST']}) |
|
404 | 404 | m.connect('admin_permissions_global', '/permissions/global', |
|
405 | 405 | action='permission_global', conditions={'method': ['GET']}) |
|
406 | 406 | |
|
407 | 407 | m.connect('admin_permissions_object', '/permissions/object', |
|
408 | 408 | action='permission_objects_update', conditions={'method': ['POST']}) |
|
409 | 409 | m.connect('admin_permissions_object', '/permissions/object', |
|
410 | 410 | action='permission_objects', conditions={'method': ['GET']}) |
|
411 | 411 | |
|
412 | 412 | m.connect('admin_permissions_ips', '/permissions/ips', |
|
413 | 413 | action='permission_ips', conditions={'method': ['POST']}) |
|
414 | 414 | m.connect('admin_permissions_ips', '/permissions/ips', |
|
415 | 415 | action='permission_ips', conditions={'method': ['GET']}) |
|
416 | 416 | |
|
417 | 417 | m.connect('admin_permissions_overview', '/permissions/overview', |
|
418 | 418 | action='permission_perms', conditions={'method': ['GET']}) |
|
419 | 419 | |
|
420 | 420 | # ADMIN DEFAULTS REST ROUTES |
|
421 | 421 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
422 | 422 | controller='admin/defaults') as m: |
|
423 | 423 | m.connect('admin_defaults_repositories', '/defaults/repositories', |
|
424 | 424 | action='update_repository_defaults', conditions={'method': ['POST']}) |
|
425 | 425 | m.connect('admin_defaults_repositories', '/defaults/repositories', |
|
426 | 426 | action='index', conditions={'method': ['GET']}) |
|
427 | 427 | |
|
428 | 428 | # ADMIN DEBUG STYLE ROUTES |
|
429 | 429 | if str2bool(config.get('debug_style')): |
|
430 | 430 | with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style', |
|
431 | 431 | controller='debug_style') as m: |
|
432 | 432 | m.connect('debug_style_home', '', |
|
433 | 433 | action='index', conditions={'method': ['GET']}) |
|
434 | 434 | m.connect('debug_style_template', '/t/{t_path}', |
|
435 | 435 | action='template', conditions={'method': ['GET']}) |
|
436 | 436 | |
|
437 | 437 | # ADMIN SETTINGS ROUTES |
|
438 | 438 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
439 | 439 | controller='admin/settings') as m: |
|
440 | 440 | |
|
441 | 441 | # default |
|
442 | 442 | m.connect('admin_settings', '/settings', |
|
443 | 443 | action='settings_global_update', |
|
444 | 444 | conditions={'method': ['POST']}) |
|
445 | 445 | m.connect('admin_settings', '/settings', |
|
446 | 446 | action='settings_global', conditions={'method': ['GET']}) |
|
447 | 447 | |
|
448 | 448 | m.connect('admin_settings_vcs', '/settings/vcs', |
|
449 | 449 | action='settings_vcs_update', |
|
450 | 450 | conditions={'method': ['POST']}) |
|
451 | 451 | m.connect('admin_settings_vcs', '/settings/vcs', |
|
452 | 452 | action='settings_vcs', |
|
453 | 453 | conditions={'method': ['GET']}) |
|
454 | 454 | m.connect('admin_settings_vcs', '/settings/vcs', |
|
455 | 455 | action='delete_svn_pattern', |
|
456 | 456 | conditions={'method': ['DELETE']}) |
|
457 | 457 | |
|
458 | 458 | m.connect('admin_settings_mapping', '/settings/mapping', |
|
459 | 459 | action='settings_mapping_update', |
|
460 | 460 | conditions={'method': ['POST']}) |
|
461 | 461 | m.connect('admin_settings_mapping', '/settings/mapping', |
|
462 | 462 | action='settings_mapping', conditions={'method': ['GET']}) |
|
463 | 463 | |
|
464 | 464 | m.connect('admin_settings_global', '/settings/global', |
|
465 | 465 | action='settings_global_update', |
|
466 | 466 | conditions={'method': ['POST']}) |
|
467 | 467 | m.connect('admin_settings_global', '/settings/global', |
|
468 | 468 | action='settings_global', conditions={'method': ['GET']}) |
|
469 | 469 | |
|
470 | 470 | m.connect('admin_settings_visual', '/settings/visual', |
|
471 | 471 | action='settings_visual_update', |
|
472 | 472 | conditions={'method': ['POST']}) |
|
473 | 473 | m.connect('admin_settings_visual', '/settings/visual', |
|
474 | 474 | action='settings_visual', conditions={'method': ['GET']}) |
|
475 | 475 | |
|
476 | 476 | m.connect('admin_settings_issuetracker', |
|
477 | 477 | '/settings/issue-tracker', action='settings_issuetracker', |
|
478 | 478 | conditions={'method': ['GET']}) |
|
479 | 479 | m.connect('admin_settings_issuetracker_save', |
|
480 | 480 | '/settings/issue-tracker/save', |
|
481 | 481 | action='settings_issuetracker_save', |
|
482 | 482 | conditions={'method': ['POST']}) |
|
483 | 483 | m.connect('admin_issuetracker_test', '/settings/issue-tracker/test', |
|
484 | 484 | action='settings_issuetracker_test', |
|
485 | 485 | conditions={'method': ['POST']}) |
|
486 | 486 | m.connect('admin_issuetracker_delete', |
|
487 | 487 | '/settings/issue-tracker/delete', |
|
488 | 488 | action='settings_issuetracker_delete', |
|
489 | 489 | conditions={'method': ['DELETE']}) |
|
490 | 490 | |
|
491 | 491 | m.connect('admin_settings_email', '/settings/email', |
|
492 | 492 | action='settings_email_update', |
|
493 | 493 | conditions={'method': ['POST']}) |
|
494 | 494 | m.connect('admin_settings_email', '/settings/email', |
|
495 | 495 | action='settings_email', conditions={'method': ['GET']}) |
|
496 | 496 | |
|
497 | 497 | m.connect('admin_settings_hooks', '/settings/hooks', |
|
498 | 498 | action='settings_hooks_update', |
|
499 | 499 | conditions={'method': ['POST', 'DELETE']}) |
|
500 | 500 | m.connect('admin_settings_hooks', '/settings/hooks', |
|
501 | 501 | action='settings_hooks', conditions={'method': ['GET']}) |
|
502 | 502 | |
|
503 | 503 | m.connect('admin_settings_search', '/settings/search', |
|
504 | 504 | action='settings_search', conditions={'method': ['GET']}) |
|
505 | 505 | |
|
506 | 506 | m.connect('admin_settings_system', '/settings/system', |
|
507 | 507 | action='settings_system', conditions={'method': ['GET']}) |
|
508 | 508 | |
|
509 | 509 | m.connect('admin_settings_system_update', '/settings/system/updates', |
|
510 | 510 | action='settings_system_update', conditions={'method': ['GET']}) |
|
511 | 511 | |
|
512 | 512 | m.connect('admin_settings_supervisor', '/settings/supervisor', |
|
513 | 513 | action='settings_supervisor', conditions={'method': ['GET']}) |
|
514 | 514 | m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log', |
|
515 | 515 | action='settings_supervisor_log', conditions={'method': ['GET']}) |
|
516 | 516 | |
|
517 | 517 | m.connect('admin_settings_labs', '/settings/labs', |
|
518 | 518 | action='settings_labs_update', |
|
519 | 519 | conditions={'method': ['POST']}) |
|
520 | 520 | m.connect('admin_settings_labs', '/settings/labs', |
|
521 | 521 | action='settings_labs', conditions={'method': ['GET']}) |
|
522 | 522 | |
|
523 | 523 | # ADMIN MY ACCOUNT |
|
524 | 524 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
525 | 525 | controller='admin/my_account') as m: |
|
526 | 526 | |
|
527 | 527 | m.connect('my_account', '/my_account', |
|
528 | 528 | action='my_account', conditions={'method': ['GET']}) |
|
529 | 529 | m.connect('my_account_edit', '/my_account/edit', |
|
530 | 530 | action='my_account_edit', conditions={'method': ['GET']}) |
|
531 | 531 | m.connect('my_account', '/my_account', |
|
532 | 532 | action='my_account_update', conditions={'method': ['POST']}) |
|
533 | 533 | |
|
534 | 534 | m.connect('my_account_password', '/my_account/password', |
|
535 | 535 | action='my_account_password', conditions={'method': ['GET', 'POST']}) |
|
536 | 536 | |
|
537 | 537 | m.connect('my_account_repos', '/my_account/repos', |
|
538 | 538 | action='my_account_repos', conditions={'method': ['GET']}) |
|
539 | 539 | |
|
540 | 540 | m.connect('my_account_watched', '/my_account/watched', |
|
541 | 541 | action='my_account_watched', conditions={'method': ['GET']}) |
|
542 | 542 | |
|
543 | 543 | m.connect('my_account_pullrequests', '/my_account/pull_requests', |
|
544 | 544 | action='my_account_pullrequests', conditions={'method': ['GET']}) |
|
545 | 545 | |
|
546 | 546 | m.connect('my_account_perms', '/my_account/perms', |
|
547 | 547 | action='my_account_perms', conditions={'method': ['GET']}) |
|
548 | 548 | |
|
549 | 549 | m.connect('my_account_emails', '/my_account/emails', |
|
550 | 550 | action='my_account_emails', conditions={'method': ['GET']}) |
|
551 | 551 | m.connect('my_account_emails', '/my_account/emails', |
|
552 | 552 | action='my_account_emails_add', conditions={'method': ['POST']}) |
|
553 | 553 | m.connect('my_account_emails', '/my_account/emails', |
|
554 | 554 | action='my_account_emails_delete', conditions={'method': ['DELETE']}) |
|
555 | 555 | |
|
556 | 556 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', |
|
557 | 557 | action='my_account_auth_tokens', conditions={'method': ['GET']}) |
|
558 | 558 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', |
|
559 | 559 | action='my_account_auth_tokens_add', conditions={'method': ['POST']}) |
|
560 | 560 | m.connect('my_account_auth_tokens', '/my_account/auth_tokens', |
|
561 | 561 | action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']}) |
|
562 | 562 | m.connect('my_account_notifications', '/my_account/notifications', |
|
563 | 563 | action='my_notifications', |
|
564 | 564 | conditions={'method': ['GET']}) |
|
565 | 565 | m.connect('my_account_notifications_toggle_visibility', |
|
566 | 566 | '/my_account/toggle_visibility', |
|
567 | 567 | action='my_notifications_toggle_visibility', |
|
568 | 568 | conditions={'method': ['POST']}) |
|
569 | 569 | |
|
570 | 570 | # NOTIFICATION REST ROUTES |
|
571 | 571 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
572 | 572 | controller='admin/notifications') as m: |
|
573 | 573 | m.connect('notifications', '/notifications', |
|
574 | 574 | action='index', conditions={'method': ['GET']}) |
|
575 | 575 | m.connect('notifications_mark_all_read', '/notifications/mark_all_read', |
|
576 | 576 | action='mark_all_read', conditions={'method': ['POST']}) |
|
577 | 577 | m.connect('/notifications/{notification_id}', |
|
578 | 578 | action='update', conditions={'method': ['PUT']}) |
|
579 | 579 | m.connect('/notifications/{notification_id}', |
|
580 | 580 | action='delete', conditions={'method': ['DELETE']}) |
|
581 | 581 | m.connect('notification', '/notifications/{notification_id}', |
|
582 | 582 | action='show', conditions={'method': ['GET']}) |
|
583 | 583 | |
|
584 | 584 | # ADMIN GIST |
|
585 | 585 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
586 | 586 | controller='admin/gists') as m: |
|
587 | 587 | m.connect('gists', '/gists', |
|
588 | 588 | action='create', conditions={'method': ['POST']}) |
|
589 | 589 | m.connect('gists', '/gists', jsroute=True, |
|
590 | 590 | action='index', conditions={'method': ['GET']}) |
|
591 | 591 | m.connect('new_gist', '/gists/new', jsroute=True, |
|
592 | 592 | action='new', conditions={'method': ['GET']}) |
|
593 | 593 | |
|
594 | 594 | m.connect('/gists/{gist_id}', |
|
595 | 595 | action='delete', conditions={'method': ['DELETE']}) |
|
596 | 596 | m.connect('edit_gist', '/gists/{gist_id}/edit', |
|
597 | 597 | action='edit_form', conditions={'method': ['GET']}) |
|
598 | 598 | m.connect('edit_gist', '/gists/{gist_id}/edit', |
|
599 | 599 | action='edit', conditions={'method': ['POST']}) |
|
600 | 600 | m.connect( |
|
601 | 601 | 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision', |
|
602 | 602 | action='check_revision', conditions={'method': ['GET']}) |
|
603 | 603 | |
|
604 | 604 | m.connect('gist', '/gists/{gist_id}', |
|
605 | 605 | action='show', conditions={'method': ['GET']}) |
|
606 | 606 | m.connect('gist_rev', '/gists/{gist_id}/{revision}', |
|
607 | 607 | revision='tip', |
|
608 | 608 | action='show', conditions={'method': ['GET']}) |
|
609 | 609 | m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}', |
|
610 | 610 | revision='tip', |
|
611 | 611 | action='show', conditions={'method': ['GET']}) |
|
612 | 612 | m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}', |
|
613 | 613 | revision='tip', |
|
614 | 614 | action='show', conditions={'method': ['GET']}, |
|
615 | 615 | requirements=URL_NAME_REQUIREMENTS) |
|
616 | 616 | |
|
617 | 617 | # ADMIN MAIN PAGES |
|
618 | 618 | with rmap.submapper(path_prefix=ADMIN_PREFIX, |
|
619 | 619 | controller='admin/admin') as m: |
|
620 | 620 | m.connect('admin_home', '', action='index') |
|
621 | 621 | m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}', |
|
622 | 622 | action='add_repo') |
|
623 | 623 | m.connect( |
|
624 | 624 | 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}', |
|
625 | 625 | action='pull_requests') |
|
626 | 626 | m.connect( |
|
627 | 627 | 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}', |
|
628 | 628 | action='pull_requests') |
|
629 | 629 | m.connect( |
|
630 | 630 | 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}', |
|
631 | 631 | action='pull_requests') |
|
632 | 632 | |
|
633 | 633 | # USER JOURNAL |
|
634 | 634 | rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,), |
|
635 | 635 | controller='journal', action='index') |
|
636 | 636 | rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,), |
|
637 | 637 | controller='journal', action='journal_rss') |
|
638 | 638 | rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,), |
|
639 | 639 | controller='journal', action='journal_atom') |
|
640 | 640 | |
|
641 | 641 | rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,), |
|
642 | 642 | controller='journal', action='public_journal') |
|
643 | 643 | |
|
644 | 644 | rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,), |
|
645 | 645 | controller='journal', action='public_journal_rss') |
|
646 | 646 | |
|
647 | 647 | rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,), |
|
648 | 648 | controller='journal', action='public_journal_rss') |
|
649 | 649 | |
|
650 | 650 | rmap.connect('public_journal_atom', |
|
651 | 651 | '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal', |
|
652 | 652 | action='public_journal_atom') |
|
653 | 653 | |
|
654 | 654 | rmap.connect('public_journal_atom_old', |
|
655 | 655 | '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal', |
|
656 | 656 | action='public_journal_atom') |
|
657 | 657 | |
|
658 | 658 | rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,), |
|
659 | 659 | controller='journal', action='toggle_following', jsroute=True, |
|
660 | 660 | conditions={'method': ['POST']}) |
|
661 | 661 | |
|
662 | 662 | # FULL TEXT SEARCH |
|
663 | 663 | rmap.connect('search', '%s/search' % (ADMIN_PREFIX,), |
|
664 | 664 | controller='search') |
|
665 | 665 | rmap.connect('search_repo_home', '/{repo_name}/search', |
|
666 | 666 | controller='search', |
|
667 | 667 | action='index', |
|
668 | 668 | conditions={'function': check_repo}, |
|
669 | 669 | requirements=URL_NAME_REQUIREMENTS) |
|
670 | 670 | |
|
671 | 671 | # FEEDS |
|
672 | 672 | rmap.connect('rss_feed_home', '/{repo_name}/feed/rss', |
|
673 | 673 | controller='feed', action='rss', |
|
674 | 674 | conditions={'function': check_repo}, |
|
675 | 675 | requirements=URL_NAME_REQUIREMENTS) |
|
676 | 676 | |
|
677 | 677 | rmap.connect('atom_feed_home', '/{repo_name}/feed/atom', |
|
678 | 678 | controller='feed', action='atom', |
|
679 | 679 | conditions={'function': check_repo}, |
|
680 | 680 | requirements=URL_NAME_REQUIREMENTS) |
|
681 | 681 | |
|
682 | 682 | #========================================================================== |
|
683 | 683 | # REPOSITORY ROUTES |
|
684 | 684 | #========================================================================== |
|
685 | 685 | |
|
686 | 686 | rmap.connect('repo_creating_home', '/{repo_name}/repo_creating', |
|
687 | 687 | controller='admin/repos', action='repo_creating', |
|
688 | 688 | requirements=URL_NAME_REQUIREMENTS) |
|
689 | 689 | rmap.connect('repo_check_home', '/{repo_name}/crepo_check', |
|
690 | 690 | controller='admin/repos', action='repo_check', |
|
691 | 691 | requirements=URL_NAME_REQUIREMENTS) |
|
692 | 692 | |
|
693 | 693 | rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}', |
|
694 | 694 | controller='summary', action='repo_stats', |
|
695 | 695 | conditions={'function': check_repo}, |
|
696 | 696 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
697 | 697 | |
|
698 | 698 | rmap.connect('repo_refs_data', '/{repo_name}/refs-data', |
|
699 | 699 | controller='summary', action='repo_refs_data', jsroute=True, |
|
700 | 700 | requirements=URL_NAME_REQUIREMENTS) |
|
701 | 701 | rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog', |
|
702 | 702 | controller='summary', action='repo_refs_changelog_data', |
|
703 | 703 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
704 | 704 | rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers', |
|
705 | 705 | controller='summary', action='repo_default_reviewers_data', |
|
706 | 706 | jsroute=True, requirements=URL_NAME_REQUIREMENTS) |
|
707 | 707 | |
|
708 | 708 | rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}', |
|
709 | 709 | controller='changeset', revision='tip', jsroute=True, |
|
710 | 710 | conditions={'function': check_repo}, |
|
711 | 711 | requirements=URL_NAME_REQUIREMENTS) |
|
712 | 712 | rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}', |
|
713 | 713 | controller='changeset', revision='tip', action='changeset_children', |
|
714 | 714 | conditions={'function': check_repo}, |
|
715 | 715 | requirements=URL_NAME_REQUIREMENTS) |
|
716 | 716 | rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}', |
|
717 | 717 | controller='changeset', revision='tip', action='changeset_parents', |
|
718 | 718 | conditions={'function': check_repo}, |
|
719 | 719 | requirements=URL_NAME_REQUIREMENTS) |
|
720 | 720 | |
|
721 | 721 | # repo edit options |
|
722 | 722 | rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True, |
|
723 | 723 | controller='admin/repos', action='edit', |
|
724 | 724 | conditions={'method': ['GET'], 'function': check_repo}, |
|
725 | 725 | requirements=URL_NAME_REQUIREMENTS) |
|
726 | 726 | |
|
727 | 727 | rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions', |
|
728 | 728 | jsroute=True, |
|
729 | 729 | controller='admin/repos', action='edit_permissions', |
|
730 | 730 | conditions={'method': ['GET'], 'function': check_repo}, |
|
731 | 731 | requirements=URL_NAME_REQUIREMENTS) |
|
732 | 732 | rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions', |
|
733 | 733 | controller='admin/repos', action='edit_permissions_update', |
|
734 | 734 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
735 | 735 | requirements=URL_NAME_REQUIREMENTS) |
|
736 | 736 | |
|
737 | 737 | rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields', |
|
738 | 738 | controller='admin/repos', action='edit_fields', |
|
739 | 739 | conditions={'method': ['GET'], 'function': check_repo}, |
|
740 | 740 | requirements=URL_NAME_REQUIREMENTS) |
|
741 | 741 | rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new', |
|
742 | 742 | controller='admin/repos', action='create_repo_field', |
|
743 | 743 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
744 | 744 | requirements=URL_NAME_REQUIREMENTS) |
|
745 | 745 | rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}', |
|
746 | 746 | controller='admin/repos', action='delete_repo_field', |
|
747 | 747 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
748 | 748 | requirements=URL_NAME_REQUIREMENTS) |
|
749 | 749 | |
|
750 | 750 | rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced', |
|
751 | 751 | controller='admin/repos', action='edit_advanced', |
|
752 | 752 | conditions={'method': ['GET'], 'function': check_repo}, |
|
753 | 753 | requirements=URL_NAME_REQUIREMENTS) |
|
754 | 754 | |
|
755 | 755 | rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking', |
|
756 | 756 | controller='admin/repos', action='edit_advanced_locking', |
|
757 | 757 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
758 | 758 | requirements=URL_NAME_REQUIREMENTS) |
|
759 | 759 | rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle', |
|
760 | 760 | controller='admin/repos', action='toggle_locking', |
|
761 | 761 | conditions={'method': ['GET'], 'function': check_repo}, |
|
762 | 762 | requirements=URL_NAME_REQUIREMENTS) |
|
763 | 763 | |
|
764 | 764 | rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal', |
|
765 | 765 | controller='admin/repos', action='edit_advanced_journal', |
|
766 | 766 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
767 | 767 | requirements=URL_NAME_REQUIREMENTS) |
|
768 | 768 | |
|
769 | 769 | rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork', |
|
770 | 770 | controller='admin/repos', action='edit_advanced_fork', |
|
771 | 771 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
772 | 772 | requirements=URL_NAME_REQUIREMENTS) |
|
773 | 773 | |
|
774 | 774 | rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', |
|
775 | 775 | controller='admin/repos', action='edit_caches_form', |
|
776 | 776 | conditions={'method': ['GET'], 'function': check_repo}, |
|
777 | 777 | requirements=URL_NAME_REQUIREMENTS) |
|
778 | 778 | rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches', |
|
779 | 779 | controller='admin/repos', action='edit_caches', |
|
780 | 780 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
781 | 781 | requirements=URL_NAME_REQUIREMENTS) |
|
782 | 782 | |
|
783 | 783 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', |
|
784 | 784 | controller='admin/repos', action='edit_remote_form', |
|
785 | 785 | conditions={'method': ['GET'], 'function': check_repo}, |
|
786 | 786 | requirements=URL_NAME_REQUIREMENTS) |
|
787 | 787 | rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote', |
|
788 | 788 | controller='admin/repos', action='edit_remote', |
|
789 | 789 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
790 | 790 | requirements=URL_NAME_REQUIREMENTS) |
|
791 | 791 | |
|
792 | 792 | rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', |
|
793 | 793 | controller='admin/repos', action='edit_statistics_form', |
|
794 | 794 | conditions={'method': ['GET'], 'function': check_repo}, |
|
795 | 795 | requirements=URL_NAME_REQUIREMENTS) |
|
796 | 796 | rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics', |
|
797 | 797 | controller='admin/repos', action='edit_statistics', |
|
798 | 798 | conditions={'method': ['PUT'], 'function': check_repo}, |
|
799 | 799 | requirements=URL_NAME_REQUIREMENTS) |
|
800 | 800 | rmap.connect('repo_settings_issuetracker', |
|
801 | 801 | '/{repo_name}/settings/issue-tracker', |
|
802 | 802 | controller='admin/repos', action='repo_issuetracker', |
|
803 | 803 | conditions={'method': ['GET'], 'function': check_repo}, |
|
804 | 804 | requirements=URL_NAME_REQUIREMENTS) |
|
805 | 805 | rmap.connect('repo_issuetracker_test', |
|
806 | 806 | '/{repo_name}/settings/issue-tracker/test', |
|
807 | 807 | controller='admin/repos', action='repo_issuetracker_test', |
|
808 | 808 | conditions={'method': ['POST'], 'function': check_repo}, |
|
809 | 809 | requirements=URL_NAME_REQUIREMENTS) |
|
810 | 810 | rmap.connect('repo_issuetracker_delete', |
|
811 | 811 | '/{repo_name}/settings/issue-tracker/delete', |
|
812 | 812 | controller='admin/repos', action='repo_issuetracker_delete', |
|
813 | 813 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
814 | 814 | requirements=URL_NAME_REQUIREMENTS) |
|
815 | 815 | rmap.connect('repo_issuetracker_save', |
|
816 | 816 | '/{repo_name}/settings/issue-tracker/save', |
|
817 | 817 | controller='admin/repos', action='repo_issuetracker_save', |
|
818 | 818 | conditions={'method': ['POST'], 'function': check_repo}, |
|
819 | 819 | requirements=URL_NAME_REQUIREMENTS) |
|
820 | 820 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
821 | 821 | controller='admin/repos', action='repo_settings_vcs_update', |
|
822 | 822 | conditions={'method': ['POST'], 'function': check_repo}, |
|
823 | 823 | requirements=URL_NAME_REQUIREMENTS) |
|
824 | 824 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
825 | 825 | controller='admin/repos', action='repo_settings_vcs', |
|
826 | 826 | conditions={'method': ['GET'], 'function': check_repo}, |
|
827 | 827 | requirements=URL_NAME_REQUIREMENTS) |
|
828 | 828 | rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs', |
|
829 | 829 | controller='admin/repos', action='repo_delete_svn_pattern', |
|
830 | 830 | conditions={'method': ['DELETE'], 'function': check_repo}, |
|
831 | 831 | requirements=URL_NAME_REQUIREMENTS) |
|
832 | 832 | rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest', |
|
833 | 833 | controller='admin/repos', action='repo_settings_pullrequest', |
|
834 | 834 | conditions={'method': ['GET', 'POST'], 'function': check_repo}, |
|
835 | 835 | requirements=URL_NAME_REQUIREMENTS) |
|
836 | 836 | |
|
837 | 837 | # still working url for backward compat. |
|
838 | 838 | rmap.connect('raw_changeset_home_depraced', |
|
839 | 839 | '/{repo_name}/raw-changeset/{revision}', |
|
840 | 840 | controller='changeset', action='changeset_raw', |
|
841 | 841 | revision='tip', conditions={'function': check_repo}, |
|
842 | 842 | requirements=URL_NAME_REQUIREMENTS) |
|
843 | 843 | |
|
844 | 844 | # new URLs |
|
845 | 845 | rmap.connect('changeset_raw_home', |
|
846 | 846 | '/{repo_name}/changeset-diff/{revision}', |
|
847 | 847 | controller='changeset', action='changeset_raw', |
|
848 | 848 | revision='tip', conditions={'function': check_repo}, |
|
849 | 849 | requirements=URL_NAME_REQUIREMENTS) |
|
850 | 850 | |
|
851 | 851 | rmap.connect('changeset_patch_home', |
|
852 | 852 | '/{repo_name}/changeset-patch/{revision}', |
|
853 | 853 | controller='changeset', action='changeset_patch', |
|
854 | 854 | revision='tip', conditions={'function': check_repo}, |
|
855 | 855 | requirements=URL_NAME_REQUIREMENTS) |
|
856 | 856 | |
|
857 | 857 | rmap.connect('changeset_download_home', |
|
858 | 858 | '/{repo_name}/changeset-download/{revision}', |
|
859 | 859 | controller='changeset', action='changeset_download', |
|
860 | 860 | revision='tip', conditions={'function': check_repo}, |
|
861 | 861 | requirements=URL_NAME_REQUIREMENTS) |
|
862 | 862 | |
|
863 | 863 | rmap.connect('changeset_comment', |
|
864 | 864 | '/{repo_name}/changeset/{revision}/comment', jsroute=True, |
|
865 | 865 | controller='changeset', revision='tip', action='comment', |
|
866 | 866 | conditions={'function': check_repo}, |
|
867 | 867 | requirements=URL_NAME_REQUIREMENTS) |
|
868 | 868 | |
|
869 | 869 | rmap.connect('changeset_comment_preview', |
|
870 | 870 | '/{repo_name}/changeset/comment/preview', jsroute=True, |
|
871 | 871 | controller='changeset', action='preview_comment', |
|
872 | 872 | conditions={'function': check_repo, 'method': ['POST']}, |
|
873 | 873 | requirements=URL_NAME_REQUIREMENTS) |
|
874 | 874 | |
|
875 | 875 | rmap.connect('changeset_comment_delete', |
|
876 | 876 | '/{repo_name}/changeset/comment/{comment_id}/delete', |
|
877 | 877 | controller='changeset', action='delete_comment', |
|
878 | 878 | conditions={'function': check_repo, 'method': ['DELETE']}, |
|
879 | 879 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
880 | 880 | |
|
881 | 881 | rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}', |
|
882 | 882 | controller='changeset', action='changeset_info', |
|
883 | 883 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
884 | 884 | |
|
885 | 885 | rmap.connect('compare_home', |
|
886 | 886 | '/{repo_name}/compare', |
|
887 | 887 | controller='compare', action='index', |
|
888 | 888 | conditions={'function': check_repo}, |
|
889 | 889 | requirements=URL_NAME_REQUIREMENTS) |
|
890 | 890 | |
|
891 | 891 | rmap.connect('compare_url', |
|
892 | 892 | '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}', |
|
893 | 893 | controller='compare', action='compare', |
|
894 | 894 | conditions={'function': check_repo}, |
|
895 | 895 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
896 | 896 | |
|
897 | 897 | rmap.connect('pullrequest_home', |
|
898 | 898 | '/{repo_name}/pull-request/new', controller='pullrequests', |
|
899 | 899 | action='index', conditions={'function': check_repo, |
|
900 | 900 | 'method': ['GET']}, |
|
901 | 901 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
902 | 902 | |
|
903 | 903 | rmap.connect('pullrequest', |
|
904 | 904 | '/{repo_name}/pull-request/new', controller='pullrequests', |
|
905 | 905 | action='create', conditions={'function': check_repo, |
|
906 | 906 | 'method': ['POST']}, |
|
907 | 907 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
908 | 908 | |
|
909 | 909 | rmap.connect('pullrequest_repo_refs', |
|
910 | 910 | '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}', |
|
911 | 911 | controller='pullrequests', |
|
912 | 912 | action='get_repo_refs', |
|
913 | 913 | conditions={'function': check_repo, 'method': ['GET']}, |
|
914 | 914 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
915 | 915 | |
|
916 | 916 | rmap.connect('pullrequest_repo_destinations', |
|
917 | 917 | '/{repo_name}/pull-request/repo-destinations', |
|
918 | 918 | controller='pullrequests', |
|
919 | 919 | action='get_repo_destinations', |
|
920 | 920 | conditions={'function': check_repo, 'method': ['GET']}, |
|
921 | 921 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
922 | 922 | |
|
923 | 923 | rmap.connect('pullrequest_show', |
|
924 | 924 | '/{repo_name}/pull-request/{pull_request_id}', |
|
925 | 925 | controller='pullrequests', |
|
926 | 926 | action='show', conditions={'function': check_repo, |
|
927 | 927 | 'method': ['GET']}, |
|
928 | 928 | requirements=URL_NAME_REQUIREMENTS) |
|
929 | 929 | |
|
930 | 930 | rmap.connect('pullrequest_update', |
|
931 | 931 | '/{repo_name}/pull-request/{pull_request_id}', |
|
932 | 932 | controller='pullrequests', |
|
933 | 933 | action='update', conditions={'function': check_repo, |
|
934 | 934 | 'method': ['PUT']}, |
|
935 | 935 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
936 | 936 | |
|
937 | 937 | rmap.connect('pullrequest_merge', |
|
938 | 938 | '/{repo_name}/pull-request/{pull_request_id}', |
|
939 | 939 | controller='pullrequests', |
|
940 | 940 | action='merge', conditions={'function': check_repo, |
|
941 | 941 | 'method': ['POST']}, |
|
942 | 942 | requirements=URL_NAME_REQUIREMENTS) |
|
943 | 943 | |
|
944 | 944 | rmap.connect('pullrequest_delete', |
|
945 | 945 | '/{repo_name}/pull-request/{pull_request_id}', |
|
946 | 946 | controller='pullrequests', |
|
947 | 947 | action='delete', conditions={'function': check_repo, |
|
948 | 948 | 'method': ['DELETE']}, |
|
949 | 949 | requirements=URL_NAME_REQUIREMENTS) |
|
950 | 950 | |
|
951 | 951 | rmap.connect('pullrequest_show_all', |
|
952 | 952 | '/{repo_name}/pull-request', |
|
953 | 953 | controller='pullrequests', |
|
954 | 954 | action='show_all', conditions={'function': check_repo, |
|
955 | 955 | 'method': ['GET']}, |
|
956 | 956 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
957 | 957 | |
|
958 | 958 | rmap.connect('pullrequest_comment', |
|
959 | 959 | '/{repo_name}/pull-request-comment/{pull_request_id}', |
|
960 | 960 | controller='pullrequests', |
|
961 | 961 | action='comment', conditions={'function': check_repo, |
|
962 | 962 | 'method': ['POST']}, |
|
963 | 963 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
964 | 964 | |
|
965 | 965 | rmap.connect('pullrequest_comment_delete', |
|
966 | 966 | '/{repo_name}/pull-request-comment/{comment_id}/delete', |
|
967 | 967 | controller='pullrequests', action='delete_comment', |
|
968 | 968 | conditions={'function': check_repo, 'method': ['DELETE']}, |
|
969 | 969 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
970 | 970 | |
|
971 | 971 | rmap.connect('summary_home_explicit', '/{repo_name}/summary', |
|
972 | 972 | controller='summary', conditions={'function': check_repo}, |
|
973 | 973 | requirements=URL_NAME_REQUIREMENTS) |
|
974 | 974 | |
|
975 | 975 | rmap.connect('branches_home', '/{repo_name}/branches', |
|
976 | 976 | controller='branches', conditions={'function': check_repo}, |
|
977 | 977 | requirements=URL_NAME_REQUIREMENTS) |
|
978 | 978 | |
|
979 | 979 | rmap.connect('tags_home', '/{repo_name}/tags', |
|
980 | 980 | controller='tags', conditions={'function': check_repo}, |
|
981 | 981 | requirements=URL_NAME_REQUIREMENTS) |
|
982 | 982 | |
|
983 | 983 | rmap.connect('bookmarks_home', '/{repo_name}/bookmarks', |
|
984 | 984 | controller='bookmarks', conditions={'function': check_repo}, |
|
985 | 985 | requirements=URL_NAME_REQUIREMENTS) |
|
986 | 986 | |
|
987 | 987 | rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True, |
|
988 | 988 | controller='changelog', conditions={'function': check_repo}, |
|
989 | 989 | requirements=URL_NAME_REQUIREMENTS) |
|
990 | 990 | |
|
991 | 991 | rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary', |
|
992 | 992 | controller='changelog', action='changelog_summary', |
|
993 | 993 | conditions={'function': check_repo}, |
|
994 | 994 | requirements=URL_NAME_REQUIREMENTS) |
|
995 | 995 | |
|
996 | 996 | rmap.connect('changelog_file_home', |
|
997 | 997 | '/{repo_name}/changelog/{revision}/{f_path}', |
|
998 | 998 | controller='changelog', f_path=None, |
|
999 | 999 | conditions={'function': check_repo}, |
|
1000 | 1000 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1001 | 1001 | |
|
1002 | 1002 | rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}', |
|
1003 | 1003 | controller='changelog', action='changelog_details', |
|
1004 | 1004 | conditions={'function': check_repo}, |
|
1005 | 1005 | requirements=URL_NAME_REQUIREMENTS) |
|
1006 | 1006 | |
|
1007 | 1007 | rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}', |
|
1008 | 1008 | controller='files', revision='tip', f_path='', |
|
1009 | 1009 | conditions={'function': check_repo}, |
|
1010 | 1010 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1011 | 1011 | |
|
1012 | 1012 | rmap.connect('files_home_simple_catchrev', |
|
1013 | 1013 | '/{repo_name}/files/{revision}', |
|
1014 | 1014 | controller='files', revision='tip', f_path='', |
|
1015 | 1015 | conditions={'function': check_repo}, |
|
1016 | 1016 | requirements=URL_NAME_REQUIREMENTS) |
|
1017 | 1017 | |
|
1018 | 1018 | rmap.connect('files_home_simple_catchall', |
|
1019 | 1019 | '/{repo_name}/files', |
|
1020 | 1020 | controller='files', revision='tip', f_path='', |
|
1021 | 1021 | conditions={'function': check_repo}, |
|
1022 | 1022 | requirements=URL_NAME_REQUIREMENTS) |
|
1023 | 1023 | |
|
1024 | 1024 | rmap.connect('files_history_home', |
|
1025 | 1025 | '/{repo_name}/history/{revision}/{f_path}', |
|
1026 | 1026 | controller='files', action='history', revision='tip', f_path='', |
|
1027 | 1027 | conditions={'function': check_repo}, |
|
1028 | 1028 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1029 | 1029 | |
|
1030 | 1030 | rmap.connect('files_authors_home', |
|
1031 | 1031 | '/{repo_name}/authors/{revision}/{f_path}', |
|
1032 | 1032 | controller='files', action='authors', revision='tip', f_path='', |
|
1033 | 1033 | conditions={'function': check_repo}, |
|
1034 | 1034 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1035 | 1035 | |
|
1036 | 1036 | rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}', |
|
1037 | 1037 | controller='files', action='diff', f_path='', |
|
1038 | 1038 | conditions={'function': check_repo}, |
|
1039 | 1039 | requirements=URL_NAME_REQUIREMENTS) |
|
1040 | 1040 | |
|
1041 | 1041 | rmap.connect('files_diff_2way_home', |
|
1042 | 1042 | '/{repo_name}/diff-2way/{f_path}', |
|
1043 | 1043 | controller='files', action='diff_2way', f_path='', |
|
1044 | 1044 | conditions={'function': check_repo}, |
|
1045 | 1045 | requirements=URL_NAME_REQUIREMENTS) |
|
1046 | 1046 | |
|
1047 | 1047 | rmap.connect('files_rawfile_home', |
|
1048 | 1048 | '/{repo_name}/rawfile/{revision}/{f_path}', |
|
1049 | 1049 | controller='files', action='rawfile', revision='tip', |
|
1050 | 1050 | f_path='', conditions={'function': check_repo}, |
|
1051 | 1051 | requirements=URL_NAME_REQUIREMENTS) |
|
1052 | 1052 | |
|
1053 | 1053 | rmap.connect('files_raw_home', |
|
1054 | 1054 | '/{repo_name}/raw/{revision}/{f_path}', |
|
1055 | 1055 | controller='files', action='raw', revision='tip', f_path='', |
|
1056 | 1056 | conditions={'function': check_repo}, |
|
1057 | 1057 | requirements=URL_NAME_REQUIREMENTS) |
|
1058 | 1058 | |
|
1059 | 1059 | rmap.connect('files_render_home', |
|
1060 | 1060 | '/{repo_name}/render/{revision}/{f_path}', |
|
1061 | 1061 | controller='files', action='index', revision='tip', f_path='', |
|
1062 | 1062 | rendered=True, conditions={'function': check_repo}, |
|
1063 | 1063 | requirements=URL_NAME_REQUIREMENTS) |
|
1064 | 1064 | |
|
1065 | 1065 | rmap.connect('files_annotate_home', |
|
1066 | 1066 | '/{repo_name}/annotate/{revision}/{f_path}', |
|
1067 | 1067 | controller='files', action='index', revision='tip', |
|
1068 | 1068 | f_path='', annotate=True, conditions={'function': check_repo}, |
|
1069 | requirements=URL_NAME_REQUIREMENTS) | |
|
1069 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) | |
|
1070 | 1070 | |
|
1071 | 1071 | rmap.connect('files_edit', |
|
1072 | 1072 | '/{repo_name}/edit/{revision}/{f_path}', |
|
1073 | 1073 | controller='files', action='edit', revision='tip', |
|
1074 | 1074 | f_path='', |
|
1075 | 1075 | conditions={'function': check_repo, 'method': ['POST']}, |
|
1076 | 1076 | requirements=URL_NAME_REQUIREMENTS) |
|
1077 | 1077 | |
|
1078 | 1078 | rmap.connect('files_edit_home', |
|
1079 | 1079 | '/{repo_name}/edit/{revision}/{f_path}', |
|
1080 | 1080 | controller='files', action='edit_home', revision='tip', |
|
1081 | 1081 | f_path='', conditions={'function': check_repo}, |
|
1082 | 1082 | requirements=URL_NAME_REQUIREMENTS) |
|
1083 | 1083 | |
|
1084 | 1084 | rmap.connect('files_add', |
|
1085 | 1085 | '/{repo_name}/add/{revision}/{f_path}', |
|
1086 | 1086 | controller='files', action='add', revision='tip', |
|
1087 | 1087 | f_path='', |
|
1088 | 1088 | conditions={'function': check_repo, 'method': ['POST']}, |
|
1089 | 1089 | requirements=URL_NAME_REQUIREMENTS) |
|
1090 | 1090 | |
|
1091 | 1091 | rmap.connect('files_add_home', |
|
1092 | 1092 | '/{repo_name}/add/{revision}/{f_path}', |
|
1093 | 1093 | controller='files', action='add_home', revision='tip', |
|
1094 | 1094 | f_path='', conditions={'function': check_repo}, |
|
1095 | 1095 | requirements=URL_NAME_REQUIREMENTS) |
|
1096 | 1096 | |
|
1097 | 1097 | rmap.connect('files_delete', |
|
1098 | 1098 | '/{repo_name}/delete/{revision}/{f_path}', |
|
1099 | 1099 | controller='files', action='delete', revision='tip', |
|
1100 | 1100 | f_path='', |
|
1101 | 1101 | conditions={'function': check_repo, 'method': ['POST']}, |
|
1102 | 1102 | requirements=URL_NAME_REQUIREMENTS) |
|
1103 | 1103 | |
|
1104 | 1104 | rmap.connect('files_delete_home', |
|
1105 | 1105 | '/{repo_name}/delete/{revision}/{f_path}', |
|
1106 | 1106 | controller='files', action='delete_home', revision='tip', |
|
1107 | 1107 | f_path='', conditions={'function': check_repo}, |
|
1108 | 1108 | requirements=URL_NAME_REQUIREMENTS) |
|
1109 | 1109 | |
|
1110 | 1110 | rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}', |
|
1111 | 1111 | controller='files', action='archivefile', |
|
1112 | 1112 | conditions={'function': check_repo}, |
|
1113 | 1113 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1114 | 1114 | |
|
1115 | 1115 | rmap.connect('files_nodelist_home', |
|
1116 | 1116 | '/{repo_name}/nodelist/{revision}/{f_path}', |
|
1117 | 1117 | controller='files', action='nodelist', |
|
1118 | 1118 | conditions={'function': check_repo}, |
|
1119 | 1119 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1120 | 1120 | |
|
1121 | 1121 | rmap.connect('files_nodetree_full', |
|
1122 | 1122 | '/{repo_name}/nodetree_full/{commit_id}/{f_path}', |
|
1123 | 1123 | controller='files', action='nodetree_full', |
|
1124 | 1124 | conditions={'function': check_repo}, |
|
1125 | 1125 | requirements=URL_NAME_REQUIREMENTS, jsroute=True) |
|
1126 | 1126 | |
|
1127 | 1127 | rmap.connect('repo_fork_create_home', '/{repo_name}/fork', |
|
1128 | 1128 | controller='forks', action='fork_create', |
|
1129 | 1129 | conditions={'function': check_repo, 'method': ['POST']}, |
|
1130 | 1130 | requirements=URL_NAME_REQUIREMENTS) |
|
1131 | 1131 | |
|
1132 | 1132 | rmap.connect('repo_fork_home', '/{repo_name}/fork', |
|
1133 | 1133 | controller='forks', action='fork', |
|
1134 | 1134 | conditions={'function': check_repo}, |
|
1135 | 1135 | requirements=URL_NAME_REQUIREMENTS) |
|
1136 | 1136 | |
|
1137 | 1137 | rmap.connect('repo_forks_home', '/{repo_name}/forks', |
|
1138 | 1138 | controller='forks', action='forks', |
|
1139 | 1139 | conditions={'function': check_repo}, |
|
1140 | 1140 | requirements=URL_NAME_REQUIREMENTS) |
|
1141 | 1141 | |
|
1142 | 1142 | rmap.connect('repo_followers_home', '/{repo_name}/followers', |
|
1143 | 1143 | controller='followers', action='followers', |
|
1144 | 1144 | conditions={'function': check_repo}, |
|
1145 | 1145 | requirements=URL_NAME_REQUIREMENTS) |
|
1146 | 1146 | |
|
1147 | 1147 | # must be here for proper group/repo catching pattern |
|
1148 | 1148 | _connect_with_slash( |
|
1149 | 1149 | rmap, 'repo_group_home', '/{group_name}', |
|
1150 | 1150 | controller='home', action='index_repo_group', |
|
1151 | 1151 | conditions={'function': check_group}, |
|
1152 | 1152 | requirements=URL_NAME_REQUIREMENTS) |
|
1153 | 1153 | |
|
1154 | 1154 | # catch all, at the end |
|
1155 | 1155 | _connect_with_slash( |
|
1156 | 1156 | rmap, 'summary_home', '/{repo_name}', jsroute=True, |
|
1157 | 1157 | controller='summary', action='index', |
|
1158 | 1158 | conditions={'function': check_repo}, |
|
1159 | 1159 | requirements=URL_NAME_REQUIREMENTS) |
|
1160 | 1160 | |
|
1161 | 1161 | return rmap |
|
1162 | 1162 | |
|
1163 | 1163 | |
|
1164 | 1164 | def _connect_with_slash(mapper, name, path, *args, **kwargs): |
|
1165 | 1165 | """ |
|
1166 | 1166 | Connect a route with an optional trailing slash in `path`. |
|
1167 | 1167 | """ |
|
1168 | 1168 | mapper.connect(name + '_slash', path + '/', *args, **kwargs) |
|
1169 | 1169 | mapper.connect(name, path, *args, **kwargs) |
@@ -1,264 +1,270 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2012-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | """ |
|
22 | 22 | Compare controller for showing differences between two commits/refs/tags etc. |
|
23 | 23 | """ |
|
24 | 24 | |
|
25 | 25 | import logging |
|
26 | 26 | |
|
27 | 27 | from webob.exc import HTTPBadRequest |
|
28 | 28 | from pylons import request, tmpl_context as c, url |
|
29 | 29 | from pylons.controllers.util import redirect |
|
30 | 30 | from pylons.i18n.translation import _ |
|
31 | 31 | |
|
32 | 32 | from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name |
|
33 | 33 | from rhodecode.lib import helpers as h |
|
34 | 34 | from rhodecode.lib import diffs, codeblocks |
|
35 | 35 | from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator |
|
36 | 36 | from rhodecode.lib.base import BaseRepoController, render |
|
37 | 37 | from rhodecode.lib.utils import safe_str |
|
38 | 38 | from rhodecode.lib.utils2 import safe_unicode, str2bool |
|
39 | 39 | from rhodecode.lib.vcs.exceptions import ( |
|
40 | 40 | EmptyRepositoryError, RepositoryError, RepositoryRequirementError, |
|
41 | 41 | NodeDoesNotExistError) |
|
42 | 42 | from rhodecode.model.db import Repository, ChangesetStatus |
|
43 | 43 | |
|
44 | 44 | log = logging.getLogger(__name__) |
|
45 | 45 | |
|
46 | 46 | |
|
47 | 47 | class CompareController(BaseRepoController): |
|
48 | 48 | |
|
49 | 49 | def __before__(self): |
|
50 | 50 | super(CompareController, self).__before__() |
|
51 | 51 | |
|
52 | 52 | def _get_commit_or_redirect( |
|
53 | 53 | self, ref, ref_type, repo, redirect_after=True, partial=False): |
|
54 | 54 | """ |
|
55 | 55 | This is a safe way to get a commit. If an error occurs it |
|
56 | 56 | redirects to a commit with a proper message. If partial is set |
|
57 | 57 | then it does not do redirect raise and throws an exception instead. |
|
58 | 58 | """ |
|
59 | 59 | try: |
|
60 | 60 | return get_commit_from_ref_name(repo, safe_str(ref), ref_type) |
|
61 | 61 | except EmptyRepositoryError: |
|
62 | 62 | if not redirect_after: |
|
63 | 63 | return repo.scm_instance().EMPTY_COMMIT |
|
64 | 64 | h.flash(h.literal(_('There are no commits yet')), |
|
65 | 65 | category='warning') |
|
66 | 66 | redirect(url('summary_home', repo_name=repo.repo_name)) |
|
67 | 67 | |
|
68 | 68 | except RepositoryError as e: |
|
69 | 69 | msg = safe_str(e) |
|
70 | 70 | log.exception(msg) |
|
71 | 71 | h.flash(msg, category='warning') |
|
72 | 72 | if not partial: |
|
73 | 73 | redirect(h.url('summary_home', repo_name=repo.repo_name)) |
|
74 | 74 | raise HTTPBadRequest() |
|
75 | 75 | |
|
76 | 76 | @LoginRequired() |
|
77 | 77 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
78 | 78 | 'repository.admin') |
|
79 | 79 | def index(self, repo_name): |
|
80 | 80 | c.compare_home = True |
|
81 | 81 | c.commit_ranges = [] |
|
82 | 82 | c.diffset = None |
|
83 | 83 | c.limited_diff = False |
|
84 | 84 | source_repo = c.rhodecode_db_repo.repo_name |
|
85 | 85 | target_repo = request.GET.get('target_repo', source_repo) |
|
86 | 86 | c.source_repo = Repository.get_by_repo_name(source_repo) |
|
87 | 87 | c.target_repo = Repository.get_by_repo_name(target_repo) |
|
88 | 88 | c.source_ref = c.target_ref = _('Select commit') |
|
89 | 89 | c.source_ref_type = "" |
|
90 | 90 | c.target_ref_type = "" |
|
91 | 91 | c.commit_statuses = ChangesetStatus.STATUSES |
|
92 | 92 | c.preview_mode = False |
|
93 | c.file_path = None | |
|
93 | 94 | return render('compare/compare_diff.html') |
|
94 | 95 | |
|
95 | 96 | @LoginRequired() |
|
96 | 97 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
97 | 98 | 'repository.admin') |
|
98 | 99 | def compare(self, repo_name, source_ref_type, source_ref, |
|
99 | 100 | target_ref_type, target_ref): |
|
100 | 101 | # source_ref will be evaluated in source_repo |
|
101 | 102 | source_repo_name = c.rhodecode_db_repo.repo_name |
|
102 | 103 | source_path, source_id = parse_path_ref(source_ref) |
|
103 | 104 | |
|
104 | 105 | # target_ref will be evaluated in target_repo |
|
105 | 106 | target_repo_name = request.GET.get('target_repo', source_repo_name) |
|
106 |
target_path, target_id = parse_path_ref( |
|
|
107 | target_path, target_id = parse_path_ref( | |
|
108 | target_ref, default_path=request.GET.get('f_path', '')) | |
|
107 | 109 | |
|
110 | c.file_path = target_path | |
|
108 | 111 | c.commit_statuses = ChangesetStatus.STATUSES |
|
109 | 112 | |
|
110 | 113 | # if merge is True |
|
111 | 114 | # Show what changes since the shared ancestor commit of target/source |
|
112 | 115 | # the source would get if it was merged with target. Only commits |
|
113 | 116 | # which are in target but not in source will be shown. |
|
114 | 117 | merge = str2bool(request.GET.get('merge')) |
|
115 | 118 | # if merge is False |
|
116 | 119 | # Show a raw diff of source/target refs even if no ancestor exists |
|
117 | 120 | |
|
118 | ||
|
119 | 121 | # c.fulldiff disables cut_off_limit |
|
120 | 122 | c.fulldiff = str2bool(request.GET.get('fulldiff')) |
|
121 | 123 | |
|
122 | 124 | # if partial, returns just compare_commits.html (commits log) |
|
123 | 125 | partial = request.is_xhr |
|
124 | 126 | |
|
125 | 127 | # swap url for compare_diff page |
|
126 | 128 | c.swap_url = h.url( |
|
127 | 129 | 'compare_url', |
|
128 | 130 | repo_name=target_repo_name, |
|
129 | 131 | source_ref_type=target_ref_type, |
|
130 | 132 | source_ref=target_ref, |
|
131 | 133 | target_repo=source_repo_name, |
|
132 | 134 | target_ref_type=source_ref_type, |
|
133 | 135 | target_ref=source_ref, |
|
134 |
merge=merge and '1' or '' |
|
|
136 | merge=merge and '1' or '', | |
|
137 | f_path=target_path) | |
|
135 | 138 | |
|
136 | 139 | source_repo = Repository.get_by_repo_name(source_repo_name) |
|
137 | 140 | target_repo = Repository.get_by_repo_name(target_repo_name) |
|
138 | 141 | |
|
139 | 142 | if source_repo is None: |
|
140 | 143 | msg = _('Could not find the original repo: %(repo)s') % { |
|
141 | 144 | 'repo': source_repo} |
|
142 | 145 | |
|
143 | 146 | log.error(msg) |
|
144 | 147 | h.flash(msg, category='error') |
|
145 | 148 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
146 | 149 | |
|
147 | 150 | if target_repo is None: |
|
148 | 151 | msg = _('Could not find the other repo: %(repo)s') % { |
|
149 | 152 | 'repo': target_repo_name} |
|
150 | 153 | log.error(msg) |
|
151 | 154 | h.flash(msg, category='error') |
|
152 | 155 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
153 | 156 | |
|
154 |
source_ |
|
|
155 |
target_ |
|
|
157 | source_scm = source_repo.scm_instance() | |
|
158 | target_scm = target_repo.scm_instance() | |
|
159 | ||
|
160 | source_alias = source_scm.alias | |
|
161 | target_alias = target_scm.alias | |
|
156 | 162 | if source_alias != target_alias: |
|
157 | 163 | msg = _('The comparison of two different kinds of remote repos ' |
|
158 | 164 | 'is not available') |
|
159 | 165 | log.error(msg) |
|
160 | 166 | h.flash(msg, category='error') |
|
161 | 167 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
162 | 168 | |
|
163 | 169 | source_commit = self._get_commit_or_redirect( |
|
164 | 170 | ref=source_id, ref_type=source_ref_type, repo=source_repo, |
|
165 | 171 | partial=partial) |
|
166 | 172 | target_commit = self._get_commit_or_redirect( |
|
167 | 173 | ref=target_id, ref_type=target_ref_type, repo=target_repo, |
|
168 | 174 | partial=partial) |
|
169 | 175 | |
|
170 | 176 | c.compare_home = False |
|
171 | 177 | c.source_repo = source_repo |
|
172 | 178 | c.target_repo = target_repo |
|
173 | 179 | c.source_ref = source_ref |
|
174 | 180 | c.target_ref = target_ref |
|
175 | 181 | c.source_ref_type = source_ref_type |
|
176 | 182 | c.target_ref_type = target_ref_type |
|
177 | 183 | |
|
178 | source_scm = source_repo.scm_instance() | |
|
179 | target_scm = target_repo.scm_instance() | |
|
180 | ||
|
181 | 184 | pre_load = ["author", "branch", "date", "message"] |
|
182 | 185 | c.ancestor = None |
|
183 | 186 | try: |
|
184 | 187 | c.commit_ranges = source_scm.compare( |
|
185 | 188 | source_commit.raw_id, target_commit.raw_id, |
|
186 | 189 | target_scm, merge, pre_load=pre_load) |
|
187 | 190 | if merge: |
|
188 | 191 | c.ancestor = source_scm.get_common_ancestor( |
|
189 | 192 | source_commit.raw_id, target_commit.raw_id, target_scm) |
|
190 | 193 | except RepositoryRequirementError: |
|
191 | 194 | msg = _('Could not compare repos with different ' |
|
192 | 195 | 'large file settings') |
|
193 | 196 | log.error(msg) |
|
194 | 197 | if partial: |
|
195 | 198 | return msg |
|
196 | 199 | h.flash(msg, category='error') |
|
197 | 200 | return redirect(url('compare_home', repo_name=c.repo_name)) |
|
198 | 201 | |
|
199 | 202 | c.statuses = c.rhodecode_db_repo.statuses( |
|
200 | 203 | [x.raw_id for x in c.commit_ranges]) |
|
201 | 204 | |
|
202 | if partial: # for PR ajax commits loader | |
|
205 | if partial: # for PR ajax commits loader | |
|
203 | 206 | if not c.ancestor: |
|
204 | return '' # cannot merge if there is no ancestor | |
|
207 | return '' # cannot merge if there is no ancestor | |
|
205 | 208 | return render('compare/compare_commits.html') |
|
206 | 209 | |
|
207 | 210 | if c.ancestor: |
|
208 | 211 | # case we want a simple diff without incoming commits, |
|
209 | 212 | # previewing what will be merged. |
|
210 | 213 | # Make the diff on target repo (which is known to have target_ref) |
|
211 | 214 | log.debug('Using ancestor %s as source_ref instead of %s' |
|
212 | 215 | % (c.ancestor, source_ref)) |
|
213 | 216 | source_repo = target_repo |
|
214 | 217 | source_commit = target_repo.get_commit(commit_id=c.ancestor) |
|
215 | 218 | |
|
216 | 219 | # diff_limit will cut off the whole diff if the limit is applied |
|
217 | 220 | # otherwise it will just hide the big files from the front-end |
|
218 | 221 | diff_limit = self.cut_off_limit_diff |
|
219 | 222 | file_limit = self.cut_off_limit_file |
|
220 | 223 | |
|
221 | 224 | log.debug('calculating diff between ' |
|
222 | 225 | 'source_ref:%s and target_ref:%s for repo `%s`', |
|
223 | 226 | source_commit, target_commit, |
|
224 | 227 | safe_unicode(source_repo.scm_instance().path)) |
|
225 | 228 | |
|
226 | 229 | if source_commit.repository != target_commit.repository: |
|
227 | 230 | msg = _( |
|
228 | 231 | "Repositories unrelated. " |
|
229 | 232 | "Cannot compare commit %(commit1)s from repository %(repo1)s " |
|
230 | 233 | "with commit %(commit2)s from repository %(repo2)s.") % { |
|
231 | 234 | 'commit1': h.show_id(source_commit), |
|
232 | 235 | 'repo1': source_repo.repo_name, |
|
233 | 236 | 'commit2': h.show_id(target_commit), |
|
234 | 237 | 'repo2': target_repo.repo_name, |
|
235 | 238 | } |
|
236 | 239 | h.flash(msg, category='error') |
|
237 | 240 | raise HTTPBadRequest() |
|
238 | 241 | |
|
239 | 242 | txtdiff = source_repo.scm_instance().get_diff( |
|
240 | 243 | commit1=source_commit, commit2=target_commit, |
|
241 |
path1=source_path |
|
|
244 | path=target_path, path1=source_path) | |
|
245 | ||
|
242 | 246 | diff_processor = diffs.DiffProcessor( |
|
243 | 247 | txtdiff, format='newdiff', diff_limit=diff_limit, |
|
244 | 248 | file_limit=file_limit, show_full_diff=c.fulldiff) |
|
245 | 249 | _parsed = diff_processor.prepare() |
|
246 | 250 | |
|
247 | 251 | def _node_getter(commit): |
|
248 | 252 | """ Returns a function that returns a node for a commit or None """ |
|
249 | 253 | def get_node(fname): |
|
250 | 254 | try: |
|
251 | 255 | return commit.get_node(fname) |
|
252 | 256 | except NodeDoesNotExistError: |
|
253 | 257 | return None |
|
254 | 258 | return get_node |
|
255 | 259 | |
|
256 | 260 | c.diffset = codeblocks.DiffSet( |
|
257 | 261 | repo_name=source_repo.repo_name, |
|
258 | 262 | source_node_getter=_node_getter(source_commit), |
|
259 | 263 | target_node_getter=_node_getter(target_commit), |
|
260 | 264 | ).render_patchset(_parsed, source_ref, target_ref) |
|
261 | 265 | |
|
262 | 266 | c.preview_mode = merge |
|
267 | c.source_commit = source_commit | |
|
268 | c.target_commit = target_commit | |
|
263 | 269 | |
|
264 | 270 | return render('compare/compare_diff.html') |
@@ -1,1127 +1,1061 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2010-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | """ |
|
22 | 22 | Files controller for RhodeCode Enterprise |
|
23 | 23 | """ |
|
24 | 24 | |
|
25 | 25 | import itertools |
|
26 | 26 | import logging |
|
27 | 27 | import os |
|
28 | 28 | import shutil |
|
29 | 29 | import tempfile |
|
30 | 30 | |
|
31 | 31 | from pylons import request, response, tmpl_context as c, url |
|
32 | 32 | from pylons.i18n.translation import _ |
|
33 | 33 | from pylons.controllers.util import redirect |
|
34 | 34 | from webob.exc import HTTPNotFound, HTTPBadRequest |
|
35 | 35 | |
|
36 | 36 | from rhodecode.controllers.utils import parse_path_ref |
|
37 | 37 | from rhodecode.lib import diffs, helpers as h, caches |
|
38 | 38 | from rhodecode.lib.compat import OrderedDict |
|
39 | 39 | from rhodecode.lib.codeblocks import ( |
|
40 | 40 | filenode_as_lines_tokens, filenode_as_annotated_lines_tokens) |
|
41 | 41 | from rhodecode.lib.utils import jsonify, action_logger |
|
42 | 42 | from rhodecode.lib.utils2 import ( |
|
43 | 43 | convert_line_endings, detect_mode, safe_str, str2bool) |
|
44 | 44 | from rhodecode.lib.auth import ( |
|
45 | 45 | LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired, XHRRequired) |
|
46 | 46 | from rhodecode.lib.base import BaseRepoController, render |
|
47 | 47 | from rhodecode.lib.vcs import path as vcspath |
|
48 | 48 | from rhodecode.lib.vcs.backends.base import EmptyCommit |
|
49 | 49 | from rhodecode.lib.vcs.conf import settings |
|
50 | 50 | from rhodecode.lib.vcs.exceptions import ( |
|
51 | 51 | RepositoryError, CommitDoesNotExistError, EmptyRepositoryError, |
|
52 | 52 | ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError, |
|
53 | 53 | NodeDoesNotExistError, CommitError, NodeError) |
|
54 | 54 | from rhodecode.lib.vcs.nodes import FileNode |
|
55 | 55 | |
|
56 | 56 | from rhodecode.model.repo import RepoModel |
|
57 | 57 | from rhodecode.model.scm import ScmModel |
|
58 | 58 | from rhodecode.model.db import Repository |
|
59 | 59 | |
|
60 | 60 | from rhodecode.controllers.changeset import ( |
|
61 | 61 | _ignorews_url, _context_url, get_line_ctx, get_ignore_ws) |
|
62 | 62 | from rhodecode.lib.exceptions import NonRelativePathError |
|
63 | 63 | |
|
64 | 64 | log = logging.getLogger(__name__) |
|
65 | 65 | |
|
66 | 66 | |
|
67 | 67 | class FilesController(BaseRepoController): |
|
68 | 68 | |
|
69 | 69 | def __before__(self): |
|
70 | 70 | super(FilesController, self).__before__() |
|
71 | 71 | c.cut_off_limit = self.cut_off_limit_file |
|
72 | 72 | |
|
73 | 73 | def _get_default_encoding(self): |
|
74 | 74 | enc_list = getattr(c, 'default_encodings', []) |
|
75 | 75 | return enc_list[0] if enc_list else 'UTF-8' |
|
76 | 76 | |
|
77 | 77 | def __get_commit_or_redirect(self, commit_id, repo_name, |
|
78 | 78 | redirect_after=True): |
|
79 | 79 | """ |
|
80 | 80 | This is a safe way to get commit. If an error occurs it redirects to |
|
81 | 81 | tip with proper message |
|
82 | 82 | |
|
83 | 83 | :param commit_id: id of commit to fetch |
|
84 | 84 | :param repo_name: repo name to redirect after |
|
85 | 85 | :param redirect_after: toggle redirection |
|
86 | 86 | """ |
|
87 | 87 | try: |
|
88 | 88 | return c.rhodecode_repo.get_commit(commit_id) |
|
89 | 89 | except EmptyRepositoryError: |
|
90 | 90 | if not redirect_after: |
|
91 | 91 | return None |
|
92 | 92 | url_ = url('files_add_home', |
|
93 | 93 | repo_name=c.repo_name, |
|
94 | 94 | revision=0, f_path='', anchor='edit') |
|
95 | 95 | if h.HasRepoPermissionAny( |
|
96 | 96 | 'repository.write', 'repository.admin')(c.repo_name): |
|
97 | 97 | add_new = h.link_to( |
|
98 | 98 | _('Click here to add a new file.'), |
|
99 | 99 | url_, class_="alert-link") |
|
100 | 100 | else: |
|
101 | 101 | add_new = "" |
|
102 | 102 | h.flash(h.literal( |
|
103 | 103 | _('There are no files yet. %s') % add_new), category='warning') |
|
104 | 104 | redirect(h.url('summary_home', repo_name=repo_name)) |
|
105 | 105 | except (CommitDoesNotExistError, LookupError): |
|
106 | 106 | msg = _('No such commit exists for this repository') |
|
107 | 107 | h.flash(msg, category='error') |
|
108 | 108 | raise HTTPNotFound() |
|
109 | 109 | except RepositoryError as e: |
|
110 | 110 | h.flash(safe_str(e), category='error') |
|
111 | 111 | raise HTTPNotFound() |
|
112 | 112 | |
|
113 | 113 | def __get_filenode_or_redirect(self, repo_name, commit, path): |
|
114 | 114 | """ |
|
115 | 115 | Returns file_node, if error occurs or given path is directory, |
|
116 | 116 | it'll redirect to top level path |
|
117 | 117 | |
|
118 | 118 | :param repo_name: repo_name |
|
119 | 119 | :param commit: given commit |
|
120 | 120 | :param path: path to lookup |
|
121 | 121 | """ |
|
122 | 122 | try: |
|
123 | 123 | file_node = commit.get_node(path) |
|
124 | 124 | if file_node.is_dir(): |
|
125 | 125 | raise RepositoryError('The given path is a directory') |
|
126 | 126 | except CommitDoesNotExistError: |
|
127 | 127 | msg = _('No such commit exists for this repository') |
|
128 | 128 | log.exception(msg) |
|
129 | 129 | h.flash(msg, category='error') |
|
130 | 130 | raise HTTPNotFound() |
|
131 | 131 | except RepositoryError as e: |
|
132 | 132 | h.flash(safe_str(e), category='error') |
|
133 | 133 | raise HTTPNotFound() |
|
134 | 134 | |
|
135 | 135 | return file_node |
|
136 | 136 | |
|
137 | 137 | def __get_tree_cache_manager(self, repo_name, namespace_type): |
|
138 | 138 | _namespace = caches.get_repo_namespace_key(namespace_type, repo_name) |
|
139 | 139 | return caches.get_cache_manager('repo_cache_long', _namespace) |
|
140 | 140 | |
|
141 | 141 | def _get_tree_at_commit(self, repo_name, commit_id, f_path, |
|
142 | 142 | full_load=False, force=False): |
|
143 | 143 | def _cached_tree(): |
|
144 | 144 | log.debug('Generating cached file tree for %s, %s, %s', |
|
145 | 145 | repo_name, commit_id, f_path) |
|
146 | 146 | c.full_load = full_load |
|
147 | 147 | return render('files/files_browser_tree.html') |
|
148 | 148 | |
|
149 | 149 | cache_manager = self.__get_tree_cache_manager( |
|
150 | 150 | repo_name, caches.FILE_TREE) |
|
151 | 151 | |
|
152 | 152 | cache_key = caches.compute_key_from_params( |
|
153 | 153 | repo_name, commit_id, f_path) |
|
154 | 154 | |
|
155 | 155 | if force: |
|
156 | 156 | # we want to force recompute of caches |
|
157 | 157 | cache_manager.remove_value(cache_key) |
|
158 | 158 | |
|
159 | 159 | return cache_manager.get(cache_key, createfunc=_cached_tree) |
|
160 | 160 | |
|
161 | 161 | def _get_nodelist_at_commit(self, repo_name, commit_id, f_path): |
|
162 | 162 | def _cached_nodes(): |
|
163 | 163 | log.debug('Generating cached nodelist for %s, %s, %s', |
|
164 | 164 | repo_name, commit_id, f_path) |
|
165 | 165 | _d, _f = ScmModel().get_nodes( |
|
166 | 166 | repo_name, commit_id, f_path, flat=False) |
|
167 | 167 | return _d + _f |
|
168 | 168 | |
|
169 | 169 | cache_manager = self.__get_tree_cache_manager( |
|
170 | 170 | repo_name, caches.FILE_SEARCH_TREE_META) |
|
171 | 171 | |
|
172 | 172 | cache_key = caches.compute_key_from_params( |
|
173 | 173 | repo_name, commit_id, f_path) |
|
174 | 174 | return cache_manager.get(cache_key, createfunc=_cached_nodes) |
|
175 | 175 | |
|
176 | 176 | @LoginRequired() |
|
177 | 177 | @HasRepoPermissionAnyDecorator( |
|
178 | 178 | 'repository.read', 'repository.write', 'repository.admin') |
|
179 | 179 | def index( |
|
180 | 180 | self, repo_name, revision, f_path, annotate=False, rendered=False): |
|
181 | 181 | commit_id = revision |
|
182 | 182 | |
|
183 | 183 | # redirect to given commit_id from form if given |
|
184 | 184 | get_commit_id = request.GET.get('at_rev', None) |
|
185 | 185 | if get_commit_id: |
|
186 | 186 | self.__get_commit_or_redirect(get_commit_id, repo_name) |
|
187 | 187 | |
|
188 | 188 | c.commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
189 | 189 | c.branch = request.GET.get('branch', None) |
|
190 | 190 | c.f_path = f_path |
|
191 | 191 | c.annotate = annotate |
|
192 | 192 | # default is false, but .rst/.md files later are autorendered, we can |
|
193 | 193 | # overwrite autorendering by setting this GET flag |
|
194 | 194 | c.renderer = rendered or not request.GET.get('no-render', False) |
|
195 | 195 | |
|
196 | 196 | # prev link |
|
197 | 197 | try: |
|
198 | 198 | prev_commit = c.commit.prev(c.branch) |
|
199 | 199 | c.prev_commit = prev_commit |
|
200 | 200 | c.url_prev = url('files_home', repo_name=c.repo_name, |
|
201 | 201 | revision=prev_commit.raw_id, f_path=f_path) |
|
202 | 202 | if c.branch: |
|
203 | 203 | c.url_prev += '?branch=%s' % c.branch |
|
204 | 204 | except (CommitDoesNotExistError, VCSError): |
|
205 | 205 | c.url_prev = '#' |
|
206 | 206 | c.prev_commit = EmptyCommit() |
|
207 | 207 | |
|
208 | 208 | # next link |
|
209 | 209 | try: |
|
210 | 210 | next_commit = c.commit.next(c.branch) |
|
211 | 211 | c.next_commit = next_commit |
|
212 | 212 | c.url_next = url('files_home', repo_name=c.repo_name, |
|
213 | 213 | revision=next_commit.raw_id, f_path=f_path) |
|
214 | 214 | if c.branch: |
|
215 | 215 | c.url_next += '?branch=%s' % c.branch |
|
216 | 216 | except (CommitDoesNotExistError, VCSError): |
|
217 | 217 | c.url_next = '#' |
|
218 | 218 | c.next_commit = EmptyCommit() |
|
219 | 219 | |
|
220 | 220 | # files or dirs |
|
221 | 221 | try: |
|
222 | 222 | c.file = c.commit.get_node(f_path) |
|
223 | 223 | c.file_author = True |
|
224 | 224 | c.file_tree = '' |
|
225 | 225 | if c.file.is_file(): |
|
226 | 226 | c.file_source_page = 'true' |
|
227 | 227 | c.file_last_commit = c.file.last_commit |
|
228 | 228 | if c.file.size < self.cut_off_limit_file: |
|
229 | 229 | if c.annotate: # annotation has precedence over renderer |
|
230 | 230 | c.annotated_lines = filenode_as_annotated_lines_tokens( |
|
231 | 231 | c.file |
|
232 | 232 | ) |
|
233 | 233 | else: |
|
234 | 234 | c.renderer = ( |
|
235 | 235 | c.renderer and h.renderer_from_filename(c.file.path) |
|
236 | 236 | ) |
|
237 | 237 | if not c.renderer: |
|
238 | 238 | c.lines = filenode_as_lines_tokens(c.file) |
|
239 | 239 | |
|
240 | 240 | c.on_branch_head = self._is_valid_head( |
|
241 | 241 | commit_id, c.rhodecode_repo) |
|
242 | 242 | c.branch_or_raw_id = c.commit.branch or c.commit.raw_id |
|
243 | 243 | |
|
244 | 244 | author = c.file_last_commit.author |
|
245 | 245 | c.authors = [(h.email(author), |
|
246 | 246 | h.person(author, 'username_or_name_or_email'))] |
|
247 | 247 | else: |
|
248 | 248 | c.file_source_page = 'false' |
|
249 | 249 | c.authors = [] |
|
250 | 250 | c.file_tree = self._get_tree_at_commit( |
|
251 | 251 | repo_name, c.commit.raw_id, f_path) |
|
252 | 252 | |
|
253 | 253 | except RepositoryError as e: |
|
254 | 254 | h.flash(safe_str(e), category='error') |
|
255 | 255 | raise HTTPNotFound() |
|
256 | 256 | |
|
257 | 257 | if request.environ.get('HTTP_X_PJAX'): |
|
258 | 258 | return render('files/files_pjax.html') |
|
259 | 259 | |
|
260 | 260 | return render('files/files.html') |
|
261 | 261 | |
|
262 | 262 | @LoginRequired() |
|
263 | 263 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
264 | 264 | 'repository.admin') |
|
265 | 265 | @jsonify |
|
266 | 266 | def history(self, repo_name, revision, f_path): |
|
267 | 267 | commit = self.__get_commit_or_redirect(revision, repo_name) |
|
268 | 268 | f_path = f_path |
|
269 | 269 | _file = commit.get_node(f_path) |
|
270 | 270 | if _file.is_file(): |
|
271 | 271 | file_history, _hist = self._get_node_history(commit, f_path) |
|
272 | 272 | |
|
273 | 273 | res = [] |
|
274 | 274 | for obj in file_history: |
|
275 | 275 | res.append({ |
|
276 | 276 | 'text': obj[1], |
|
277 | 277 | 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]] |
|
278 | 278 | }) |
|
279 | 279 | |
|
280 | 280 | data = { |
|
281 | 281 | 'more': False, |
|
282 | 282 | 'results': res |
|
283 | 283 | } |
|
284 | 284 | return data |
|
285 | 285 | |
|
286 | 286 | @LoginRequired() |
|
287 | 287 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
288 | 288 | 'repository.admin') |
|
289 | 289 | def authors(self, repo_name, revision, f_path): |
|
290 | 290 | commit = self.__get_commit_or_redirect(revision, repo_name) |
|
291 | 291 | file_node = commit.get_node(f_path) |
|
292 | 292 | if file_node.is_file(): |
|
293 | 293 | c.file_last_commit = file_node.last_commit |
|
294 | 294 | if request.GET.get('annotate') == '1': |
|
295 | 295 | # use _hist from annotation if annotation mode is on |
|
296 | 296 | commit_ids = set(x[1] for x in file_node.annotate) |
|
297 | 297 | _hist = ( |
|
298 | 298 | c.rhodecode_repo.get_commit(commit_id) |
|
299 | 299 | for commit_id in commit_ids) |
|
300 | 300 | else: |
|
301 | 301 | _f_history, _hist = self._get_node_history(commit, f_path) |
|
302 | 302 | c.file_author = False |
|
303 | 303 | c.authors = [] |
|
304 | 304 | for author in set(commit.author for commit in _hist): |
|
305 | 305 | c.authors.append(( |
|
306 | 306 | h.email(author), |
|
307 | 307 | h.person(author, 'username_or_name_or_email'))) |
|
308 | 308 | return render('files/file_authors_box.html') |
|
309 | 309 | |
|
310 | 310 | @LoginRequired() |
|
311 | 311 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
312 | 312 | 'repository.admin') |
|
313 | 313 | def rawfile(self, repo_name, revision, f_path): |
|
314 | 314 | """ |
|
315 | 315 | Action for download as raw |
|
316 | 316 | """ |
|
317 | 317 | commit = self.__get_commit_or_redirect(revision, repo_name) |
|
318 | 318 | file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path) |
|
319 | 319 | |
|
320 | 320 | response.content_disposition = 'attachment; filename=%s' % \ |
|
321 | 321 | safe_str(f_path.split(Repository.NAME_SEP)[-1]) |
|
322 | 322 | |
|
323 | 323 | response.content_type = file_node.mimetype |
|
324 | 324 | charset = self._get_default_encoding() |
|
325 | 325 | if charset: |
|
326 | 326 | response.charset = charset |
|
327 | 327 | |
|
328 | 328 | return file_node.content |
|
329 | 329 | |
|
330 | 330 | @LoginRequired() |
|
331 | 331 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
332 | 332 | 'repository.admin') |
|
333 | 333 | def raw(self, repo_name, revision, f_path): |
|
334 | 334 | """ |
|
335 | 335 | Action for show as raw, some mimetypes are "rendered", |
|
336 | 336 | those include images, icons. |
|
337 | 337 | """ |
|
338 | 338 | commit = self.__get_commit_or_redirect(revision, repo_name) |
|
339 | 339 | file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path) |
|
340 | 340 | |
|
341 | 341 | raw_mimetype_mapping = { |
|
342 | 342 | # map original mimetype to a mimetype used for "show as raw" |
|
343 | 343 | # you can also provide a content-disposition to override the |
|
344 | 344 | # default "attachment" disposition. |
|
345 | 345 | # orig_type: (new_type, new_dispo) |
|
346 | 346 | |
|
347 | 347 | # show images inline: |
|
348 | 348 | # Do not re-add SVG: it is unsafe and permits XSS attacks. One can |
|
349 | 349 | # for example render an SVG with javascript inside or even render |
|
350 | 350 | # HTML. |
|
351 | 351 | 'image/x-icon': ('image/x-icon', 'inline'), |
|
352 | 352 | 'image/png': ('image/png', 'inline'), |
|
353 | 353 | 'image/gif': ('image/gif', 'inline'), |
|
354 | 354 | 'image/jpeg': ('image/jpeg', 'inline'), |
|
355 | 355 | } |
|
356 | 356 | |
|
357 | 357 | mimetype = file_node.mimetype |
|
358 | 358 | try: |
|
359 | 359 | mimetype, dispo = raw_mimetype_mapping[mimetype] |
|
360 | 360 | except KeyError: |
|
361 | 361 | # we don't know anything special about this, handle it safely |
|
362 | 362 | if file_node.is_binary: |
|
363 | 363 | # do same as download raw for binary files |
|
364 | 364 | mimetype, dispo = 'application/octet-stream', 'attachment' |
|
365 | 365 | else: |
|
366 | 366 | # do not just use the original mimetype, but force text/plain, |
|
367 | 367 | # otherwise it would serve text/html and that might be unsafe. |
|
368 | 368 | # Note: underlying vcs library fakes text/plain mimetype if the |
|
369 | 369 | # mimetype can not be determined and it thinks it is not |
|
370 | 370 | # binary.This might lead to erroneous text display in some |
|
371 | 371 | # cases, but helps in other cases, like with text files |
|
372 | 372 | # without extension. |
|
373 | 373 | mimetype, dispo = 'text/plain', 'inline' |
|
374 | 374 | |
|
375 | 375 | if dispo == 'attachment': |
|
376 | 376 | dispo = 'attachment; filename=%s' % safe_str( |
|
377 | 377 | f_path.split(os.sep)[-1]) |
|
378 | 378 | |
|
379 | 379 | response.content_disposition = dispo |
|
380 | 380 | response.content_type = mimetype |
|
381 | 381 | charset = self._get_default_encoding() |
|
382 | 382 | if charset: |
|
383 | 383 | response.charset = charset |
|
384 | 384 | return file_node.content |
|
385 | 385 | |
|
386 | 386 | @CSRFRequired() |
|
387 | 387 | @LoginRequired() |
|
388 | 388 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
389 | 389 | def delete(self, repo_name, revision, f_path): |
|
390 | 390 | commit_id = revision |
|
391 | 391 | |
|
392 | 392 | repo = c.rhodecode_db_repo |
|
393 | 393 | if repo.enable_locking and repo.locked[0]: |
|
394 | 394 | h.flash(_('This repository has been locked by %s on %s') |
|
395 | 395 | % (h.person_by_id(repo.locked[0]), |
|
396 | 396 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
397 | 397 | 'warning') |
|
398 | 398 | return redirect(h.url('files_home', |
|
399 | 399 | repo_name=repo_name, revision='tip')) |
|
400 | 400 | |
|
401 | 401 | if not self._is_valid_head(commit_id, repo.scm_instance()): |
|
402 | 402 | h.flash(_('You can only delete files with revision ' |
|
403 | 403 | 'being a valid branch '), category='warning') |
|
404 | 404 | return redirect(h.url('files_home', |
|
405 | 405 | repo_name=repo_name, revision='tip', |
|
406 | 406 | f_path=f_path)) |
|
407 | 407 | |
|
408 | 408 | c.commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
409 | 409 | c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) |
|
410 | 410 | |
|
411 | 411 | c.default_message = _( |
|
412 | 412 | 'Deleted file %s via RhodeCode Enterprise') % (f_path) |
|
413 | 413 | c.f_path = f_path |
|
414 | 414 | node_path = f_path |
|
415 | 415 | author = c.rhodecode_user.full_contact |
|
416 | 416 | message = request.POST.get('message') or c.default_message |
|
417 | 417 | try: |
|
418 | 418 | nodes = { |
|
419 | 419 | node_path: { |
|
420 | 420 | 'content': '' |
|
421 | 421 | } |
|
422 | 422 | } |
|
423 | 423 | self.scm_model.delete_nodes( |
|
424 | 424 | user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo, |
|
425 | 425 | message=message, |
|
426 | 426 | nodes=nodes, |
|
427 | 427 | parent_commit=c.commit, |
|
428 | 428 | author=author, |
|
429 | 429 | ) |
|
430 | 430 | |
|
431 | 431 | h.flash(_('Successfully deleted file %s') % f_path, |
|
432 | 432 | category='success') |
|
433 | 433 | except Exception: |
|
434 | 434 | msg = _('Error occurred during commit') |
|
435 | 435 | log.exception(msg) |
|
436 | 436 | h.flash(msg, category='error') |
|
437 | 437 | return redirect(url('changeset_home', |
|
438 | 438 | repo_name=c.repo_name, revision='tip')) |
|
439 | 439 | |
|
440 | 440 | @LoginRequired() |
|
441 | 441 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
442 | 442 | def delete_home(self, repo_name, revision, f_path): |
|
443 | 443 | commit_id = revision |
|
444 | 444 | |
|
445 | 445 | repo = c.rhodecode_db_repo |
|
446 | 446 | if repo.enable_locking and repo.locked[0]: |
|
447 | 447 | h.flash(_('This repository has been locked by %s on %s') |
|
448 | 448 | % (h.person_by_id(repo.locked[0]), |
|
449 | 449 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
450 | 450 | 'warning') |
|
451 | 451 | return redirect(h.url('files_home', |
|
452 | 452 | repo_name=repo_name, revision='tip')) |
|
453 | 453 | |
|
454 | 454 | if not self._is_valid_head(commit_id, repo.scm_instance()): |
|
455 | 455 | h.flash(_('You can only delete files with revision ' |
|
456 | 456 | 'being a valid branch '), category='warning') |
|
457 | 457 | return redirect(h.url('files_home', |
|
458 | 458 | repo_name=repo_name, revision='tip', |
|
459 | 459 | f_path=f_path)) |
|
460 | 460 | |
|
461 | 461 | c.commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
462 | 462 | c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) |
|
463 | 463 | |
|
464 | 464 | c.default_message = _( |
|
465 | 465 | 'Deleted file %s via RhodeCode Enterprise') % (f_path) |
|
466 | 466 | c.f_path = f_path |
|
467 | 467 | |
|
468 | 468 | return render('files/files_delete.html') |
|
469 | 469 | |
|
470 | 470 | @CSRFRequired() |
|
471 | 471 | @LoginRequired() |
|
472 | 472 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
473 | 473 | def edit(self, repo_name, revision, f_path): |
|
474 | 474 | commit_id = revision |
|
475 | 475 | |
|
476 | 476 | repo = c.rhodecode_db_repo |
|
477 | 477 | if repo.enable_locking and repo.locked[0]: |
|
478 | 478 | h.flash(_('This repository has been locked by %s on %s') |
|
479 | 479 | % (h.person_by_id(repo.locked[0]), |
|
480 | 480 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
481 | 481 | 'warning') |
|
482 | 482 | return redirect(h.url('files_home', |
|
483 | 483 | repo_name=repo_name, revision='tip')) |
|
484 | 484 | |
|
485 | 485 | if not self._is_valid_head(commit_id, repo.scm_instance()): |
|
486 | 486 | h.flash(_('You can only edit files with revision ' |
|
487 | 487 | 'being a valid branch '), category='warning') |
|
488 | 488 | return redirect(h.url('files_home', |
|
489 | 489 | repo_name=repo_name, revision='tip', |
|
490 | 490 | f_path=f_path)) |
|
491 | 491 | |
|
492 | 492 | c.commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
493 | 493 | c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) |
|
494 | 494 | |
|
495 | 495 | if c.file.is_binary: |
|
496 | 496 | return redirect(url('files_home', repo_name=c.repo_name, |
|
497 | 497 | revision=c.commit.raw_id, f_path=f_path)) |
|
498 | 498 | c.default_message = _( |
|
499 | 499 | 'Edited file %s via RhodeCode Enterprise') % (f_path) |
|
500 | 500 | c.f_path = f_path |
|
501 | 501 | old_content = c.file.content |
|
502 | 502 | sl = old_content.splitlines(1) |
|
503 | 503 | first_line = sl[0] if sl else '' |
|
504 | 504 | |
|
505 | 505 | # modes: 0 - Unix, 1 - Mac, 2 - DOS |
|
506 | 506 | mode = detect_mode(first_line, 0) |
|
507 | 507 | content = convert_line_endings(request.POST.get('content', ''), mode) |
|
508 | 508 | |
|
509 | 509 | message = request.POST.get('message') or c.default_message |
|
510 | 510 | org_f_path = c.file.unicode_path |
|
511 | 511 | filename = request.POST['filename'] |
|
512 | 512 | org_filename = c.file.name |
|
513 | 513 | |
|
514 | 514 | if content == old_content and filename == org_filename: |
|
515 | 515 | h.flash(_('No changes'), category='warning') |
|
516 | 516 | return redirect(url('changeset_home', repo_name=c.repo_name, |
|
517 | 517 | revision='tip')) |
|
518 | 518 | try: |
|
519 | 519 | mapping = { |
|
520 | 520 | org_f_path: { |
|
521 | 521 | 'org_filename': org_f_path, |
|
522 | 522 | 'filename': os.path.join(c.file.dir_path, filename), |
|
523 | 523 | 'content': content, |
|
524 | 524 | 'lexer': '', |
|
525 | 525 | 'op': 'mod', |
|
526 | 526 | } |
|
527 | 527 | } |
|
528 | 528 | |
|
529 | 529 | ScmModel().update_nodes( |
|
530 | 530 | user=c.rhodecode_user.user_id, |
|
531 | 531 | repo=c.rhodecode_db_repo, |
|
532 | 532 | message=message, |
|
533 | 533 | nodes=mapping, |
|
534 | 534 | parent_commit=c.commit, |
|
535 | 535 | ) |
|
536 | 536 | |
|
537 | 537 | h.flash(_('Successfully committed to %s') % f_path, |
|
538 | 538 | category='success') |
|
539 | 539 | except Exception: |
|
540 | 540 | msg = _('Error occurred during commit') |
|
541 | 541 | log.exception(msg) |
|
542 | 542 | h.flash(msg, category='error') |
|
543 | 543 | return redirect(url('changeset_home', |
|
544 | 544 | repo_name=c.repo_name, revision='tip')) |
|
545 | 545 | |
|
546 | 546 | @LoginRequired() |
|
547 | 547 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
548 | 548 | def edit_home(self, repo_name, revision, f_path): |
|
549 | 549 | commit_id = revision |
|
550 | 550 | |
|
551 | 551 | repo = c.rhodecode_db_repo |
|
552 | 552 | if repo.enable_locking and repo.locked[0]: |
|
553 | 553 | h.flash(_('This repository has been locked by %s on %s') |
|
554 | 554 | % (h.person_by_id(repo.locked[0]), |
|
555 | 555 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
556 | 556 | 'warning') |
|
557 | 557 | return redirect(h.url('files_home', |
|
558 | 558 | repo_name=repo_name, revision='tip')) |
|
559 | 559 | |
|
560 | 560 | if not self._is_valid_head(commit_id, repo.scm_instance()): |
|
561 | 561 | h.flash(_('You can only edit files with revision ' |
|
562 | 562 | 'being a valid branch '), category='warning') |
|
563 | 563 | return redirect(h.url('files_home', |
|
564 | 564 | repo_name=repo_name, revision='tip', |
|
565 | 565 | f_path=f_path)) |
|
566 | 566 | |
|
567 | 567 | c.commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
568 | 568 | c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path) |
|
569 | 569 | |
|
570 | 570 | if c.file.is_binary: |
|
571 | 571 | return redirect(url('files_home', repo_name=c.repo_name, |
|
572 | 572 | revision=c.commit.raw_id, f_path=f_path)) |
|
573 | 573 | c.default_message = _( |
|
574 | 574 | 'Edited file %s via RhodeCode Enterprise') % (f_path) |
|
575 | 575 | c.f_path = f_path |
|
576 | 576 | |
|
577 | 577 | return render('files/files_edit.html') |
|
578 | 578 | |
|
579 | 579 | def _is_valid_head(self, commit_id, repo): |
|
580 | 580 | # check if commit is a branch identifier- basically we cannot |
|
581 | 581 | # create multiple heads via file editing |
|
582 | 582 | valid_heads = repo.branches.keys() + repo.branches.values() |
|
583 | 583 | |
|
584 | 584 | if h.is_svn(repo) and not repo.is_empty(): |
|
585 | 585 | # Note: Subversion only has one head, we add it here in case there |
|
586 | 586 | # is no branch matched. |
|
587 | 587 | valid_heads.append(repo.get_commit(commit_idx=-1).raw_id) |
|
588 | 588 | |
|
589 | 589 | # check if commit is a branch name or branch hash |
|
590 | 590 | return commit_id in valid_heads |
|
591 | 591 | |
|
592 | 592 | @CSRFRequired() |
|
593 | 593 | @LoginRequired() |
|
594 | 594 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
595 | 595 | def add(self, repo_name, revision, f_path): |
|
596 | 596 | repo = Repository.get_by_repo_name(repo_name) |
|
597 | 597 | if repo.enable_locking and repo.locked[0]: |
|
598 | 598 | h.flash(_('This repository has been locked by %s on %s') |
|
599 | 599 | % (h.person_by_id(repo.locked[0]), |
|
600 | 600 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
601 | 601 | 'warning') |
|
602 | 602 | return redirect(h.url('files_home', |
|
603 | 603 | repo_name=repo_name, revision='tip')) |
|
604 | 604 | |
|
605 | 605 | r_post = request.POST |
|
606 | 606 | |
|
607 | 607 | c.commit = self.__get_commit_or_redirect( |
|
608 | 608 | revision, repo_name, redirect_after=False) |
|
609 | 609 | if c.commit is None: |
|
610 | 610 | c.commit = EmptyCommit(alias=c.rhodecode_repo.alias) |
|
611 | 611 | c.default_message = (_('Added file via RhodeCode Enterprise')) |
|
612 | 612 | c.f_path = f_path |
|
613 | 613 | unix_mode = 0 |
|
614 | 614 | content = convert_line_endings(r_post.get('content', ''), unix_mode) |
|
615 | 615 | |
|
616 | 616 | message = r_post.get('message') or c.default_message |
|
617 | 617 | filename = r_post.get('filename') |
|
618 | 618 | location = r_post.get('location', '') # dir location |
|
619 | 619 | file_obj = r_post.get('upload_file', None) |
|
620 | 620 | |
|
621 | 621 | if file_obj is not None and hasattr(file_obj, 'filename'): |
|
622 | 622 | filename = file_obj.filename |
|
623 | 623 | content = file_obj.file |
|
624 | 624 | |
|
625 | 625 | if hasattr(content, 'file'): |
|
626 | 626 | # non posix systems store real file under file attr |
|
627 | 627 | content = content.file |
|
628 | 628 | |
|
629 | 629 | # If there's no commit, redirect to repo summary |
|
630 | 630 | if type(c.commit) is EmptyCommit: |
|
631 | 631 | redirect_url = "summary_home" |
|
632 | 632 | else: |
|
633 | 633 | redirect_url = "changeset_home" |
|
634 | 634 | |
|
635 | 635 | if not filename: |
|
636 | 636 | h.flash(_('No filename'), category='warning') |
|
637 | 637 | return redirect(url(redirect_url, repo_name=c.repo_name, |
|
638 | 638 | revision='tip')) |
|
639 | 639 | |
|
640 | 640 | # extract the location from filename, |
|
641 | 641 | # allows using foo/bar.txt syntax to create subdirectories |
|
642 | 642 | subdir_loc = filename.rsplit('/', 1) |
|
643 | 643 | if len(subdir_loc) == 2: |
|
644 | 644 | location = os.path.join(location, subdir_loc[0]) |
|
645 | 645 | |
|
646 | 646 | # strip all crap out of file, just leave the basename |
|
647 | 647 | filename = os.path.basename(filename) |
|
648 | 648 | node_path = os.path.join(location, filename) |
|
649 | 649 | author = c.rhodecode_user.full_contact |
|
650 | 650 | |
|
651 | 651 | try: |
|
652 | 652 | nodes = { |
|
653 | 653 | node_path: { |
|
654 | 654 | 'content': content |
|
655 | 655 | } |
|
656 | 656 | } |
|
657 | 657 | self.scm_model.create_nodes( |
|
658 | 658 | user=c.rhodecode_user.user_id, |
|
659 | 659 | repo=c.rhodecode_db_repo, |
|
660 | 660 | message=message, |
|
661 | 661 | nodes=nodes, |
|
662 | 662 | parent_commit=c.commit, |
|
663 | 663 | author=author, |
|
664 | 664 | ) |
|
665 | 665 | |
|
666 | 666 | h.flash(_('Successfully committed to %s') % node_path, |
|
667 | 667 | category='success') |
|
668 | 668 | except NonRelativePathError as e: |
|
669 | 669 | h.flash(_( |
|
670 | 670 | 'The location specified must be a relative path and must not ' |
|
671 | 671 | 'contain .. in the path'), category='warning') |
|
672 | 672 | return redirect(url('changeset_home', repo_name=c.repo_name, |
|
673 | 673 | revision='tip')) |
|
674 | 674 | except (NodeError, NodeAlreadyExistsError) as e: |
|
675 | 675 | h.flash(_(e), category='error') |
|
676 | 676 | except Exception: |
|
677 | 677 | msg = _('Error occurred during commit') |
|
678 | 678 | log.exception(msg) |
|
679 | 679 | h.flash(msg, category='error') |
|
680 | 680 | return redirect(url('changeset_home', |
|
681 | 681 | repo_name=c.repo_name, revision='tip')) |
|
682 | 682 | |
|
683 | 683 | @LoginRequired() |
|
684 | 684 | @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin') |
|
685 | 685 | def add_home(self, repo_name, revision, f_path): |
|
686 | 686 | |
|
687 | 687 | repo = Repository.get_by_repo_name(repo_name) |
|
688 | 688 | if repo.enable_locking and repo.locked[0]: |
|
689 | 689 | h.flash(_('This repository has been locked by %s on %s') |
|
690 | 690 | % (h.person_by_id(repo.locked[0]), |
|
691 | 691 | h.format_date(h.time_to_datetime(repo.locked[1]))), |
|
692 | 692 | 'warning') |
|
693 | 693 | return redirect(h.url('files_home', |
|
694 | 694 | repo_name=repo_name, revision='tip')) |
|
695 | 695 | |
|
696 | 696 | c.commit = self.__get_commit_or_redirect( |
|
697 | 697 | revision, repo_name, redirect_after=False) |
|
698 | 698 | if c.commit is None: |
|
699 | 699 | c.commit = EmptyCommit(alias=c.rhodecode_repo.alias) |
|
700 | 700 | c.default_message = (_('Added file via RhodeCode Enterprise')) |
|
701 | 701 | c.f_path = f_path |
|
702 | 702 | |
|
703 | 703 | return render('files/files_add.html') |
|
704 | 704 | |
|
705 | 705 | @LoginRequired() |
|
706 | 706 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
707 | 707 | 'repository.admin') |
|
708 | 708 | def archivefile(self, repo_name, fname): |
|
709 | 709 | fileformat = None |
|
710 | 710 | commit_id = None |
|
711 | 711 | ext = None |
|
712 | 712 | subrepos = request.GET.get('subrepos') == 'true' |
|
713 | 713 | |
|
714 | 714 | for a_type, ext_data in settings.ARCHIVE_SPECS.items(): |
|
715 | 715 | archive_spec = fname.split(ext_data[1]) |
|
716 | 716 | if len(archive_spec) == 2 and archive_spec[1] == '': |
|
717 | 717 | fileformat = a_type or ext_data[1] |
|
718 | 718 | commit_id = archive_spec[0] |
|
719 | 719 | ext = ext_data[1] |
|
720 | 720 | |
|
721 | 721 | dbrepo = RepoModel().get_by_repo_name(repo_name) |
|
722 | 722 | if not dbrepo.enable_downloads: |
|
723 | 723 | return _('Downloads disabled') |
|
724 | 724 | |
|
725 | 725 | try: |
|
726 | 726 | commit = c.rhodecode_repo.get_commit(commit_id) |
|
727 | 727 | content_type = settings.ARCHIVE_SPECS[fileformat][0] |
|
728 | 728 | except CommitDoesNotExistError: |
|
729 | 729 | return _('Unknown revision %s') % commit_id |
|
730 | 730 | except EmptyRepositoryError: |
|
731 | 731 | return _('Empty repository') |
|
732 | 732 | except KeyError: |
|
733 | 733 | return _('Unknown archive type') |
|
734 | 734 | |
|
735 | 735 | # archive cache |
|
736 | 736 | from rhodecode import CONFIG |
|
737 | 737 | |
|
738 | 738 | archive_name = '%s-%s%s%s' % ( |
|
739 | 739 | safe_str(repo_name.replace('/', '_')), |
|
740 | 740 | '-sub' if subrepos else '', |
|
741 | 741 | safe_str(commit.short_id), ext) |
|
742 | 742 | |
|
743 | 743 | use_cached_archive = False |
|
744 | 744 | archive_cache_enabled = CONFIG.get( |
|
745 | 745 | 'archive_cache_dir') and not request.GET.get('no_cache') |
|
746 | 746 | |
|
747 | 747 | if archive_cache_enabled: |
|
748 | 748 | # check if we it's ok to write |
|
749 | 749 | if not os.path.isdir(CONFIG['archive_cache_dir']): |
|
750 | 750 | os.makedirs(CONFIG['archive_cache_dir']) |
|
751 | 751 | cached_archive_path = os.path.join( |
|
752 | 752 | CONFIG['archive_cache_dir'], archive_name) |
|
753 | 753 | if os.path.isfile(cached_archive_path): |
|
754 | 754 | log.debug('Found cached archive in %s', cached_archive_path) |
|
755 | 755 | fd, archive = None, cached_archive_path |
|
756 | 756 | use_cached_archive = True |
|
757 | 757 | else: |
|
758 | 758 | log.debug('Archive %s is not yet cached', archive_name) |
|
759 | 759 | |
|
760 | 760 | if not use_cached_archive: |
|
761 | 761 | # generate new archive |
|
762 | 762 | fd, archive = tempfile.mkstemp() |
|
763 | 763 | log.debug('Creating new temp archive in %s' % (archive,)) |
|
764 | 764 | try: |
|
765 | 765 | commit.archive_repo(archive, kind=fileformat, subrepos=subrepos) |
|
766 | 766 | except ImproperArchiveTypeError: |
|
767 | 767 | return _('Unknown archive type') |
|
768 | 768 | if archive_cache_enabled: |
|
769 | 769 | # if we generated the archive and we have cache enabled |
|
770 | 770 | # let's use this for future |
|
771 | 771 | log.debug('Storing new archive in %s' % (cached_archive_path,)) |
|
772 | 772 | shutil.move(archive, cached_archive_path) |
|
773 | 773 | archive = cached_archive_path |
|
774 | 774 | |
|
775 | 775 | def get_chunked_archive(archive): |
|
776 | 776 | with open(archive, 'rb') as stream: |
|
777 | 777 | while True: |
|
778 | 778 | data = stream.read(16 * 1024) |
|
779 | 779 | if not data: |
|
780 | 780 | if fd: # fd means we used temporary file |
|
781 | 781 | os.close(fd) |
|
782 | 782 | if not archive_cache_enabled: |
|
783 | 783 | log.debug('Destroying temp archive %s', archive) |
|
784 | 784 | os.remove(archive) |
|
785 | 785 | break |
|
786 | 786 | yield data |
|
787 | 787 | |
|
788 | 788 | # store download action |
|
789 | 789 | action_logger(user=c.rhodecode_user, |
|
790 | 790 | action='user_downloaded_archive:%s' % archive_name, |
|
791 | 791 | repo=repo_name, ipaddr=self.ip_addr, commit=True) |
|
792 | 792 | response.content_disposition = str( |
|
793 | 793 | 'attachment; filename=%s' % archive_name) |
|
794 | 794 | response.content_type = str(content_type) |
|
795 | 795 | |
|
796 | 796 | return get_chunked_archive(archive) |
|
797 | 797 | |
|
798 | 798 | @LoginRequired() |
|
799 | 799 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
800 | 800 | 'repository.admin') |
|
801 | 801 | def diff(self, repo_name, f_path): |
|
802 | ignore_whitespace = request.GET.get('ignorews') == '1' | |
|
803 |
|
|
|
802 | ||
|
803 | c.action = request.GET.get('diff') | |
|
804 | 804 | diff1 = request.GET.get('diff1', '') |
|
805 | diff2 = request.GET.get('diff2', '') | |
|
805 | 806 | |
|
806 | 807 | path1, diff1 = parse_path_ref(diff1, default_path=f_path) |
|
807 | 808 | |
|
808 | diff2 = request.GET.get('diff2', '') | |
|
809 |
|
|
|
810 | c.no_changes = diff1 == diff2 | |
|
811 | c.f_path = f_path | |
|
812 | c.big_diff = False | |
|
813 | c.ignorews_url = _ignorews_url | |
|
814 | c.context_url = _context_url | |
|
815 | c.changes = OrderedDict() | |
|
816 | c.changes[diff2] = [] | |
|
809 | ignore_whitespace = str2bool(request.GET.get('ignorews')) | |
|
810 | line_context = request.GET.get('context', 3) | |
|
817 | 811 | |
|
818 | 812 | if not any((diff1, diff2)): |
|
819 | 813 | h.flash( |
|
820 | 814 | 'Need query parameter "diff1" or "diff2" to generate a diff.', |
|
821 | 815 | category='error') |
|
822 | 816 | raise HTTPBadRequest() |
|
823 | 817 | |
|
824 | # special case if we want a show commit_id only, it's impl here | |
|
825 | # to reduce JS and callbacks | |
|
826 | ||
|
827 | if request.GET.get('show_rev') and diff1: | |
|
828 | if str2bool(request.GET.get('annotate', 'False')): | |
|
829 | _url = url('files_annotate_home', repo_name=c.repo_name, | |
|
830 | revision=diff1, f_path=path1) | |
|
831 | else: | |
|
832 | _url = url('files_home', repo_name=c.repo_name, | |
|
833 |
|
|
|
834 | ||
|
835 | return redirect(_url) | |
|
818 | if c.action not in ['download', 'raw']: | |
|
819 | # redirect to new view if we render diff | |
|
820 | return redirect( | |
|
821 | url('compare_url', repo_name=repo_name, | |
|
822 | source_ref_type='rev', | |
|
823 | source_ref=diff1, | |
|
824 | target_repo=c.repo_name, | |
|
825 | target_ref_type='rev', | |
|
826 | target_ref=diff2, | |
|
827 | f_path=f_path)) | |
|
836 | 828 | |
|
837 | 829 | try: |
|
838 | 830 | node1 = self._get_file_node(diff1, path1) |
|
839 | 831 | node2 = self._get_file_node(diff2, f_path) |
|
840 | 832 | except (RepositoryError, NodeError): |
|
841 | 833 | log.exception("Exception while trying to get node from repository") |
|
842 | 834 | return redirect(url( |
|
843 | 835 | 'files_home', repo_name=c.repo_name, f_path=f_path)) |
|
844 | 836 | |
|
845 | 837 | if all(isinstance(node.commit, EmptyCommit) |
|
846 | 838 | for node in (node1, node2)): |
|
847 | 839 | raise HTTPNotFound |
|
848 | 840 | |
|
849 | 841 | c.commit_1 = node1.commit |
|
850 | 842 | c.commit_2 = node2.commit |
|
851 | 843 | |
|
852 | 844 | if c.action == 'download': |
|
853 | 845 | _diff = diffs.get_gitdiff(node1, node2, |
|
854 | 846 | ignore_whitespace=ignore_whitespace, |
|
855 | 847 | context=line_context) |
|
856 | 848 | diff = diffs.DiffProcessor(_diff, format='gitdiff') |
|
857 | 849 | |
|
858 | 850 | diff_name = '%s_vs_%s.diff' % (diff1, diff2) |
|
859 | 851 | response.content_type = 'text/plain' |
|
860 | 852 | response.content_disposition = ( |
|
861 | 853 | 'attachment; filename=%s' % (diff_name,) |
|
862 | 854 | ) |
|
863 | 855 | charset = self._get_default_encoding() |
|
864 | 856 | if charset: |
|
865 | 857 | response.charset = charset |
|
866 | 858 | return diff.as_raw() |
|
867 | 859 | |
|
868 | 860 | elif c.action == 'raw': |
|
869 | 861 | _diff = diffs.get_gitdiff(node1, node2, |
|
870 | 862 | ignore_whitespace=ignore_whitespace, |
|
871 | 863 | context=line_context) |
|
872 | 864 | diff = diffs.DiffProcessor(_diff, format='gitdiff') |
|
873 | 865 | response.content_type = 'text/plain' |
|
874 | 866 | charset = self._get_default_encoding() |
|
875 | 867 | if charset: |
|
876 | 868 | response.charset = charset |
|
877 | 869 | return diff.as_raw() |
|
878 | 870 | |
|
879 | 871 | else: |
|
880 | fid = h.FID(diff2, node2.path) | |
|
881 | line_context_lcl = get_line_ctx(fid, request.GET) | |
|
882 | ign_whitespace_lcl = get_ignore_ws(fid, request.GET) | |
|
883 | ||
|
884 | __, commit1, commit2, diff, st, data = diffs.wrapped_diff( | |
|
885 | filenode_old=node1, | |
|
886 | filenode_new=node2, | |
|
887 | diff_limit=self.cut_off_limit_diff, | |
|
888 | file_limit=self.cut_off_limit_file, | |
|
889 | show_full_diff=request.GET.get('fulldiff'), | |
|
890 | ignore_whitespace=ign_whitespace_lcl, | |
|
891 | line_context=line_context_lcl,) | |
|
892 | ||
|
893 | c.lines_added = data['stats']['added'] if data else 0 | |
|
894 | c.lines_deleted = data['stats']['deleted'] if data else 0 | |
|
895 | c.files = [data] | |
|
896 | c.commit_ranges = [c.commit_1, c.commit_2] | |
|
897 | c.ancestor = None | |
|
898 | c.statuses = [] | |
|
899 | c.target_repo = c.rhodecode_db_repo | |
|
900 | c.filename1 = node1.path | |
|
901 | c.filename = node2.path | |
|
902 | c.binary_file = node1.is_binary or node2.is_binary | |
|
903 | operation = data['operation'] if data else '' | |
|
904 | ||
|
905 | commit_changes = { | |
|
906 | # TODO: it's passing the old file to the diff to keep the | |
|
907 | # standard but this is not being used for this template, | |
|
908 | # but might need both files in the future or a more standard | |
|
909 | # way to work with that | |
|
910 | 'fid': [commit1, commit2, operation, | |
|
911 | c.filename, diff, st, data] | |
|
912 | } | |
|
913 | ||
|
914 | c.changes = commit_changes | |
|
915 | ||
|
916 | return render('files/file_diff.html') | |
|
872 | return redirect( | |
|
873 | url('compare_url', repo_name=repo_name, | |
|
874 | source_ref_type='rev', | |
|
875 | source_ref=diff1, | |
|
876 | target_repo=c.repo_name, | |
|
877 | target_ref_type='rev', | |
|
878 | target_ref=diff2, | |
|
879 | f_path=f_path)) | |
|
917 | 880 | |
|
918 | 881 | @LoginRequired() |
|
919 | 882 | @HasRepoPermissionAnyDecorator('repository.read', 'repository.write', |
|
920 | 883 | 'repository.admin') |
|
921 | 884 | def diff_2way(self, repo_name, f_path): |
|
885 | """ | |
|
886 | Kept only to make OLD links work | |
|
887 | """ | |
|
922 | 888 | diff1 = request.GET.get('diff1', '') |
|
923 | 889 | diff2 = request.GET.get('diff2', '') |
|
924 | 890 | |
|
925 | nodes = [] | |
|
926 | unknown_commits = [] | |
|
927 | for commit in [diff1, diff2]: | |
|
928 |
|
|
|
929 | nodes.append(self._get_file_node(commit, f_path)) | |
|
930 | except (RepositoryError, NodeError): | |
|
931 | log.exception('%(commit)s does not exist' % {'commit': commit}) | |
|
932 | unknown_commits.append(commit) | |
|
933 | h.flash(h.literal( | |
|
934 | _('Commit %(commit)s does not exist.') % {'commit': commit} | |
|
935 | ), category='error') | |
|
936 | ||
|
937 | if unknown_commits: | |
|
938 | return redirect(url('files_home', repo_name=c.repo_name, | |
|
939 | f_path=f_path)) | |
|
940 | ||
|
941 | if all(isinstance(node.commit, EmptyCommit) for node in nodes): | |
|
942 | raise HTTPNotFound | |
|
943 | ||
|
944 | node1, node2 = nodes | |
|
891 | if not any((diff1, diff2)): | |
|
892 | h.flash( | |
|
893 | 'Need query parameter "diff1" or "diff2" to generate a diff.', | |
|
894 | category='error') | |
|
895 | raise HTTPBadRequest() | |
|
945 | 896 | |
|
946 | f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False) | |
|
947 | diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff') | |
|
948 | diff_data = diff_processor.prepare() | |
|
949 | ||
|
950 | if not diff_data or diff_data[0]['raw_diff'] == '': | |
|
951 | h.flash(h.literal(_('%(file_path)s has not changed ' | |
|
952 | 'between %(commit_1)s and %(commit_2)s.') % { | |
|
953 |
|
|
|
954 | 'commit_1': node1.commit.id, | |
|
955 | 'commit_2': node2.commit.id | |
|
956 | }), category='error') | |
|
957 | return redirect(url('files_home', repo_name=c.repo_name, | |
|
958 | f_path=f_path)) | |
|
959 | ||
|
960 | c.diff_data = diff_data[0] | |
|
961 | c.FID = h.FID(diff2, node2.path) | |
|
962 | # cleanup some unneeded data | |
|
963 | del c.diff_data['raw_diff'] | |
|
964 | del c.diff_data['chunks'] | |
|
965 | ||
|
966 | c.node1 = node1 | |
|
967 | c.commit_1 = node1.commit | |
|
968 | c.node2 = node2 | |
|
969 | c.commit_2 = node2.commit | |
|
970 | ||
|
971 | return render('files/diff_2way.html') | |
|
897 | return redirect( | |
|
898 | url('compare_url', repo_name=repo_name, | |
|
899 | source_ref_type='rev', | |
|
900 | source_ref=diff1, | |
|
901 | target_repo=c.repo_name, | |
|
902 | target_ref_type='rev', | |
|
903 | target_ref=diff2, | |
|
904 | f_path=f_path, | |
|
905 | diffmode='sideside')) | |
|
972 | 906 | |
|
973 | 907 | def _get_file_node(self, commit_id, f_path): |
|
974 | 908 | if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]: |
|
975 | 909 | commit = c.rhodecode_repo.get_commit(commit_id=commit_id) |
|
976 | 910 | try: |
|
977 | 911 | node = commit.get_node(f_path) |
|
978 | 912 | if node.is_dir(): |
|
979 | 913 | raise NodeError('%s path is a %s not a file' |
|
980 | 914 | % (node, type(node))) |
|
981 | 915 | except NodeDoesNotExistError: |
|
982 | 916 | commit = EmptyCommit( |
|
983 | 917 | commit_id=commit_id, |
|
984 | 918 | idx=commit.idx, |
|
985 | 919 | repo=commit.repository, |
|
986 | 920 | alias=commit.repository.alias, |
|
987 | 921 | message=commit.message, |
|
988 | 922 | author=commit.author, |
|
989 | 923 | date=commit.date) |
|
990 | 924 | node = FileNode(f_path, '', commit=commit) |
|
991 | 925 | else: |
|
992 | 926 | commit = EmptyCommit( |
|
993 | 927 | repo=c.rhodecode_repo, |
|
994 | 928 | alias=c.rhodecode_repo.alias) |
|
995 | 929 | node = FileNode(f_path, '', commit=commit) |
|
996 | 930 | return node |
|
997 | 931 | |
|
998 | 932 | def _get_node_history(self, commit, f_path, commits=None): |
|
999 | 933 | """ |
|
1000 | 934 | get commit history for given node |
|
1001 | 935 | |
|
1002 | 936 | :param commit: commit to calculate history |
|
1003 | 937 | :param f_path: path for node to calculate history for |
|
1004 | 938 | :param commits: if passed don't calculate history and take |
|
1005 | 939 | commits defined in this list |
|
1006 | 940 | """ |
|
1007 | 941 | # calculate history based on tip |
|
1008 | 942 | tip = c.rhodecode_repo.get_commit() |
|
1009 | 943 | if commits is None: |
|
1010 | 944 | pre_load = ["author", "branch"] |
|
1011 | 945 | try: |
|
1012 | 946 | commits = tip.get_file_history(f_path, pre_load=pre_load) |
|
1013 | 947 | except (NodeDoesNotExistError, CommitError): |
|
1014 | 948 | # this node is not present at tip! |
|
1015 | 949 | commits = commit.get_file_history(f_path, pre_load=pre_load) |
|
1016 | 950 | |
|
1017 | 951 | history = [] |
|
1018 | 952 | commits_group = ([], _("Changesets")) |
|
1019 | 953 | for commit in commits: |
|
1020 | 954 | branch = ' (%s)' % commit.branch if commit.branch else '' |
|
1021 | 955 | n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch) |
|
1022 | 956 | commits_group[0].append((commit.raw_id, n_desc,)) |
|
1023 | 957 | history.append(commits_group) |
|
1024 | 958 | |
|
1025 | 959 | symbolic_reference = self._symbolic_reference |
|
1026 | 960 | |
|
1027 | 961 | if c.rhodecode_repo.alias == 'svn': |
|
1028 | 962 | adjusted_f_path = self._adjust_file_path_for_svn( |
|
1029 | 963 | f_path, c.rhodecode_repo) |
|
1030 | 964 | if adjusted_f_path != f_path: |
|
1031 | 965 | log.debug( |
|
1032 | 966 | 'Recognized svn tag or branch in file "%s", using svn ' |
|
1033 | 967 | 'specific symbolic references', f_path) |
|
1034 | 968 | f_path = adjusted_f_path |
|
1035 | 969 | symbolic_reference = self._symbolic_reference_svn |
|
1036 | 970 | |
|
1037 | 971 | branches = self._create_references( |
|
1038 | 972 | c.rhodecode_repo.branches, symbolic_reference, f_path) |
|
1039 | 973 | branches_group = (branches, _("Branches")) |
|
1040 | 974 | |
|
1041 | 975 | tags = self._create_references( |
|
1042 | 976 | c.rhodecode_repo.tags, symbolic_reference, f_path) |
|
1043 | 977 | tags_group = (tags, _("Tags")) |
|
1044 | 978 | |
|
1045 | 979 | history.append(branches_group) |
|
1046 | 980 | history.append(tags_group) |
|
1047 | 981 | |
|
1048 | 982 | return history, commits |
|
1049 | 983 | |
|
1050 | 984 | def _adjust_file_path_for_svn(self, f_path, repo): |
|
1051 | 985 | """ |
|
1052 | 986 | Computes the relative path of `f_path`. |
|
1053 | 987 | |
|
1054 | 988 | This is mainly based on prefix matching of the recognized tags and |
|
1055 | 989 | branches in the underlying repository. |
|
1056 | 990 | """ |
|
1057 | 991 | tags_and_branches = itertools.chain( |
|
1058 | 992 | repo.branches.iterkeys(), |
|
1059 | 993 | repo.tags.iterkeys()) |
|
1060 | 994 | tags_and_branches = sorted(tags_and_branches, key=len, reverse=True) |
|
1061 | 995 | |
|
1062 | 996 | for name in tags_and_branches: |
|
1063 | 997 | if f_path.startswith(name + '/'): |
|
1064 | 998 | f_path = vcspath.relpath(f_path, name) |
|
1065 | 999 | break |
|
1066 | 1000 | return f_path |
|
1067 | 1001 | |
|
1068 | 1002 | def _create_references( |
|
1069 | 1003 | self, branches_or_tags, symbolic_reference, f_path): |
|
1070 | 1004 | items = [] |
|
1071 | 1005 | for name, commit_id in branches_or_tags.items(): |
|
1072 | 1006 | sym_ref = symbolic_reference(commit_id, name, f_path) |
|
1073 | 1007 | items.append((sym_ref, name)) |
|
1074 | 1008 | return items |
|
1075 | 1009 | |
|
1076 | 1010 | def _symbolic_reference(self, commit_id, name, f_path): |
|
1077 | 1011 | return commit_id |
|
1078 | 1012 | |
|
1079 | 1013 | def _symbolic_reference_svn(self, commit_id, name, f_path): |
|
1080 | 1014 | new_f_path = vcspath.join(name, f_path) |
|
1081 | 1015 | return u'%s@%s' % (new_f_path, commit_id) |
|
1082 | 1016 | |
|
1083 | 1017 | @LoginRequired() |
|
1084 | 1018 | @XHRRequired() |
|
1085 | 1019 | @HasRepoPermissionAnyDecorator( |
|
1086 | 1020 | 'repository.read', 'repository.write', 'repository.admin') |
|
1087 | 1021 | @jsonify |
|
1088 | 1022 | def nodelist(self, repo_name, revision, f_path): |
|
1089 | 1023 | commit = self.__get_commit_or_redirect(revision, repo_name) |
|
1090 | 1024 | |
|
1091 | 1025 | metadata = self._get_nodelist_at_commit( |
|
1092 | 1026 | repo_name, commit.raw_id, f_path) |
|
1093 | 1027 | return {'nodes': metadata} |
|
1094 | 1028 | |
|
1095 | 1029 | @LoginRequired() |
|
1096 | 1030 | @XHRRequired() |
|
1097 | 1031 | @HasRepoPermissionAnyDecorator( |
|
1098 | 1032 | 'repository.read', 'repository.write', 'repository.admin') |
|
1099 | 1033 | def nodetree_full(self, repo_name, commit_id, f_path): |
|
1100 | 1034 | """ |
|
1101 | 1035 | Returns rendered html of file tree that contains commit date, |
|
1102 | 1036 | author, revision for the specified combination of |
|
1103 | 1037 | repo, commit_id and file path |
|
1104 | 1038 | |
|
1105 | 1039 | :param repo_name: name of the repository |
|
1106 | 1040 | :param commit_id: commit_id of file tree |
|
1107 | 1041 | :param f_path: file path of the requested directory |
|
1108 | 1042 | """ |
|
1109 | 1043 | |
|
1110 | 1044 | commit = self.__get_commit_or_redirect(commit_id, repo_name) |
|
1111 | 1045 | try: |
|
1112 | 1046 | dir_node = commit.get_node(f_path) |
|
1113 | 1047 | except RepositoryError as e: |
|
1114 | 1048 | return 'error {}'.format(safe_str(e)) |
|
1115 | 1049 | |
|
1116 | 1050 | if dir_node.is_file(): |
|
1117 | 1051 | return '' |
|
1118 | 1052 | |
|
1119 | 1053 | c.file = dir_node |
|
1120 | 1054 | c.commit = commit |
|
1121 | 1055 | |
|
1122 | 1056 | # using force=True here, make a little trick. We flush the cache and |
|
1123 | 1057 | # compute it using the same key as without full_load, so the fully |
|
1124 | 1058 | # loaded cached tree is now returned instead of partial |
|
1125 | 1059 | return self._get_tree_at_commit( |
|
1126 | 1060 | repo_name, commit.raw_id, dir_node.path, full_load=True, |
|
1127 | 1061 | force=True) |
@@ -1,106 +1,107 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2010-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | """ |
|
22 | 22 | Utilities to be shared by multiple controllers. |
|
23 | 23 | |
|
24 | 24 | Should only contain utilities to be shared in the controller layer. |
|
25 | 25 | """ |
|
26 | 26 | |
|
27 | 27 | from rhodecode.lib import helpers as h |
|
28 | 28 | from rhodecode.lib.vcs.exceptions import RepositoryError |
|
29 | 29 | |
|
30 | ||
|
30 | 31 | def parse_path_ref(ref, default_path=None): |
|
31 | 32 | """ |
|
32 | 33 | Parse out a path and reference combination and return both parts of it. |
|
33 | 34 | |
|
34 | 35 | This is used to allow support of path based comparisons for Subversion |
|
35 | 36 | as an iterim solution in parameter handling. |
|
36 | 37 | """ |
|
37 | 38 | if '@' in ref: |
|
38 | 39 | return ref.rsplit('@', 1) |
|
39 | 40 | else: |
|
40 | 41 | return default_path, ref |
|
41 | 42 | |
|
42 | 43 | |
|
43 | 44 | def get_format_ref_id(repo): |
|
44 | 45 | """Returns a `repo` specific reference formatter function""" |
|
45 | 46 | if h.is_svn(repo): |
|
46 | 47 | return _format_ref_id_svn |
|
47 | 48 | else: |
|
48 | 49 | return _format_ref_id |
|
49 | 50 | |
|
50 | 51 | |
|
51 | 52 | def _format_ref_id(name, raw_id): |
|
52 | 53 | """Default formatting of a given reference `name`""" |
|
53 | 54 | return name |
|
54 | 55 | |
|
55 | 56 | |
|
56 | 57 | def _format_ref_id_svn(name, raw_id): |
|
57 | 58 | """Special way of formatting a reference for Subversion including path""" |
|
58 | 59 | return '%s@%s' % (name, raw_id) |
|
59 | 60 | |
|
60 | 61 | |
|
61 | 62 | def get_commit_from_ref_name(repo, ref_name, ref_type=None): |
|
62 | 63 | """ |
|
63 | 64 | Gets the commit for a `ref_name` taking into account `ref_type`. |
|
64 | 65 | Needed in case a bookmark / tag share the same name. |
|
65 | 66 | |
|
66 | 67 | :param repo: the repo instance |
|
67 | 68 | :param ref_name: the name of the ref to get |
|
68 | 69 | :param ref_type: optional, used to disambiguate colliding refs |
|
69 | 70 | """ |
|
70 | 71 | repo_scm = repo.scm_instance() |
|
71 | 72 | ref_type_mapping = { |
|
72 | 73 | 'book': repo_scm.bookmarks, |
|
73 | 74 | 'bookmark': repo_scm.bookmarks, |
|
74 | 75 | 'tag': repo_scm.tags, |
|
75 | 76 | 'branch': repo_scm.branches, |
|
76 | 77 | } |
|
77 | 78 | |
|
78 | 79 | commit_id = ref_name |
|
79 | if repo_scm.alias != 'svn': # pass svn refs straight to backend until | |
|
80 | # the branch issue with svn is fixed | |
|
80 | if repo_scm.alias != 'svn': # pass svn refs straight to backend until | |
|
81 | # the branch issue with svn is fixed | |
|
81 | 82 | if ref_type and ref_type in ref_type_mapping: |
|
82 | 83 | try: |
|
83 | 84 | commit_id = ref_type_mapping[ref_type][ref_name] |
|
84 | 85 | except KeyError: |
|
85 | 86 | raise RepositoryError( |
|
86 | 87 | '%s "%s" does not exist' % (ref_type, ref_name)) |
|
87 | 88 | |
|
88 | 89 | return repo_scm.get_commit(commit_id) |
|
89 | 90 | |
|
90 | 91 | |
|
91 | 92 | def reviewer_as_json(user, reasons): |
|
92 | 93 | """ |
|
93 | 94 | Returns json struct of a reviewer for frontend |
|
94 | 95 | |
|
95 | 96 | :param user: the reviewer |
|
96 | 97 | :param reasons: list of strings of why they are reviewers |
|
97 | 98 | """ |
|
98 | 99 | |
|
99 | 100 | return { |
|
100 | 101 | 'user_id': user.user_id, |
|
101 | 102 | 'reasons': reasons, |
|
102 | 103 | 'username': user.username, |
|
103 | 104 | 'firstname': user.firstname, |
|
104 | 105 | 'lastname': user.lastname, |
|
105 | 106 | 'gravatar_link': h.gravatar_url(user.email, 14), |
|
106 | 107 | } |
@@ -1,1576 +1,1587 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2014-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | """ |
|
22 | 22 | Base module for all VCS systems |
|
23 | 23 | """ |
|
24 | 24 | |
|
25 | 25 | import collections |
|
26 | 26 | import datetime |
|
27 | 27 | import itertools |
|
28 | 28 | import logging |
|
29 | 29 | import os |
|
30 | 30 | import time |
|
31 | 31 | import warnings |
|
32 | 32 | |
|
33 | 33 | from zope.cachedescriptors.property import Lazy as LazyProperty |
|
34 | 34 | |
|
35 | 35 | from rhodecode.lib.utils2 import safe_str, safe_unicode |
|
36 | 36 | from rhodecode.lib.vcs import connection |
|
37 | 37 | from rhodecode.lib.vcs.utils import author_name, author_email |
|
38 | 38 | from rhodecode.lib.vcs.conf import settings |
|
39 | 39 | from rhodecode.lib.vcs.exceptions import ( |
|
40 | 40 | CommitError, EmptyRepositoryError, NodeAlreadyAddedError, |
|
41 | 41 | NodeAlreadyChangedError, NodeAlreadyExistsError, NodeAlreadyRemovedError, |
|
42 | 42 | NodeDoesNotExistError, NodeNotChangedError, VCSError, |
|
43 | 43 | ImproperArchiveTypeError, BranchDoesNotExistError, CommitDoesNotExistError, |
|
44 | 44 | RepositoryError) |
|
45 | 45 | |
|
46 | 46 | |
|
47 | 47 | log = logging.getLogger(__name__) |
|
48 | 48 | |
|
49 | 49 | |
|
50 | 50 | FILEMODE_DEFAULT = 0100644 |
|
51 | 51 | FILEMODE_EXECUTABLE = 0100755 |
|
52 | 52 | |
|
53 | 53 | Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id')) |
|
54 | 54 | MergeResponse = collections.namedtuple( |
|
55 | 55 | 'MergeResponse', |
|
56 | 56 | ('possible', 'executed', 'merge_ref', 'failure_reason')) |
|
57 | 57 | |
|
58 | 58 | |
|
59 | 59 | class MergeFailureReason(object): |
|
60 | 60 | """ |
|
61 | 61 | Enumeration with all the reasons why the server side merge could fail. |
|
62 | 62 | |
|
63 | 63 | DO NOT change the number of the reasons, as they may be stored in the |
|
64 | 64 | database. |
|
65 | 65 | |
|
66 | 66 | Changing the name of a reason is acceptable and encouraged to deprecate old |
|
67 | 67 | reasons. |
|
68 | 68 | """ |
|
69 | 69 | |
|
70 | 70 | # Everything went well. |
|
71 | 71 | NONE = 0 |
|
72 | 72 | |
|
73 | 73 | # An unexpected exception was raised. Check the logs for more details. |
|
74 | 74 | UNKNOWN = 1 |
|
75 | 75 | |
|
76 | 76 | # The merge was not successful, there are conflicts. |
|
77 | 77 | MERGE_FAILED = 2 |
|
78 | 78 | |
|
79 | 79 | # The merge succeeded but we could not push it to the target repository. |
|
80 | 80 | PUSH_FAILED = 3 |
|
81 | 81 | |
|
82 | 82 | # The specified target is not a head in the target repository. |
|
83 | 83 | TARGET_IS_NOT_HEAD = 4 |
|
84 | 84 | |
|
85 | 85 | # The source repository contains more branches than the target. Pushing |
|
86 | 86 | # the merge will create additional branches in the target. |
|
87 | 87 | HG_SOURCE_HAS_MORE_BRANCHES = 5 |
|
88 | 88 | |
|
89 | 89 | # The target reference has multiple heads. That does not allow to correctly |
|
90 | 90 | # identify the target location. This could only happen for mercurial |
|
91 | 91 | # branches. |
|
92 | 92 | HG_TARGET_HAS_MULTIPLE_HEADS = 6 |
|
93 | 93 | |
|
94 | 94 | # The target repository is locked |
|
95 | 95 | TARGET_IS_LOCKED = 7 |
|
96 | 96 | |
|
97 | 97 | # Deprecated, use MISSING_TARGET_REF or MISSING_SOURCE_REF instead. |
|
98 | 98 | # A involved commit could not be found. |
|
99 | 99 | _DEPRECATED_MISSING_COMMIT = 8 |
|
100 | 100 | |
|
101 | 101 | # The target repo reference is missing. |
|
102 | 102 | MISSING_TARGET_REF = 9 |
|
103 | 103 | |
|
104 | 104 | # The source repo reference is missing. |
|
105 | 105 | MISSING_SOURCE_REF = 10 |
|
106 | 106 | |
|
107 | 107 | # The merge was not successful, there are conflicts related to sub |
|
108 | 108 | # repositories. |
|
109 | 109 | SUBREPO_MERGE_FAILED = 11 |
|
110 | 110 | |
|
111 | 111 | |
|
112 | 112 | class UpdateFailureReason(object): |
|
113 | 113 | """ |
|
114 | 114 | Enumeration with all the reasons why the pull request update could fail. |
|
115 | 115 | |
|
116 | 116 | DO NOT change the number of the reasons, as they may be stored in the |
|
117 | 117 | database. |
|
118 | 118 | |
|
119 | 119 | Changing the name of a reason is acceptable and encouraged to deprecate old |
|
120 | 120 | reasons. |
|
121 | 121 | """ |
|
122 | 122 | |
|
123 | 123 | # Everything went well. |
|
124 | 124 | NONE = 0 |
|
125 | 125 | |
|
126 | 126 | # An unexpected exception was raised. Check the logs for more details. |
|
127 | 127 | UNKNOWN = 1 |
|
128 | 128 | |
|
129 | 129 | # The pull request is up to date. |
|
130 | 130 | NO_CHANGE = 2 |
|
131 | 131 | |
|
132 | 132 | # The pull request has a reference type that is not supported for update. |
|
133 | 133 | WRONG_REF_TPYE = 3 |
|
134 | 134 | |
|
135 | 135 | # Update failed because the target reference is missing. |
|
136 | 136 | MISSING_TARGET_REF = 4 |
|
137 | 137 | |
|
138 | 138 | # Update failed because the source reference is missing. |
|
139 | 139 | MISSING_SOURCE_REF = 5 |
|
140 | 140 | |
|
141 | 141 | |
|
142 | 142 | class BaseRepository(object): |
|
143 | 143 | """ |
|
144 | 144 | Base Repository for final backends |
|
145 | 145 | |
|
146 | 146 | .. attribute:: DEFAULT_BRANCH_NAME |
|
147 | 147 | |
|
148 | 148 | name of default branch (i.e. "trunk" for svn, "master" for git etc. |
|
149 | 149 | |
|
150 | 150 | .. attribute:: commit_ids |
|
151 | 151 | |
|
152 | 152 | list of all available commit ids, in ascending order |
|
153 | 153 | |
|
154 | 154 | .. attribute:: path |
|
155 | 155 | |
|
156 | 156 | absolute path to the repository |
|
157 | 157 | |
|
158 | 158 | .. attribute:: bookmarks |
|
159 | 159 | |
|
160 | 160 | Mapping from name to :term:`Commit ID` of the bookmark. Empty in case |
|
161 | 161 | there are no bookmarks or the backend implementation does not support |
|
162 | 162 | bookmarks. |
|
163 | 163 | |
|
164 | 164 | .. attribute:: tags |
|
165 | 165 | |
|
166 | 166 | Mapping from name to :term:`Commit ID` of the tag. |
|
167 | 167 | |
|
168 | 168 | """ |
|
169 | 169 | |
|
170 | 170 | DEFAULT_BRANCH_NAME = None |
|
171 | 171 | DEFAULT_CONTACT = u"Unknown" |
|
172 | 172 | DEFAULT_DESCRIPTION = u"unknown" |
|
173 | 173 | EMPTY_COMMIT_ID = '0' * 40 |
|
174 | 174 | |
|
175 | 175 | path = None |
|
176 | 176 | |
|
177 | 177 | def __init__(self, repo_path, config=None, create=False, **kwargs): |
|
178 | 178 | """ |
|
179 | 179 | Initializes repository. Raises RepositoryError if repository could |
|
180 | 180 | not be find at the given ``repo_path`` or directory at ``repo_path`` |
|
181 | 181 | exists and ``create`` is set to True. |
|
182 | 182 | |
|
183 | 183 | :param repo_path: local path of the repository |
|
184 | 184 | :param config: repository configuration |
|
185 | 185 | :param create=False: if set to True, would try to create repository. |
|
186 | 186 | :param src_url=None: if set, should be proper url from which repository |
|
187 | 187 | would be cloned; requires ``create`` parameter to be set to True - |
|
188 | 188 | raises RepositoryError if src_url is set and create evaluates to |
|
189 | 189 | False |
|
190 | 190 | """ |
|
191 | 191 | raise NotImplementedError |
|
192 | 192 | |
|
193 | 193 | def __repr__(self): |
|
194 | 194 | return '<%s at %s>' % (self.__class__.__name__, self.path) |
|
195 | 195 | |
|
196 | 196 | def __len__(self): |
|
197 | 197 | return self.count() |
|
198 | 198 | |
|
199 | 199 | def __eq__(self, other): |
|
200 | 200 | same_instance = isinstance(other, self.__class__) |
|
201 | 201 | return same_instance and other.path == self.path |
|
202 | 202 | |
|
203 | 203 | def __ne__(self, other): |
|
204 | 204 | return not self.__eq__(other) |
|
205 | 205 | |
|
206 | 206 | @LazyProperty |
|
207 | 207 | def EMPTY_COMMIT(self): |
|
208 | 208 | return EmptyCommit(self.EMPTY_COMMIT_ID) |
|
209 | 209 | |
|
210 | 210 | @LazyProperty |
|
211 | 211 | def alias(self): |
|
212 | 212 | for k, v in settings.BACKENDS.items(): |
|
213 | 213 | if v.split('.')[-1] == str(self.__class__.__name__): |
|
214 | 214 | return k |
|
215 | 215 | |
|
216 | 216 | @LazyProperty |
|
217 | 217 | def name(self): |
|
218 | 218 | return safe_unicode(os.path.basename(self.path)) |
|
219 | 219 | |
|
220 | 220 | @LazyProperty |
|
221 | 221 | def description(self): |
|
222 | 222 | raise NotImplementedError |
|
223 | 223 | |
|
224 | 224 | def refs(self): |
|
225 | 225 | """ |
|
226 | 226 | returns a `dict` with branches, bookmarks, tags, and closed_branches |
|
227 | 227 | for this repository |
|
228 | 228 | """ |
|
229 | 229 | return dict( |
|
230 | 230 | branches=self.branches, |
|
231 | 231 | branches_closed=self.branches_closed, |
|
232 | 232 | tags=self.tags, |
|
233 | 233 | bookmarks=self.bookmarks |
|
234 | 234 | ) |
|
235 | 235 | |
|
236 | 236 | @LazyProperty |
|
237 | 237 | def branches(self): |
|
238 | 238 | """ |
|
239 | 239 | A `dict` which maps branch names to commit ids. |
|
240 | 240 | """ |
|
241 | 241 | raise NotImplementedError |
|
242 | 242 | |
|
243 | 243 | @LazyProperty |
|
244 | 244 | def tags(self): |
|
245 | 245 | """ |
|
246 | 246 | A `dict` which maps tags names to commit ids. |
|
247 | 247 | """ |
|
248 | 248 | raise NotImplementedError |
|
249 | 249 | |
|
250 | 250 | @LazyProperty |
|
251 | 251 | def size(self): |
|
252 | 252 | """ |
|
253 | 253 | Returns combined size in bytes for all repository files |
|
254 | 254 | """ |
|
255 | 255 | tip = self.get_commit() |
|
256 | 256 | return tip.size |
|
257 | 257 | |
|
258 | 258 | def size_at_commit(self, commit_id): |
|
259 | 259 | commit = self.get_commit(commit_id) |
|
260 | 260 | return commit.size |
|
261 | 261 | |
|
262 | 262 | def is_empty(self): |
|
263 | 263 | return not bool(self.commit_ids) |
|
264 | 264 | |
|
265 | 265 | @staticmethod |
|
266 | 266 | def check_url(url, config): |
|
267 | 267 | """ |
|
268 | 268 | Function will check given url and try to verify if it's a valid |
|
269 | 269 | link. |
|
270 | 270 | """ |
|
271 | 271 | raise NotImplementedError |
|
272 | 272 | |
|
273 | 273 | @staticmethod |
|
274 | 274 | def is_valid_repository(path): |
|
275 | 275 | """ |
|
276 | 276 | Check if given `path` contains a valid repository of this backend |
|
277 | 277 | """ |
|
278 | 278 | raise NotImplementedError |
|
279 | 279 | |
|
280 | 280 | # ========================================================================== |
|
281 | 281 | # COMMITS |
|
282 | 282 | # ========================================================================== |
|
283 | 283 | |
|
284 | 284 | def get_commit(self, commit_id=None, commit_idx=None, pre_load=None): |
|
285 | 285 | """ |
|
286 | 286 | Returns instance of `BaseCommit` class. If `commit_id` and `commit_idx` |
|
287 | 287 | are both None, most recent commit is returned. |
|
288 | 288 | |
|
289 | 289 | :param pre_load: Optional. List of commit attributes to load. |
|
290 | 290 | |
|
291 | 291 | :raises ``EmptyRepositoryError``: if there are no commits |
|
292 | 292 | """ |
|
293 | 293 | raise NotImplementedError |
|
294 | 294 | |
|
295 | 295 | def __iter__(self): |
|
296 | 296 | for commit_id in self.commit_ids: |
|
297 | 297 | yield self.get_commit(commit_id=commit_id) |
|
298 | 298 | |
|
299 | 299 | def get_commits( |
|
300 | 300 | self, start_id=None, end_id=None, start_date=None, end_date=None, |
|
301 | 301 | branch_name=None, pre_load=None): |
|
302 | 302 | """ |
|
303 | 303 | Returns iterator of `BaseCommit` objects from start to end |
|
304 | 304 | not inclusive. This should behave just like a list, ie. end is not |
|
305 | 305 | inclusive. |
|
306 | 306 | |
|
307 | 307 | :param start_id: None or str, must be a valid commit id |
|
308 | 308 | :param end_id: None or str, must be a valid commit id |
|
309 | 309 | :param start_date: |
|
310 | 310 | :param end_date: |
|
311 | 311 | :param branch_name: |
|
312 | 312 | :param pre_load: |
|
313 | 313 | """ |
|
314 | 314 | raise NotImplementedError |
|
315 | 315 | |
|
316 | 316 | def __getitem__(self, key): |
|
317 | 317 | """ |
|
318 | 318 | Allows index based access to the commit objects of this repository. |
|
319 | 319 | """ |
|
320 | 320 | pre_load = ["author", "branch", "date", "message", "parents"] |
|
321 | 321 | if isinstance(key, slice): |
|
322 | 322 | return self._get_range(key, pre_load) |
|
323 | 323 | return self.get_commit(commit_idx=key, pre_load=pre_load) |
|
324 | 324 | |
|
325 | 325 | def _get_range(self, slice_obj, pre_load): |
|
326 | 326 | for commit_id in self.commit_ids.__getitem__(slice_obj): |
|
327 | 327 | yield self.get_commit(commit_id=commit_id, pre_load=pre_load) |
|
328 | 328 | |
|
329 | 329 | def count(self): |
|
330 | 330 | return len(self.commit_ids) |
|
331 | 331 | |
|
332 | 332 | def tag(self, name, user, commit_id=None, message=None, date=None, **opts): |
|
333 | 333 | """ |
|
334 | 334 | Creates and returns a tag for the given ``commit_id``. |
|
335 | 335 | |
|
336 | 336 | :param name: name for new tag |
|
337 | 337 | :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" |
|
338 | 338 | :param commit_id: commit id for which new tag would be created |
|
339 | 339 | :param message: message of the tag's commit |
|
340 | 340 | :param date: date of tag's commit |
|
341 | 341 | |
|
342 | 342 | :raises TagAlreadyExistError: if tag with same name already exists |
|
343 | 343 | """ |
|
344 | 344 | raise NotImplementedError |
|
345 | 345 | |
|
346 | 346 | def remove_tag(self, name, user, message=None, date=None): |
|
347 | 347 | """ |
|
348 | 348 | Removes tag with the given ``name``. |
|
349 | 349 | |
|
350 | 350 | :param name: name of the tag to be removed |
|
351 | 351 | :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>" |
|
352 | 352 | :param message: message of the tag's removal commit |
|
353 | 353 | :param date: date of tag's removal commit |
|
354 | 354 | |
|
355 | 355 | :raises TagDoesNotExistError: if tag with given name does not exists |
|
356 | 356 | """ |
|
357 | 357 | raise NotImplementedError |
|
358 | 358 | |
|
359 | 359 | def get_diff( |
|
360 | 360 | self, commit1, commit2, path=None, ignore_whitespace=False, |
|
361 | 361 | context=3, path1=None): |
|
362 | 362 | """ |
|
363 | 363 | Returns (git like) *diff*, as plain text. Shows changes introduced by |
|
364 | 364 | `commit2` since `commit1`. |
|
365 | 365 | |
|
366 | 366 | :param commit1: Entry point from which diff is shown. Can be |
|
367 | 367 | ``self.EMPTY_COMMIT`` - in this case, patch showing all |
|
368 | 368 | the changes since empty state of the repository until `commit2` |
|
369 | 369 | :param commit2: Until which commit changes should be shown. |
|
370 | 370 | :param path: Can be set to a path of a file to create a diff of that |
|
371 | 371 | file. If `path1` is also set, this value is only associated to |
|
372 | 372 | `commit2`. |
|
373 | 373 | :param ignore_whitespace: If set to ``True``, would not show whitespace |
|
374 | 374 | changes. Defaults to ``False``. |
|
375 | 375 | :param context: How many lines before/after changed lines should be |
|
376 | 376 | shown. Defaults to ``3``. |
|
377 | 377 | :param path1: Can be set to a path to associate with `commit1`. This |
|
378 | 378 | parameter works only for backends which support diff generation for |
|
379 | 379 | different paths. Other backends will raise a `ValueError` if `path1` |
|
380 | 380 | is set and has a different value than `path`. |
|
381 | :param file_path: filter this diff by given path pattern | |
|
381 | 382 | """ |
|
382 | 383 | raise NotImplementedError |
|
383 | 384 | |
|
384 | 385 | def strip(self, commit_id, branch=None): |
|
385 | 386 | """ |
|
386 | 387 | Strip given commit_id from the repository |
|
387 | 388 | """ |
|
388 | 389 | raise NotImplementedError |
|
389 | 390 | |
|
390 | 391 | def get_common_ancestor(self, commit_id1, commit_id2, repo2): |
|
391 | 392 | """ |
|
392 | 393 | Return a latest common ancestor commit if one exists for this repo |
|
393 | 394 | `commit_id1` vs `commit_id2` from `repo2`. |
|
394 | 395 | |
|
395 | 396 | :param commit_id1: Commit it from this repository to use as a |
|
396 | 397 | target for the comparison. |
|
397 | 398 | :param commit_id2: Source commit id to use for comparison. |
|
398 | 399 | :param repo2: Source repository to use for comparison. |
|
399 | 400 | """ |
|
400 | 401 | raise NotImplementedError |
|
401 | 402 | |
|
402 | 403 | def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None): |
|
403 | 404 | """ |
|
404 | 405 | Compare this repository's revision `commit_id1` with `commit_id2`. |
|
405 | 406 | |
|
406 | 407 | Returns a tuple(commits, ancestor) that would be merged from |
|
407 | 408 | `commit_id2`. Doing a normal compare (``merge=False``), ``None`` |
|
408 | 409 | will be returned as ancestor. |
|
409 | 410 | |
|
410 | 411 | :param commit_id1: Commit it from this repository to use as a |
|
411 | 412 | target for the comparison. |
|
412 | 413 | :param commit_id2: Source commit id to use for comparison. |
|
413 | 414 | :param repo2: Source repository to use for comparison. |
|
414 | 415 | :param merge: If set to ``True`` will do a merge compare which also |
|
415 | 416 | returns the common ancestor. |
|
416 | 417 | :param pre_load: Optional. List of commit attributes to load. |
|
417 | 418 | """ |
|
418 | 419 | raise NotImplementedError |
|
419 | 420 | |
|
420 | 421 | def merge(self, target_ref, source_repo, source_ref, workspace_id, |
|
421 | 422 | user_name='', user_email='', message='', dry_run=False, |
|
422 | 423 | use_rebase=False): |
|
423 | 424 | """ |
|
424 | 425 | Merge the revisions specified in `source_ref` from `source_repo` |
|
425 | 426 | onto the `target_ref` of this repository. |
|
426 | 427 | |
|
427 | 428 | `source_ref` and `target_ref` are named tupls with the following |
|
428 | 429 | fields `type`, `name` and `commit_id`. |
|
429 | 430 | |
|
430 | 431 | Returns a MergeResponse named tuple with the following fields |
|
431 | 432 | 'possible', 'executed', 'source_commit', 'target_commit', |
|
432 | 433 | 'merge_commit'. |
|
433 | 434 | |
|
434 | 435 | :param target_ref: `target_ref` points to the commit on top of which |
|
435 | 436 | the `source_ref` should be merged. |
|
436 | 437 | :param source_repo: The repository that contains the commits to be |
|
437 | 438 | merged. |
|
438 | 439 | :param source_ref: `source_ref` points to the topmost commit from |
|
439 | 440 | the `source_repo` which should be merged. |
|
440 | 441 | :param workspace_id: `workspace_id` unique identifier. |
|
441 | 442 | :param user_name: Merge commit `user_name`. |
|
442 | 443 | :param user_email: Merge commit `user_email`. |
|
443 | 444 | :param message: Merge commit `message`. |
|
444 | 445 | :param dry_run: If `True` the merge will not take place. |
|
445 | 446 | :param use_rebase: If `True` commits from the source will be rebased |
|
446 | 447 | on top of the target instead of being merged. |
|
447 | 448 | """ |
|
448 | 449 | if dry_run: |
|
449 | 450 | message = message or 'dry_run_merge_message' |
|
450 | 451 | user_email = user_email or 'dry-run-merge@rhodecode.com' |
|
451 | 452 | user_name = user_name or 'Dry-Run User' |
|
452 | 453 | else: |
|
453 | 454 | if not user_name: |
|
454 | 455 | raise ValueError('user_name cannot be empty') |
|
455 | 456 | if not user_email: |
|
456 | 457 | raise ValueError('user_email cannot be empty') |
|
457 | 458 | if not message: |
|
458 | 459 | raise ValueError('message cannot be empty') |
|
459 | 460 | |
|
460 | 461 | shadow_repository_path = self._maybe_prepare_merge_workspace( |
|
461 | 462 | workspace_id, target_ref) |
|
462 | 463 | |
|
463 | 464 | try: |
|
464 | 465 | return self._merge_repo( |
|
465 | 466 | shadow_repository_path, target_ref, source_repo, |
|
466 | 467 | source_ref, message, user_name, user_email, dry_run=dry_run, |
|
467 | 468 | use_rebase=use_rebase) |
|
468 | 469 | except RepositoryError: |
|
469 | 470 | log.exception( |
|
470 | 471 | 'Unexpected failure when running merge, dry-run=%s', |
|
471 | 472 | dry_run) |
|
472 | 473 | return MergeResponse( |
|
473 | 474 | False, False, None, MergeFailureReason.UNKNOWN) |
|
474 | 475 | |
|
475 | 476 | def _merge_repo(self, shadow_repository_path, target_ref, |
|
476 | 477 | source_repo, source_ref, merge_message, |
|
477 | 478 | merger_name, merger_email, dry_run=False, use_rebase=False): |
|
478 | 479 | """Internal implementation of merge.""" |
|
479 | 480 | raise NotImplementedError |
|
480 | 481 | |
|
481 | 482 | def _maybe_prepare_merge_workspace(self, workspace_id, target_ref): |
|
482 | 483 | """ |
|
483 | 484 | Create the merge workspace. |
|
484 | 485 | |
|
485 | 486 | :param workspace_id: `workspace_id` unique identifier. |
|
486 | 487 | """ |
|
487 | 488 | raise NotImplementedError |
|
488 | 489 | |
|
489 | 490 | def cleanup_merge_workspace(self, workspace_id): |
|
490 | 491 | """ |
|
491 | 492 | Remove merge workspace. |
|
492 | 493 | |
|
493 | 494 | This function MUST not fail in case there is no workspace associated to |
|
494 | 495 | the given `workspace_id`. |
|
495 | 496 | |
|
496 | 497 | :param workspace_id: `workspace_id` unique identifier. |
|
497 | 498 | """ |
|
498 | 499 | raise NotImplementedError |
|
499 | 500 | |
|
500 | 501 | # ========== # |
|
501 | 502 | # COMMIT API # |
|
502 | 503 | # ========== # |
|
503 | 504 | |
|
504 | 505 | @LazyProperty |
|
505 | 506 | def in_memory_commit(self): |
|
506 | 507 | """ |
|
507 | 508 | Returns :class:`InMemoryCommit` object for this repository. |
|
508 | 509 | """ |
|
509 | 510 | raise NotImplementedError |
|
510 | 511 | |
|
511 | 512 | # ======================== # |
|
512 | 513 | # UTILITIES FOR SUBCLASSES # |
|
513 | 514 | # ======================== # |
|
514 | 515 | |
|
515 | 516 | def _validate_diff_commits(self, commit1, commit2): |
|
516 | 517 | """ |
|
517 | 518 | Validates that the given commits are related to this repository. |
|
518 | 519 | |
|
519 | 520 | Intended as a utility for sub classes to have a consistent validation |
|
520 | 521 | of input parameters in methods like :meth:`get_diff`. |
|
521 | 522 | """ |
|
522 | 523 | self._validate_commit(commit1) |
|
523 | 524 | self._validate_commit(commit2) |
|
524 | 525 | if (isinstance(commit1, EmptyCommit) and |
|
525 | 526 | isinstance(commit2, EmptyCommit)): |
|
526 | 527 | raise ValueError("Cannot compare two empty commits") |
|
527 | 528 | |
|
528 | 529 | def _validate_commit(self, commit): |
|
529 | 530 | if not isinstance(commit, BaseCommit): |
|
530 | 531 | raise TypeError( |
|
531 | 532 | "%s is not of type BaseCommit" % repr(commit)) |
|
532 | 533 | if commit.repository != self and not isinstance(commit, EmptyCommit): |
|
533 | 534 | raise ValueError( |
|
534 | 535 | "Commit %s must be a valid commit from this repository %s, " |
|
535 | 536 | "related to this repository instead %s." % |
|
536 | 537 | (commit, self, commit.repository)) |
|
537 | 538 | |
|
538 | 539 | def _validate_commit_id(self, commit_id): |
|
539 | 540 | if not isinstance(commit_id, basestring): |
|
540 | 541 | raise TypeError("commit_id must be a string value") |
|
541 | 542 | |
|
542 | 543 | def _validate_commit_idx(self, commit_idx): |
|
543 | 544 | if not isinstance(commit_idx, (int, long)): |
|
544 | 545 | raise TypeError("commit_idx must be a numeric value") |
|
545 | 546 | |
|
546 | 547 | def _validate_branch_name(self, branch_name): |
|
547 | 548 | if branch_name and branch_name not in self.branches_all: |
|
548 | 549 | msg = ("Branch %s not found in %s" % (branch_name, self)) |
|
549 | 550 | raise BranchDoesNotExistError(msg) |
|
550 | 551 | |
|
551 | 552 | # |
|
552 | 553 | # Supporting deprecated API parts |
|
553 | 554 | # TODO: johbo: consider to move this into a mixin |
|
554 | 555 | # |
|
555 | 556 | |
|
556 | 557 | @property |
|
557 | 558 | def EMPTY_CHANGESET(self): |
|
558 | 559 | warnings.warn( |
|
559 | 560 | "Use EMPTY_COMMIT or EMPTY_COMMIT_ID instead", DeprecationWarning) |
|
560 | 561 | return self.EMPTY_COMMIT_ID |
|
561 | 562 | |
|
562 | 563 | @property |
|
563 | 564 | def revisions(self): |
|
564 | 565 | warnings.warn("Use commits attribute instead", DeprecationWarning) |
|
565 | 566 | return self.commit_ids |
|
566 | 567 | |
|
567 | 568 | @revisions.setter |
|
568 | 569 | def revisions(self, value): |
|
569 | 570 | warnings.warn("Use commits attribute instead", DeprecationWarning) |
|
570 | 571 | self.commit_ids = value |
|
571 | 572 | |
|
572 | 573 | def get_changeset(self, revision=None, pre_load=None): |
|
573 | 574 | warnings.warn("Use get_commit instead", DeprecationWarning) |
|
574 | 575 | commit_id = None |
|
575 | 576 | commit_idx = None |
|
576 | 577 | if isinstance(revision, basestring): |
|
577 | 578 | commit_id = revision |
|
578 | 579 | else: |
|
579 | 580 | commit_idx = revision |
|
580 | 581 | return self.get_commit( |
|
581 | 582 | commit_id=commit_id, commit_idx=commit_idx, pre_load=pre_load) |
|
582 | 583 | |
|
583 | 584 | def get_changesets( |
|
584 | 585 | self, start=None, end=None, start_date=None, end_date=None, |
|
585 | 586 | branch_name=None, pre_load=None): |
|
586 | 587 | warnings.warn("Use get_commits instead", DeprecationWarning) |
|
587 | 588 | start_id = self._revision_to_commit(start) |
|
588 | 589 | end_id = self._revision_to_commit(end) |
|
589 | 590 | return self.get_commits( |
|
590 | 591 | start_id=start_id, end_id=end_id, start_date=start_date, |
|
591 | 592 | end_date=end_date, branch_name=branch_name, pre_load=pre_load) |
|
592 | 593 | |
|
593 | 594 | def _revision_to_commit(self, revision): |
|
594 | 595 | """ |
|
595 | 596 | Translates a revision to a commit_id |
|
596 | 597 | |
|
597 | 598 | Helps to support the old changeset based API which allows to use |
|
598 | 599 | commit ids and commit indices interchangeable. |
|
599 | 600 | """ |
|
600 | 601 | if revision is None: |
|
601 | 602 | return revision |
|
602 | 603 | |
|
603 | 604 | if isinstance(revision, basestring): |
|
604 | 605 | commit_id = revision |
|
605 | 606 | else: |
|
606 | 607 | commit_id = self.commit_ids[revision] |
|
607 | 608 | return commit_id |
|
608 | 609 | |
|
609 | 610 | @property |
|
610 | 611 | def in_memory_changeset(self): |
|
611 | 612 | warnings.warn("Use in_memory_commit instead", DeprecationWarning) |
|
612 | 613 | return self.in_memory_commit |
|
613 | 614 | |
|
614 | 615 | |
|
615 | 616 | class BaseCommit(object): |
|
616 | 617 | """ |
|
617 | 618 | Each backend should implement it's commit representation. |
|
618 | 619 | |
|
619 | 620 | **Attributes** |
|
620 | 621 | |
|
621 | 622 | ``repository`` |
|
622 | 623 | repository object within which commit exists |
|
623 | 624 | |
|
624 | 625 | ``id`` |
|
625 | 626 | The commit id, may be ``raw_id`` or i.e. for mercurial's tip |
|
626 | 627 | just ``tip``. |
|
627 | 628 | |
|
628 | 629 | ``raw_id`` |
|
629 | 630 | raw commit representation (i.e. full 40 length sha for git |
|
630 | 631 | backend) |
|
631 | 632 | |
|
632 | 633 | ``short_id`` |
|
633 | 634 | shortened (if apply) version of ``raw_id``; it would be simple |
|
634 | 635 | shortcut for ``raw_id[:12]`` for git/mercurial backends or same |
|
635 | 636 | as ``raw_id`` for subversion |
|
636 | 637 | |
|
637 | 638 | ``idx`` |
|
638 | 639 | commit index |
|
639 | 640 | |
|
640 | 641 | ``files`` |
|
641 | 642 | list of ``FileNode`` (``Node`` with NodeKind.FILE) objects |
|
642 | 643 | |
|
643 | 644 | ``dirs`` |
|
644 | 645 | list of ``DirNode`` (``Node`` with NodeKind.DIR) objects |
|
645 | 646 | |
|
646 | 647 | ``nodes`` |
|
647 | 648 | combined list of ``Node`` objects |
|
648 | 649 | |
|
649 | 650 | ``author`` |
|
650 | 651 | author of the commit, as unicode |
|
651 | 652 | |
|
652 | 653 | ``message`` |
|
653 | 654 | message of the commit, as unicode |
|
654 | 655 | |
|
655 | 656 | ``parents`` |
|
656 | 657 | list of parent commits |
|
657 | 658 | |
|
658 | 659 | """ |
|
659 | 660 | |
|
660 | 661 | branch = None |
|
661 | 662 | """ |
|
662 | 663 | Depending on the backend this should be set to the branch name of the |
|
663 | 664 | commit. Backends not supporting branches on commits should leave this |
|
664 | 665 | value as ``None``. |
|
665 | 666 | """ |
|
666 | 667 | |
|
667 | 668 | _ARCHIVE_PREFIX_TEMPLATE = b'{repo_name}-{short_id}' |
|
668 | 669 | """ |
|
669 | 670 | This template is used to generate a default prefix for repository archives |
|
670 | 671 | if no prefix has been specified. |
|
671 | 672 | """ |
|
672 | 673 | |
|
673 | 674 | def __str__(self): |
|
674 | 675 | return '<%s at %s:%s>' % ( |
|
675 | 676 | self.__class__.__name__, self.idx, self.short_id) |
|
676 | 677 | |
|
677 | 678 | def __repr__(self): |
|
678 | 679 | return self.__str__() |
|
679 | 680 | |
|
680 | 681 | def __unicode__(self): |
|
681 | 682 | return u'%s:%s' % (self.idx, self.short_id) |
|
682 | 683 | |
|
683 | 684 | def __eq__(self, other): |
|
684 | 685 | same_instance = isinstance(other, self.__class__) |
|
685 | 686 | return same_instance and self.raw_id == other.raw_id |
|
686 | 687 | |
|
687 | 688 | def __json__(self): |
|
688 | 689 | parents = [] |
|
689 | 690 | try: |
|
690 | 691 | for parent in self.parents: |
|
691 | 692 | parents.append({'raw_id': parent.raw_id}) |
|
692 | 693 | except NotImplementedError: |
|
693 | 694 | # empty commit doesn't have parents implemented |
|
694 | 695 | pass |
|
695 | 696 | |
|
696 | 697 | return { |
|
697 | 698 | 'short_id': self.short_id, |
|
698 | 699 | 'raw_id': self.raw_id, |
|
699 | 700 | 'revision': self.idx, |
|
700 | 701 | 'message': self.message, |
|
701 | 702 | 'date': self.date, |
|
702 | 703 | 'author': self.author, |
|
703 | 704 | 'parents': parents, |
|
704 | 705 | 'branch': self.branch |
|
705 | 706 | } |
|
706 | 707 | |
|
707 | 708 | @LazyProperty |
|
708 | 709 | def last(self): |
|
709 | 710 | """ |
|
710 | 711 | ``True`` if this is last commit in repository, ``False`` |
|
711 | 712 | otherwise; trying to access this attribute while there is no |
|
712 | 713 | commits would raise `EmptyRepositoryError` |
|
713 | 714 | """ |
|
714 | 715 | if self.repository is None: |
|
715 | 716 | raise CommitError("Cannot check if it's most recent commit") |
|
716 | 717 | return self.raw_id == self.repository.commit_ids[-1] |
|
717 | 718 | |
|
718 | 719 | @LazyProperty |
|
719 | 720 | def parents(self): |
|
720 | 721 | """ |
|
721 | 722 | Returns list of parent commits. |
|
722 | 723 | """ |
|
723 | 724 | raise NotImplementedError |
|
724 | 725 | |
|
725 | 726 | @property |
|
726 | 727 | def merge(self): |
|
727 | 728 | """ |
|
728 | 729 | Returns boolean if commit is a merge. |
|
729 | 730 | """ |
|
730 | 731 | return len(self.parents) > 1 |
|
731 | 732 | |
|
732 | 733 | @LazyProperty |
|
733 | 734 | def children(self): |
|
734 | 735 | """ |
|
735 | 736 | Returns list of child commits. |
|
736 | 737 | """ |
|
737 | 738 | raise NotImplementedError |
|
738 | 739 | |
|
739 | 740 | @LazyProperty |
|
740 | 741 | def id(self): |
|
741 | 742 | """ |
|
742 | 743 | Returns string identifying this commit. |
|
743 | 744 | """ |
|
744 | 745 | raise NotImplementedError |
|
745 | 746 | |
|
746 | 747 | @LazyProperty |
|
747 | 748 | def raw_id(self): |
|
748 | 749 | """ |
|
749 | 750 | Returns raw string identifying this commit. |
|
750 | 751 | """ |
|
751 | 752 | raise NotImplementedError |
|
752 | 753 | |
|
753 | 754 | @LazyProperty |
|
754 | 755 | def short_id(self): |
|
755 | 756 | """ |
|
756 | 757 | Returns shortened version of ``raw_id`` attribute, as string, |
|
757 | 758 | identifying this commit, useful for presentation to users. |
|
758 | 759 | """ |
|
759 | 760 | raise NotImplementedError |
|
760 | 761 | |
|
761 | 762 | @LazyProperty |
|
762 | 763 | def idx(self): |
|
763 | 764 | """ |
|
764 | 765 | Returns integer identifying this commit. |
|
765 | 766 | """ |
|
766 | 767 | raise NotImplementedError |
|
767 | 768 | |
|
768 | 769 | @LazyProperty |
|
769 | 770 | def committer(self): |
|
770 | 771 | """ |
|
771 | 772 | Returns committer for this commit |
|
772 | 773 | """ |
|
773 | 774 | raise NotImplementedError |
|
774 | 775 | |
|
775 | 776 | @LazyProperty |
|
776 | 777 | def committer_name(self): |
|
777 | 778 | """ |
|
778 | 779 | Returns committer name for this commit |
|
779 | 780 | """ |
|
780 | 781 | |
|
781 | 782 | return author_name(self.committer) |
|
782 | 783 | |
|
783 | 784 | @LazyProperty |
|
784 | 785 | def committer_email(self): |
|
785 | 786 | """ |
|
786 | 787 | Returns committer email address for this commit |
|
787 | 788 | """ |
|
788 | 789 | |
|
789 | 790 | return author_email(self.committer) |
|
790 | 791 | |
|
791 | 792 | @LazyProperty |
|
792 | 793 | def author(self): |
|
793 | 794 | """ |
|
794 | 795 | Returns author for this commit |
|
795 | 796 | """ |
|
796 | 797 | |
|
797 | 798 | raise NotImplementedError |
|
798 | 799 | |
|
799 | 800 | @LazyProperty |
|
800 | 801 | def author_name(self): |
|
801 | 802 | """ |
|
802 | 803 | Returns author name for this commit |
|
803 | 804 | """ |
|
804 | 805 | |
|
805 | 806 | return author_name(self.author) |
|
806 | 807 | |
|
807 | 808 | @LazyProperty |
|
808 | 809 | def author_email(self): |
|
809 | 810 | """ |
|
810 | 811 | Returns author email address for this commit |
|
811 | 812 | """ |
|
812 | 813 | |
|
813 | 814 | return author_email(self.author) |
|
814 | 815 | |
|
815 | 816 | def get_file_mode(self, path): |
|
816 | 817 | """ |
|
817 | 818 | Returns stat mode of the file at `path`. |
|
818 | 819 | """ |
|
819 | 820 | raise NotImplementedError |
|
820 | 821 | |
|
821 | 822 | def is_link(self, path): |
|
822 | 823 | """ |
|
823 | 824 | Returns ``True`` if given `path` is a symlink |
|
824 | 825 | """ |
|
825 | 826 | raise NotImplementedError |
|
826 | 827 | |
|
827 | 828 | def get_file_content(self, path): |
|
828 | 829 | """ |
|
829 | 830 | Returns content of the file at the given `path`. |
|
830 | 831 | """ |
|
831 | 832 | raise NotImplementedError |
|
832 | 833 | |
|
833 | 834 | def get_file_size(self, path): |
|
834 | 835 | """ |
|
835 | 836 | Returns size of the file at the given `path`. |
|
836 | 837 | """ |
|
837 | 838 | raise NotImplementedError |
|
838 | 839 | |
|
839 | 840 | def get_file_commit(self, path, pre_load=None): |
|
840 | 841 | """ |
|
841 | 842 | Returns last commit of the file at the given `path`. |
|
842 | 843 | |
|
843 | 844 | :param pre_load: Optional. List of commit attributes to load. |
|
844 | 845 | """ |
|
845 | 846 | commits = self.get_file_history(path, limit=1, pre_load=pre_load) |
|
846 | 847 | if not commits: |
|
847 | 848 | raise RepositoryError( |
|
848 | 849 | 'Failed to fetch history for path {}. ' |
|
849 | 850 | 'Please check if such path exists in your repository'.format( |
|
850 | 851 | path)) |
|
851 | 852 | return commits[0] |
|
852 | 853 | |
|
853 | 854 | def get_file_history(self, path, limit=None, pre_load=None): |
|
854 | 855 | """ |
|
855 | 856 | Returns history of file as reversed list of :class:`BaseCommit` |
|
856 | 857 | objects for which file at given `path` has been modified. |
|
857 | 858 | |
|
858 | 859 | :param limit: Optional. Allows to limit the size of the returned |
|
859 | 860 | history. This is intended as a hint to the underlying backend, so |
|
860 | 861 | that it can apply optimizations depending on the limit. |
|
861 | 862 | :param pre_load: Optional. List of commit attributes to load. |
|
862 | 863 | """ |
|
863 | 864 | raise NotImplementedError |
|
864 | 865 | |
|
865 | 866 | def get_file_annotate(self, path, pre_load=None): |
|
866 | 867 | """ |
|
867 | 868 | Returns a generator of four element tuples with |
|
868 | 869 | lineno, sha, commit lazy loader and line |
|
869 | 870 | |
|
870 | 871 | :param pre_load: Optional. List of commit attributes to load. |
|
871 | 872 | """ |
|
872 | 873 | raise NotImplementedError |
|
873 | 874 | |
|
874 | 875 | def get_nodes(self, path): |
|
875 | 876 | """ |
|
876 | 877 | Returns combined ``DirNode`` and ``FileNode`` objects list representing |
|
877 | 878 | state of commit at the given ``path``. |
|
878 | 879 | |
|
879 | 880 | :raises ``CommitError``: if node at the given ``path`` is not |
|
880 | 881 | instance of ``DirNode`` |
|
881 | 882 | """ |
|
882 | 883 | raise NotImplementedError |
|
883 | 884 | |
|
884 | 885 | def get_node(self, path): |
|
885 | 886 | """ |
|
886 | 887 | Returns ``Node`` object from the given ``path``. |
|
887 | 888 | |
|
888 | 889 | :raises ``NodeDoesNotExistError``: if there is no node at the given |
|
889 | 890 | ``path`` |
|
890 | 891 | """ |
|
891 | 892 | raise NotImplementedError |
|
892 | 893 | |
|
893 | 894 | def get_largefile_node(self, path): |
|
894 | 895 | """ |
|
895 | 896 | Returns the path to largefile from Mercurial storage. |
|
896 | 897 | """ |
|
897 | 898 | raise NotImplementedError |
|
898 | 899 | |
|
899 | 900 | def archive_repo(self, file_path, kind='tgz', subrepos=None, |
|
900 | 901 | prefix=None, write_metadata=False, mtime=None): |
|
901 | 902 | """ |
|
902 | 903 | Creates an archive containing the contents of the repository. |
|
903 | 904 | |
|
904 | 905 | :param file_path: path to the file which to create the archive. |
|
905 | 906 | :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``. |
|
906 | 907 | :param prefix: name of root directory in archive. |
|
907 | 908 | Default is repository name and commit's short_id joined with dash: |
|
908 | 909 | ``"{repo_name}-{short_id}"``. |
|
909 | 910 | :param write_metadata: write a metadata file into archive. |
|
910 | 911 | :param mtime: custom modification time for archive creation, defaults |
|
911 | 912 | to time.time() if not given. |
|
912 | 913 | |
|
913 | 914 | :raise VCSError: If prefix has a problem. |
|
914 | 915 | """ |
|
915 | 916 | allowed_kinds = settings.ARCHIVE_SPECS.keys() |
|
916 | 917 | if kind not in allowed_kinds: |
|
917 | 918 | raise ImproperArchiveTypeError( |
|
918 | 919 | 'Archive kind (%s) not supported use one of %s' % |
|
919 | 920 | (kind, allowed_kinds)) |
|
920 | 921 | |
|
921 | 922 | prefix = self._validate_archive_prefix(prefix) |
|
922 | 923 | |
|
923 | 924 | mtime = mtime or time.mktime(self.date.timetuple()) |
|
924 | 925 | |
|
925 | 926 | file_info = [] |
|
926 | 927 | cur_rev = self.repository.get_commit(commit_id=self.raw_id) |
|
927 | 928 | for _r, _d, files in cur_rev.walk('/'): |
|
928 | 929 | for f in files: |
|
929 | 930 | f_path = os.path.join(prefix, f.path) |
|
930 | 931 | file_info.append( |
|
931 | 932 | (f_path, f.mode, f.is_link(), f.raw_bytes)) |
|
932 | 933 | |
|
933 | 934 | if write_metadata: |
|
934 | 935 | metadata = [ |
|
935 | 936 | ('repo_name', self.repository.name), |
|
936 | 937 | ('rev', self.raw_id), |
|
937 | 938 | ('create_time', mtime), |
|
938 | 939 | ('branch', self.branch), |
|
939 | 940 | ('tags', ','.join(self.tags)), |
|
940 | 941 | ] |
|
941 | 942 | meta = ["%s:%s" % (f_name, value) for f_name, value in metadata] |
|
942 | 943 | file_info.append(('.archival.txt', 0644, False, '\n'.join(meta))) |
|
943 | 944 | |
|
944 | 945 | connection.Hg.archive_repo(file_path, mtime, file_info, kind) |
|
945 | 946 | |
|
946 | 947 | def _validate_archive_prefix(self, prefix): |
|
947 | 948 | if prefix is None: |
|
948 | 949 | prefix = self._ARCHIVE_PREFIX_TEMPLATE.format( |
|
949 | 950 | repo_name=safe_str(self.repository.name), |
|
950 | 951 | short_id=self.short_id) |
|
951 | 952 | elif not isinstance(prefix, str): |
|
952 | 953 | raise ValueError("prefix not a bytes object: %s" % repr(prefix)) |
|
953 | 954 | elif prefix.startswith('/'): |
|
954 | 955 | raise VCSError("Prefix cannot start with leading slash") |
|
955 | 956 | elif prefix.strip() == '': |
|
956 | 957 | raise VCSError("Prefix cannot be empty") |
|
957 | 958 | return prefix |
|
958 | 959 | |
|
959 | 960 | @LazyProperty |
|
960 | 961 | def root(self): |
|
961 | 962 | """ |
|
962 | 963 | Returns ``RootNode`` object for this commit. |
|
963 | 964 | """ |
|
964 | 965 | return self.get_node('') |
|
965 | 966 | |
|
966 | 967 | def next(self, branch=None): |
|
967 | 968 | """ |
|
968 | 969 | Returns next commit from current, if branch is gives it will return |
|
969 | 970 | next commit belonging to this branch |
|
970 | 971 | |
|
971 | 972 | :param branch: show commits within the given named branch |
|
972 | 973 | """ |
|
973 | 974 | indexes = xrange(self.idx + 1, self.repository.count()) |
|
974 | 975 | return self._find_next(indexes, branch) |
|
975 | 976 | |
|
976 | 977 | def prev(self, branch=None): |
|
977 | 978 | """ |
|
978 | 979 | Returns previous commit from current, if branch is gives it will |
|
979 | 980 | return previous commit belonging to this branch |
|
980 | 981 | |
|
981 | 982 | :param branch: show commit within the given named branch |
|
982 | 983 | """ |
|
983 | 984 | indexes = xrange(self.idx - 1, -1, -1) |
|
984 | 985 | return self._find_next(indexes, branch) |
|
985 | 986 | |
|
986 | 987 | def _find_next(self, indexes, branch=None): |
|
987 | 988 | if branch and self.branch != branch: |
|
988 | 989 | raise VCSError('Branch option used on commit not belonging ' |
|
989 | 990 | 'to that branch') |
|
990 | 991 | |
|
991 | 992 | for next_idx in indexes: |
|
992 | 993 | commit = self.repository.get_commit(commit_idx=next_idx) |
|
993 | 994 | if branch and branch != commit.branch: |
|
994 | 995 | continue |
|
995 | 996 | return commit |
|
996 | 997 | raise CommitDoesNotExistError |
|
997 | 998 | |
|
998 | 999 | def diff(self, ignore_whitespace=True, context=3): |
|
999 | 1000 | """ |
|
1000 | 1001 | Returns a `Diff` object representing the change made by this commit. |
|
1001 | 1002 | """ |
|
1002 | 1003 | parent = ( |
|
1003 | 1004 | self.parents[0] if self.parents else self.repository.EMPTY_COMMIT) |
|
1004 | 1005 | diff = self.repository.get_diff( |
|
1005 | 1006 | parent, self, |
|
1006 | 1007 | ignore_whitespace=ignore_whitespace, |
|
1007 | 1008 | context=context) |
|
1008 | 1009 | return diff |
|
1009 | 1010 | |
|
1010 | 1011 | @LazyProperty |
|
1011 | 1012 | def added(self): |
|
1012 | 1013 | """ |
|
1013 | 1014 | Returns list of added ``FileNode`` objects. |
|
1014 | 1015 | """ |
|
1015 | 1016 | raise NotImplementedError |
|
1016 | 1017 | |
|
1017 | 1018 | @LazyProperty |
|
1018 | 1019 | def changed(self): |
|
1019 | 1020 | """ |
|
1020 | 1021 | Returns list of modified ``FileNode`` objects. |
|
1021 | 1022 | """ |
|
1022 | 1023 | raise NotImplementedError |
|
1023 | 1024 | |
|
1024 | 1025 | @LazyProperty |
|
1025 | 1026 | def removed(self): |
|
1026 | 1027 | """ |
|
1027 | 1028 | Returns list of removed ``FileNode`` objects. |
|
1028 | 1029 | """ |
|
1029 | 1030 | raise NotImplementedError |
|
1030 | 1031 | |
|
1031 | 1032 | @LazyProperty |
|
1032 | 1033 | def size(self): |
|
1033 | 1034 | """ |
|
1034 | 1035 | Returns total number of bytes from contents of all filenodes. |
|
1035 | 1036 | """ |
|
1036 | 1037 | return sum((node.size for node in self.get_filenodes_generator())) |
|
1037 | 1038 | |
|
1038 | 1039 | def walk(self, topurl=''): |
|
1039 | 1040 | """ |
|
1040 | 1041 | Similar to os.walk method. Insted of filesystem it walks through |
|
1041 | 1042 | commit starting at given ``topurl``. Returns generator of tuples |
|
1042 | 1043 | (topnode, dirnodes, filenodes). |
|
1043 | 1044 | """ |
|
1044 | 1045 | topnode = self.get_node(topurl) |
|
1045 | 1046 | if not topnode.is_dir(): |
|
1046 | 1047 | return |
|
1047 | 1048 | yield (topnode, topnode.dirs, topnode.files) |
|
1048 | 1049 | for dirnode in topnode.dirs: |
|
1049 | 1050 | for tup in self.walk(dirnode.path): |
|
1050 | 1051 | yield tup |
|
1051 | 1052 | |
|
1052 | 1053 | def get_filenodes_generator(self): |
|
1053 | 1054 | """ |
|
1054 | 1055 | Returns generator that yields *all* file nodes. |
|
1055 | 1056 | """ |
|
1056 | 1057 | for topnode, dirs, files in self.walk(): |
|
1057 | 1058 | for node in files: |
|
1058 | 1059 | yield node |
|
1059 | 1060 | |
|
1060 | 1061 | # |
|
1061 | 1062 | # Utilities for sub classes to support consistent behavior |
|
1062 | 1063 | # |
|
1063 | 1064 | |
|
1064 | 1065 | def no_node_at_path(self, path): |
|
1065 | 1066 | return NodeDoesNotExistError( |
|
1066 | 1067 | "There is no file nor directory at the given path: " |
|
1067 | 1068 | "'%s' at commit %s" % (path, self.short_id)) |
|
1068 | 1069 | |
|
1069 | 1070 | def _fix_path(self, path): |
|
1070 | 1071 | """ |
|
1071 | 1072 | Paths are stored without trailing slash so we need to get rid off it if |
|
1072 | 1073 | needed. |
|
1073 | 1074 | """ |
|
1074 | 1075 | return path.rstrip('/') |
|
1075 | 1076 | |
|
1076 | 1077 | # |
|
1077 | 1078 | # Deprecated API based on changesets |
|
1078 | 1079 | # |
|
1079 | 1080 | |
|
1080 | 1081 | @property |
|
1081 | 1082 | def revision(self): |
|
1082 | 1083 | warnings.warn("Use idx instead", DeprecationWarning) |
|
1083 | 1084 | return self.idx |
|
1084 | 1085 | |
|
1085 | 1086 | @revision.setter |
|
1086 | 1087 | def revision(self, value): |
|
1087 | 1088 | warnings.warn("Use idx instead", DeprecationWarning) |
|
1088 | 1089 | self.idx = value |
|
1089 | 1090 | |
|
1090 | 1091 | def get_file_changeset(self, path): |
|
1091 | 1092 | warnings.warn("Use get_file_commit instead", DeprecationWarning) |
|
1092 | 1093 | return self.get_file_commit(path) |
|
1093 | 1094 | |
|
1094 | 1095 | |
|
1095 | 1096 | class BaseChangesetClass(type): |
|
1096 | 1097 | |
|
1097 | 1098 | def __instancecheck__(self, instance): |
|
1098 | 1099 | return isinstance(instance, BaseCommit) |
|
1099 | 1100 | |
|
1100 | 1101 | |
|
1101 | 1102 | class BaseChangeset(BaseCommit): |
|
1102 | 1103 | |
|
1103 | 1104 | __metaclass__ = BaseChangesetClass |
|
1104 | 1105 | |
|
1105 | 1106 | def __new__(cls, *args, **kwargs): |
|
1106 | 1107 | warnings.warn( |
|
1107 | 1108 | "Use BaseCommit instead of BaseChangeset", DeprecationWarning) |
|
1108 | 1109 | return super(BaseChangeset, cls).__new__(cls, *args, **kwargs) |
|
1109 | 1110 | |
|
1110 | 1111 | |
|
1111 | 1112 | class BaseInMemoryCommit(object): |
|
1112 | 1113 | """ |
|
1113 | 1114 | Represents differences between repository's state (most recent head) and |
|
1114 | 1115 | changes made *in place*. |
|
1115 | 1116 | |
|
1116 | 1117 | **Attributes** |
|
1117 | 1118 | |
|
1118 | 1119 | ``repository`` |
|
1119 | 1120 | repository object for this in-memory-commit |
|
1120 | 1121 | |
|
1121 | 1122 | ``added`` |
|
1122 | 1123 | list of ``FileNode`` objects marked as *added* |
|
1123 | 1124 | |
|
1124 | 1125 | ``changed`` |
|
1125 | 1126 | list of ``FileNode`` objects marked as *changed* |
|
1126 | 1127 | |
|
1127 | 1128 | ``removed`` |
|
1128 | 1129 | list of ``FileNode`` or ``RemovedFileNode`` objects marked to be |
|
1129 | 1130 | *removed* |
|
1130 | 1131 | |
|
1131 | 1132 | ``parents`` |
|
1132 | 1133 | list of :class:`BaseCommit` instances representing parents of |
|
1133 | 1134 | in-memory commit. Should always be 2-element sequence. |
|
1134 | 1135 | |
|
1135 | 1136 | """ |
|
1136 | 1137 | |
|
1137 | 1138 | def __init__(self, repository): |
|
1138 | 1139 | self.repository = repository |
|
1139 | 1140 | self.added = [] |
|
1140 | 1141 | self.changed = [] |
|
1141 | 1142 | self.removed = [] |
|
1142 | 1143 | self.parents = [] |
|
1143 | 1144 | |
|
1144 | 1145 | def add(self, *filenodes): |
|
1145 | 1146 | """ |
|
1146 | 1147 | Marks given ``FileNode`` objects as *to be committed*. |
|
1147 | 1148 | |
|
1148 | 1149 | :raises ``NodeAlreadyExistsError``: if node with same path exists at |
|
1149 | 1150 | latest commit |
|
1150 | 1151 | :raises ``NodeAlreadyAddedError``: if node with same path is already |
|
1151 | 1152 | marked as *added* |
|
1152 | 1153 | """ |
|
1153 | 1154 | # Check if not already marked as *added* first |
|
1154 | 1155 | for node in filenodes: |
|
1155 | 1156 | if node.path in (n.path for n in self.added): |
|
1156 | 1157 | raise NodeAlreadyAddedError( |
|
1157 | 1158 | "Such FileNode %s is already marked for addition" |
|
1158 | 1159 | % node.path) |
|
1159 | 1160 | for node in filenodes: |
|
1160 | 1161 | self.added.append(node) |
|
1161 | 1162 | |
|
1162 | 1163 | def change(self, *filenodes): |
|
1163 | 1164 | """ |
|
1164 | 1165 | Marks given ``FileNode`` objects to be *changed* in next commit. |
|
1165 | 1166 | |
|
1166 | 1167 | :raises ``EmptyRepositoryError``: if there are no commits yet |
|
1167 | 1168 | :raises ``NodeAlreadyExistsError``: if node with same path is already |
|
1168 | 1169 | marked to be *changed* |
|
1169 | 1170 | :raises ``NodeAlreadyRemovedError``: if node with same path is already |
|
1170 | 1171 | marked to be *removed* |
|
1171 | 1172 | :raises ``NodeDoesNotExistError``: if node doesn't exist in latest |
|
1172 | 1173 | commit |
|
1173 | 1174 | :raises ``NodeNotChangedError``: if node hasn't really be changed |
|
1174 | 1175 | """ |
|
1175 | 1176 | for node in filenodes: |
|
1176 | 1177 | if node.path in (n.path for n in self.removed): |
|
1177 | 1178 | raise NodeAlreadyRemovedError( |
|
1178 | 1179 | "Node at %s is already marked as removed" % node.path) |
|
1179 | 1180 | try: |
|
1180 | 1181 | self.repository.get_commit() |
|
1181 | 1182 | except EmptyRepositoryError: |
|
1182 | 1183 | raise EmptyRepositoryError( |
|
1183 | 1184 | "Nothing to change - try to *add* new nodes rather than " |
|
1184 | 1185 | "changing them") |
|
1185 | 1186 | for node in filenodes: |
|
1186 | 1187 | if node.path in (n.path for n in self.changed): |
|
1187 | 1188 | raise NodeAlreadyChangedError( |
|
1188 | 1189 | "Node at '%s' is already marked as changed" % node.path) |
|
1189 | 1190 | self.changed.append(node) |
|
1190 | 1191 | |
|
1191 | 1192 | def remove(self, *filenodes): |
|
1192 | 1193 | """ |
|
1193 | 1194 | Marks given ``FileNode`` (or ``RemovedFileNode``) objects to be |
|
1194 | 1195 | *removed* in next commit. |
|
1195 | 1196 | |
|
1196 | 1197 | :raises ``NodeAlreadyRemovedError``: if node has been already marked to |
|
1197 | 1198 | be *removed* |
|
1198 | 1199 | :raises ``NodeAlreadyChangedError``: if node has been already marked to |
|
1199 | 1200 | be *changed* |
|
1200 | 1201 | """ |
|
1201 | 1202 | for node in filenodes: |
|
1202 | 1203 | if node.path in (n.path for n in self.removed): |
|
1203 | 1204 | raise NodeAlreadyRemovedError( |
|
1204 | 1205 | "Node is already marked to for removal at %s" % node.path) |
|
1205 | 1206 | if node.path in (n.path for n in self.changed): |
|
1206 | 1207 | raise NodeAlreadyChangedError( |
|
1207 | 1208 | "Node is already marked to be changed at %s" % node.path) |
|
1208 | 1209 | # We only mark node as *removed* - real removal is done by |
|
1209 | 1210 | # commit method |
|
1210 | 1211 | self.removed.append(node) |
|
1211 | 1212 | |
|
1212 | 1213 | def reset(self): |
|
1213 | 1214 | """ |
|
1214 | 1215 | Resets this instance to initial state (cleans ``added``, ``changed`` |
|
1215 | 1216 | and ``removed`` lists). |
|
1216 | 1217 | """ |
|
1217 | 1218 | self.added = [] |
|
1218 | 1219 | self.changed = [] |
|
1219 | 1220 | self.removed = [] |
|
1220 | 1221 | self.parents = [] |
|
1221 | 1222 | |
|
1222 | 1223 | def get_ipaths(self): |
|
1223 | 1224 | """ |
|
1224 | 1225 | Returns generator of paths from nodes marked as added, changed or |
|
1225 | 1226 | removed. |
|
1226 | 1227 | """ |
|
1227 | 1228 | for node in itertools.chain(self.added, self.changed, self.removed): |
|
1228 | 1229 | yield node.path |
|
1229 | 1230 | |
|
1230 | 1231 | def get_paths(self): |
|
1231 | 1232 | """ |
|
1232 | 1233 | Returns list of paths from nodes marked as added, changed or removed. |
|
1233 | 1234 | """ |
|
1234 | 1235 | return list(self.get_ipaths()) |
|
1235 | 1236 | |
|
1236 | 1237 | def check_integrity(self, parents=None): |
|
1237 | 1238 | """ |
|
1238 | 1239 | Checks in-memory commit's integrity. Also, sets parents if not |
|
1239 | 1240 | already set. |
|
1240 | 1241 | |
|
1241 | 1242 | :raises CommitError: if any error occurs (i.e. |
|
1242 | 1243 | ``NodeDoesNotExistError``). |
|
1243 | 1244 | """ |
|
1244 | 1245 | if not self.parents: |
|
1245 | 1246 | parents = parents or [] |
|
1246 | 1247 | if len(parents) == 0: |
|
1247 | 1248 | try: |
|
1248 | 1249 | parents = [self.repository.get_commit(), None] |
|
1249 | 1250 | except EmptyRepositoryError: |
|
1250 | 1251 | parents = [None, None] |
|
1251 | 1252 | elif len(parents) == 1: |
|
1252 | 1253 | parents += [None] |
|
1253 | 1254 | self.parents = parents |
|
1254 | 1255 | |
|
1255 | 1256 | # Local parents, only if not None |
|
1256 | 1257 | parents = [p for p in self.parents if p] |
|
1257 | 1258 | |
|
1258 | 1259 | # Check nodes marked as added |
|
1259 | 1260 | for p in parents: |
|
1260 | 1261 | for node in self.added: |
|
1261 | 1262 | try: |
|
1262 | 1263 | p.get_node(node.path) |
|
1263 | 1264 | except NodeDoesNotExistError: |
|
1264 | 1265 | pass |
|
1265 | 1266 | else: |
|
1266 | 1267 | raise NodeAlreadyExistsError( |
|
1267 | 1268 | "Node `%s` already exists at %s" % (node.path, p)) |
|
1268 | 1269 | |
|
1269 | 1270 | # Check nodes marked as changed |
|
1270 | 1271 | missing = set(self.changed) |
|
1271 | 1272 | not_changed = set(self.changed) |
|
1272 | 1273 | if self.changed and not parents: |
|
1273 | 1274 | raise NodeDoesNotExistError(str(self.changed[0].path)) |
|
1274 | 1275 | for p in parents: |
|
1275 | 1276 | for node in self.changed: |
|
1276 | 1277 | try: |
|
1277 | 1278 | old = p.get_node(node.path) |
|
1278 | 1279 | missing.remove(node) |
|
1279 | 1280 | # if content actually changed, remove node from not_changed |
|
1280 | 1281 | if old.content != node.content: |
|
1281 | 1282 | not_changed.remove(node) |
|
1282 | 1283 | except NodeDoesNotExistError: |
|
1283 | 1284 | pass |
|
1284 | 1285 | if self.changed and missing: |
|
1285 | 1286 | raise NodeDoesNotExistError( |
|
1286 | 1287 | "Node `%s` marked as modified but missing in parents: %s" |
|
1287 | 1288 | % (node.path, parents)) |
|
1288 | 1289 | |
|
1289 | 1290 | if self.changed and not_changed: |
|
1290 | 1291 | raise NodeNotChangedError( |
|
1291 | 1292 | "Node `%s` wasn't actually changed (parents: %s)" |
|
1292 | 1293 | % (not_changed.pop().path, parents)) |
|
1293 | 1294 | |
|
1294 | 1295 | # Check nodes marked as removed |
|
1295 | 1296 | if self.removed and not parents: |
|
1296 | 1297 | raise NodeDoesNotExistError( |
|
1297 | 1298 | "Cannot remove node at %s as there " |
|
1298 | 1299 | "were no parents specified" % self.removed[0].path) |
|
1299 | 1300 | really_removed = set() |
|
1300 | 1301 | for p in parents: |
|
1301 | 1302 | for node in self.removed: |
|
1302 | 1303 | try: |
|
1303 | 1304 | p.get_node(node.path) |
|
1304 | 1305 | really_removed.add(node) |
|
1305 | 1306 | except CommitError: |
|
1306 | 1307 | pass |
|
1307 | 1308 | not_removed = set(self.removed) - really_removed |
|
1308 | 1309 | if not_removed: |
|
1309 | 1310 | # TODO: johbo: This code branch does not seem to be covered |
|
1310 | 1311 | raise NodeDoesNotExistError( |
|
1311 | 1312 | "Cannot remove node at %s from " |
|
1312 | 1313 | "following parents: %s" % (not_removed, parents)) |
|
1313 | 1314 | |
|
1314 | 1315 | def commit( |
|
1315 | 1316 | self, message, author, parents=None, branch=None, date=None, |
|
1316 | 1317 | **kwargs): |
|
1317 | 1318 | """ |
|
1318 | 1319 | Performs in-memory commit (doesn't check workdir in any way) and |
|
1319 | 1320 | returns newly created :class:`BaseCommit`. Updates repository's |
|
1320 | 1321 | attribute `commits`. |
|
1321 | 1322 | |
|
1322 | 1323 | .. note:: |
|
1323 | 1324 | |
|
1324 | 1325 | While overriding this method each backend's should call |
|
1325 | 1326 | ``self.check_integrity(parents)`` in the first place. |
|
1326 | 1327 | |
|
1327 | 1328 | :param message: message of the commit |
|
1328 | 1329 | :param author: full username, i.e. "Joe Doe <joe.doe@example.com>" |
|
1329 | 1330 | :param parents: single parent or sequence of parents from which commit |
|
1330 | 1331 | would be derived |
|
1331 | 1332 | :param date: ``datetime.datetime`` instance. Defaults to |
|
1332 | 1333 | ``datetime.datetime.now()``. |
|
1333 | 1334 | :param branch: branch name, as string. If none given, default backend's |
|
1334 | 1335 | branch would be used. |
|
1335 | 1336 | |
|
1336 | 1337 | :raises ``CommitError``: if any error occurs while committing |
|
1337 | 1338 | """ |
|
1338 | 1339 | raise NotImplementedError |
|
1339 | 1340 | |
|
1340 | 1341 | |
|
1341 | 1342 | class BaseInMemoryChangesetClass(type): |
|
1342 | 1343 | |
|
1343 | 1344 | def __instancecheck__(self, instance): |
|
1344 | 1345 | return isinstance(instance, BaseInMemoryCommit) |
|
1345 | 1346 | |
|
1346 | 1347 | |
|
1347 | 1348 | class BaseInMemoryChangeset(BaseInMemoryCommit): |
|
1348 | 1349 | |
|
1349 | 1350 | __metaclass__ = BaseInMemoryChangesetClass |
|
1350 | 1351 | |
|
1351 | 1352 | def __new__(cls, *args, **kwargs): |
|
1352 | 1353 | warnings.warn( |
|
1353 | 1354 | "Use BaseCommit instead of BaseInMemoryCommit", DeprecationWarning) |
|
1354 | 1355 | return super(BaseInMemoryChangeset, cls).__new__(cls, *args, **kwargs) |
|
1355 | 1356 | |
|
1356 | 1357 | |
|
1357 | 1358 | class EmptyCommit(BaseCommit): |
|
1358 | 1359 | """ |
|
1359 | 1360 | An dummy empty commit. It's possible to pass hash when creating |
|
1360 | 1361 | an EmptyCommit |
|
1361 | 1362 | """ |
|
1362 | 1363 | |
|
1363 | 1364 | def __init__( |
|
1364 | 1365 | self, commit_id='0' * 40, repo=None, alias=None, idx=-1, |
|
1365 | 1366 | message='', author='', date=None): |
|
1366 | 1367 | self._empty_commit_id = commit_id |
|
1367 | 1368 | # TODO: johbo: Solve idx parameter, default value does not make |
|
1368 | 1369 | # too much sense |
|
1369 | 1370 | self.idx = idx |
|
1370 | 1371 | self.message = message |
|
1371 | 1372 | self.author = author |
|
1372 | 1373 | self.date = date or datetime.datetime.fromtimestamp(0) |
|
1373 | 1374 | self.repository = repo |
|
1374 | 1375 | self.alias = alias |
|
1375 | 1376 | |
|
1376 | 1377 | @LazyProperty |
|
1377 | 1378 | def raw_id(self): |
|
1378 | 1379 | """ |
|
1379 | 1380 | Returns raw string identifying this commit, useful for web |
|
1380 | 1381 | representation. |
|
1381 | 1382 | """ |
|
1382 | 1383 | |
|
1383 | 1384 | return self._empty_commit_id |
|
1384 | 1385 | |
|
1385 | 1386 | @LazyProperty |
|
1386 | 1387 | def branch(self): |
|
1387 | 1388 | if self.alias: |
|
1388 | 1389 | from rhodecode.lib.vcs.backends import get_backend |
|
1389 | 1390 | return get_backend(self.alias).DEFAULT_BRANCH_NAME |
|
1390 | 1391 | |
|
1391 | 1392 | @LazyProperty |
|
1392 | 1393 | def short_id(self): |
|
1393 | 1394 | return self.raw_id[:12] |
|
1394 | 1395 | |
|
1395 | 1396 | @LazyProperty |
|
1396 | 1397 | def id(self): |
|
1397 | 1398 | return self.raw_id |
|
1398 | 1399 | |
|
1399 | 1400 | def get_file_commit(self, path): |
|
1400 | 1401 | return self |
|
1401 | 1402 | |
|
1402 | 1403 | def get_file_content(self, path): |
|
1403 | 1404 | return u'' |
|
1404 | 1405 | |
|
1405 | 1406 | def get_file_size(self, path): |
|
1406 | 1407 | return 0 |
|
1407 | 1408 | |
|
1408 | 1409 | |
|
1409 | 1410 | class EmptyChangesetClass(type): |
|
1410 | 1411 | |
|
1411 | 1412 | def __instancecheck__(self, instance): |
|
1412 | 1413 | return isinstance(instance, EmptyCommit) |
|
1413 | 1414 | |
|
1414 | 1415 | |
|
1415 | 1416 | class EmptyChangeset(EmptyCommit): |
|
1416 | 1417 | |
|
1417 | 1418 | __metaclass__ = EmptyChangesetClass |
|
1418 | 1419 | |
|
1419 | 1420 | def __new__(cls, *args, **kwargs): |
|
1420 | 1421 | warnings.warn( |
|
1421 | 1422 | "Use EmptyCommit instead of EmptyChangeset", DeprecationWarning) |
|
1422 | 1423 | return super(EmptyCommit, cls).__new__(cls, *args, **kwargs) |
|
1423 | 1424 | |
|
1424 | 1425 | def __init__(self, cs='0' * 40, repo=None, requested_revision=None, |
|
1425 | 1426 | alias=None, revision=-1, message='', author='', date=None): |
|
1426 | 1427 | if requested_revision is not None: |
|
1427 | 1428 | warnings.warn( |
|
1428 | 1429 | "Parameter requested_revision not supported anymore", |
|
1429 | 1430 | DeprecationWarning) |
|
1430 | 1431 | super(EmptyChangeset, self).__init__( |
|
1431 | 1432 | commit_id=cs, repo=repo, alias=alias, idx=revision, |
|
1432 | 1433 | message=message, author=author, date=date) |
|
1433 | 1434 | |
|
1434 | 1435 | @property |
|
1435 | 1436 | def revision(self): |
|
1436 | 1437 | warnings.warn("Use idx instead", DeprecationWarning) |
|
1437 | 1438 | return self.idx |
|
1438 | 1439 | |
|
1439 | 1440 | @revision.setter |
|
1440 | 1441 | def revision(self, value): |
|
1441 | 1442 | warnings.warn("Use idx instead", DeprecationWarning) |
|
1442 | 1443 | self.idx = value |
|
1443 | 1444 | |
|
1444 | 1445 | |
|
1445 | 1446 | class EmptyRepository(BaseRepository): |
|
1446 | 1447 | def __init__(self, repo_path=None, config=None, create=False, **kwargs): |
|
1447 | 1448 | pass |
|
1448 | 1449 | |
|
1449 | 1450 | def get_diff(self, *args, **kwargs): |
|
1450 | 1451 | from rhodecode.lib.vcs.backends.git.diff import GitDiff |
|
1451 | 1452 | return GitDiff('') |
|
1452 | 1453 | |
|
1453 | 1454 | |
|
1454 | 1455 | class CollectionGenerator(object): |
|
1455 | 1456 | |
|
1456 | 1457 | def __init__(self, repo, commit_ids, collection_size=None, pre_load=None): |
|
1457 | 1458 | self.repo = repo |
|
1458 | 1459 | self.commit_ids = commit_ids |
|
1459 | 1460 | # TODO: (oliver) this isn't currently hooked up |
|
1460 | 1461 | self.collection_size = None |
|
1461 | 1462 | self.pre_load = pre_load |
|
1462 | 1463 | |
|
1463 | 1464 | def __len__(self): |
|
1464 | 1465 | if self.collection_size is not None: |
|
1465 | 1466 | return self.collection_size |
|
1466 | 1467 | return self.commit_ids.__len__() |
|
1467 | 1468 | |
|
1468 | 1469 | def __iter__(self): |
|
1469 | 1470 | for commit_id in self.commit_ids: |
|
1470 | 1471 | # TODO: johbo: Mercurial passes in commit indices or commit ids |
|
1471 | 1472 | yield self._commit_factory(commit_id) |
|
1472 | 1473 | |
|
1473 | 1474 | def _commit_factory(self, commit_id): |
|
1474 | 1475 | """ |
|
1475 | 1476 | Allows backends to override the way commits are generated. |
|
1476 | 1477 | """ |
|
1477 | 1478 | return self.repo.get_commit(commit_id=commit_id, |
|
1478 | 1479 | pre_load=self.pre_load) |
|
1479 | 1480 | |
|
1480 | 1481 | def __getslice__(self, i, j): |
|
1481 | 1482 | """ |
|
1482 | 1483 | Returns an iterator of sliced repository |
|
1483 | 1484 | """ |
|
1484 | 1485 | commit_ids = self.commit_ids[i:j] |
|
1485 | 1486 | return self.__class__( |
|
1486 | 1487 | self.repo, commit_ids, pre_load=self.pre_load) |
|
1487 | 1488 | |
|
1488 | 1489 | def __repr__(self): |
|
1489 | 1490 | return '<CollectionGenerator[len:%s]>' % (self.__len__()) |
|
1490 | 1491 | |
|
1491 | 1492 | |
|
1492 | 1493 | class Config(object): |
|
1493 | 1494 | """ |
|
1494 | 1495 | Represents the configuration for a repository. |
|
1495 | 1496 | |
|
1496 | 1497 | The API is inspired by :class:`ConfigParser.ConfigParser` from the |
|
1497 | 1498 | standard library. It implements only the needed subset. |
|
1498 | 1499 | """ |
|
1499 | 1500 | |
|
1500 | 1501 | def __init__(self): |
|
1501 | 1502 | self._values = {} |
|
1502 | 1503 | |
|
1503 | 1504 | def copy(self): |
|
1504 | 1505 | clone = Config() |
|
1505 | 1506 | for section, values in self._values.items(): |
|
1506 | 1507 | clone._values[section] = values.copy() |
|
1507 | 1508 | return clone |
|
1508 | 1509 | |
|
1509 | 1510 | def __repr__(self): |
|
1510 | 1511 | return '<Config(%s sections) at %s>' % ( |
|
1511 | 1512 | len(self._values), hex(id(self))) |
|
1512 | 1513 | |
|
1513 | 1514 | def items(self, section): |
|
1514 | 1515 | return self._values.get(section, {}).iteritems() |
|
1515 | 1516 | |
|
1516 | 1517 | def get(self, section, option): |
|
1517 | 1518 | return self._values.get(section, {}).get(option) |
|
1518 | 1519 | |
|
1519 | 1520 | def set(self, section, option, value): |
|
1520 | 1521 | section_values = self._values.setdefault(section, {}) |
|
1521 | 1522 | section_values[option] = value |
|
1522 | 1523 | |
|
1523 | 1524 | def clear_section(self, section): |
|
1524 | 1525 | self._values[section] = {} |
|
1525 | 1526 | |
|
1526 | 1527 | def serialize(self): |
|
1527 | 1528 | """ |
|
1528 | 1529 | Creates a list of three tuples (section, key, value) representing |
|
1529 | 1530 | this config object. |
|
1530 | 1531 | """ |
|
1531 | 1532 | items = [] |
|
1532 | 1533 | for section in self._values: |
|
1533 | 1534 | for option, value in self._values[section].items(): |
|
1534 | 1535 | items.append( |
|
1535 | 1536 | (safe_str(section), safe_str(option), safe_str(value))) |
|
1536 | 1537 | return items |
|
1537 | 1538 | |
|
1538 | 1539 | |
|
1539 | 1540 | class Diff(object): |
|
1540 | 1541 | """ |
|
1541 | 1542 | Represents a diff result from a repository backend. |
|
1542 | 1543 | |
|
1543 |
Subclasses have to provide a backend specific value for |
|
|
1544 | Subclasses have to provide a backend specific value for | |
|
1545 | :attr:`_header_re` and :attr:`_meta_re`. | |
|
1544 | 1546 | """ |
|
1545 | ||
|
1547 | _meta_re = None | |
|
1546 | 1548 | _header_re = None |
|
1547 | 1549 | |
|
1548 | 1550 | def __init__(self, raw_diff): |
|
1549 | 1551 | self.raw = raw_diff |
|
1550 | 1552 | |
|
1551 | 1553 | def chunks(self): |
|
1552 | 1554 | """ |
|
1553 | 1555 | split the diff in chunks of separate --git a/file b/file chunks |
|
1554 | 1556 | to make diffs consistent we must prepend with \n, and make sure |
|
1555 | 1557 | we can detect last chunk as this was also has special rule |
|
1556 | 1558 | """ |
|
1557 | chunks = ('\n' + self.raw).split('\ndiff --git')[1:] | |
|
1559 | ||
|
1560 | diff_parts = ('\n' + self.raw).split('\ndiff --git') | |
|
1561 | header = diff_parts[0] | |
|
1562 | ||
|
1563 | if self._meta_re: | |
|
1564 | match = self._meta_re.match(header) | |
|
1565 | ||
|
1566 | chunks = diff_parts[1:] | |
|
1558 | 1567 | total_chunks = len(chunks) |
|
1559 | return (DiffChunk(chunk, self, cur_chunk == total_chunks) | |
|
1560 | for cur_chunk, chunk in enumerate(chunks, start=1)) | |
|
1568 | ||
|
1569 | return ( | |
|
1570 | DiffChunk(chunk, self, cur_chunk == total_chunks) | |
|
1571 | for cur_chunk, chunk in enumerate(chunks, start=1)) | |
|
1561 | 1572 | |
|
1562 | 1573 | |
|
1563 | 1574 | class DiffChunk(object): |
|
1564 | 1575 | |
|
1565 | 1576 | def __init__(self, chunk, diff, last_chunk): |
|
1566 | 1577 | self._diff = diff |
|
1567 | 1578 | |
|
1568 | 1579 | # since we split by \ndiff --git that part is lost from original diff |
|
1569 | 1580 | # we need to re-apply it at the end, EXCEPT ! if it's last chunk |
|
1570 | 1581 | if not last_chunk: |
|
1571 | 1582 | chunk += '\n' |
|
1572 | 1583 | |
|
1573 | 1584 | match = self._diff._header_re.match(chunk) |
|
1574 | 1585 | self.header = match.groupdict() |
|
1575 | 1586 | self.diff = chunk[match.end():] |
|
1576 | 1587 | self.raw = chunk |
@@ -1,48 +1,52 b'' | |||
|
1 | 1 | # -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | # Copyright (C) 2014-2016 RhodeCode GmbH |
|
4 | 4 | # |
|
5 | 5 | # This program is free software: you can redistribute it and/or modify |
|
6 | 6 | # it under the terms of the GNU Affero General Public License, version 3 |
|
7 | 7 | # (only), as published by the Free Software Foundation. |
|
8 | 8 | # |
|
9 | 9 | # This program is distributed in the hope that it will be useful, |
|
10 | 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
11 | 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
12 | 12 | # GNU General Public License for more details. |
|
13 | 13 | # |
|
14 | 14 | # You should have received a copy of the GNU Affero General Public License |
|
15 | 15 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
16 | 16 | # |
|
17 | 17 | # This program is dual-licensed. If you wish to learn more about the |
|
18 | 18 | # RhodeCode Enterprise Edition, including its added features, Support services, |
|
19 | 19 | # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
20 | 20 | |
|
21 | 21 | |
|
22 | 22 | """ |
|
23 | 23 | SVN diff module |
|
24 | 24 | """ |
|
25 | 25 | |
|
26 | 26 | import re |
|
27 | 27 | |
|
28 | 28 | from rhodecode.lib.vcs.backends import base |
|
29 | 29 | |
|
30 | 30 | |
|
31 | 31 | class SubversionDiff(base.Diff): |
|
32 | 32 | |
|
33 | _meta_re = re.compile(r""" | |
|
34 | (?:^(?P<svn_bin_patch>Cannot[ ]display:[ ]file[ ]marked[ ]as[ ]a[ ]binary[ ]type.)(?:\n|$))? | |
|
35 | """, re.VERBOSE | re.MULTILINE) | |
|
36 | ||
|
33 | 37 | _header_re = re.compile(r""" |
|
34 | 38 | #^diff[ ]--git |
|
35 | 39 | [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n |
|
36 | 40 | (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n |
|
37 | 41 | ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n |
|
38 | 42 | ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))? |
|
39 | 43 | (?:^old[ ]mode[ ](?P<old_mode>\d+)\n |
|
40 | 44 | ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))? |
|
41 | 45 | (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))? |
|
42 | 46 | (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))? |
|
43 | 47 | (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+) |
|
44 | 48 | \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))? |
|
45 | 49 | (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))? |
|
46 | 50 | (?:^---[ ](a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))? |
|
47 | 51 | (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))? |
|
48 | 52 | """, re.VERBOSE | re.MULTILINE) |
@@ -1,2216 +1,2217 b'' | |||
|
1 | 1 | //Primary CSS |
|
2 | 2 | |
|
3 | 3 | //--- IMPORTS ------------------// |
|
4 | 4 | |
|
5 | 5 | @import 'helpers'; |
|
6 | 6 | @import 'mixins'; |
|
7 | 7 | @import 'rcicons'; |
|
8 | 8 | @import 'fonts'; |
|
9 | 9 | @import 'variables'; |
|
10 | 10 | @import 'bootstrap-variables'; |
|
11 | 11 | @import 'form-bootstrap'; |
|
12 | 12 | @import 'codemirror'; |
|
13 | 13 | @import 'legacy_code_styles'; |
|
14 | 14 | @import 'progress-bar'; |
|
15 | 15 | |
|
16 | 16 | @import 'type'; |
|
17 | 17 | @import 'alerts'; |
|
18 | 18 | @import 'buttons'; |
|
19 | 19 | @import 'tags'; |
|
20 | 20 | @import 'code-block'; |
|
21 | 21 | @import 'examples'; |
|
22 | 22 | @import 'login'; |
|
23 | 23 | @import 'main-content'; |
|
24 | 24 | @import 'select2'; |
|
25 | 25 | @import 'comments'; |
|
26 | 26 | @import 'panels-bootstrap'; |
|
27 | 27 | @import 'panels'; |
|
28 | 28 | @import 'deform'; |
|
29 | 29 | |
|
30 | 30 | //--- BASE ------------------// |
|
31 | 31 | .noscript-error { |
|
32 | 32 | top: 0; |
|
33 | 33 | left: 0; |
|
34 | 34 | width: 100%; |
|
35 | 35 | z-index: 101; |
|
36 | 36 | text-align: center; |
|
37 | 37 | font-family: @text-semibold; |
|
38 | 38 | font-size: 120%; |
|
39 | 39 | color: white; |
|
40 | 40 | background-color: @alert2; |
|
41 | 41 | padding: 5px 0 5px 0; |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | html { |
|
45 | 45 | display: table; |
|
46 | 46 | height: 100%; |
|
47 | 47 | width: 100%; |
|
48 | 48 | } |
|
49 | 49 | |
|
50 | 50 | body { |
|
51 | 51 | display: table-cell; |
|
52 | 52 | width: 100%; |
|
53 | 53 | } |
|
54 | 54 | |
|
55 | 55 | //--- LAYOUT ------------------// |
|
56 | 56 | |
|
57 | 57 | .hidden{ |
|
58 | 58 | display: none !important; |
|
59 | 59 | } |
|
60 | 60 | |
|
61 | 61 | .box{ |
|
62 | 62 | float: left; |
|
63 | 63 | width: 100%; |
|
64 | 64 | } |
|
65 | 65 | |
|
66 | 66 | .browser-header { |
|
67 | 67 | clear: both; |
|
68 | 68 | } |
|
69 | 69 | .main { |
|
70 | 70 | clear: both; |
|
71 | 71 | padding:0 0 @pagepadding; |
|
72 | 72 | height: auto; |
|
73 | 73 | |
|
74 | 74 | &:after { //clearfix |
|
75 | 75 | content:""; |
|
76 | 76 | clear:both; |
|
77 | 77 | width:100%; |
|
78 | 78 | display:block; |
|
79 | 79 | } |
|
80 | 80 | } |
|
81 | 81 | |
|
82 | 82 | .action-link{ |
|
83 | 83 | margin-left: @padding; |
|
84 | 84 | padding-left: @padding; |
|
85 | 85 | border-left: @border-thickness solid @border-default-color; |
|
86 | 86 | } |
|
87 | 87 | |
|
88 | 88 | input + .action-link, .action-link.first{ |
|
89 | 89 | border-left: none; |
|
90 | 90 | } |
|
91 | 91 | |
|
92 | 92 | .action-link.last{ |
|
93 | 93 | margin-right: @padding; |
|
94 | 94 | padding-right: @padding; |
|
95 | 95 | } |
|
96 | 96 | |
|
97 | 97 | .action-link.active, |
|
98 | 98 | .action-link.active a{ |
|
99 | 99 | color: @grey4; |
|
100 | 100 | } |
|
101 | 101 | |
|
102 | 102 | ul.simple-list{ |
|
103 | 103 | list-style: none; |
|
104 | 104 | margin: 0; |
|
105 | 105 | padding: 0; |
|
106 | 106 | } |
|
107 | 107 | |
|
108 | 108 | .main-content { |
|
109 | 109 | padding-bottom: @pagepadding; |
|
110 | 110 | } |
|
111 | 111 | |
|
112 | 112 | .wide-mode-wrapper { |
|
113 | 113 | max-width:2400px !important; |
|
114 | 114 | } |
|
115 | 115 | |
|
116 | 116 | .wrapper { |
|
117 | 117 | position: relative; |
|
118 | 118 | max-width: @wrapper-maxwidth; |
|
119 | 119 | margin: 0 auto; |
|
120 | 120 | } |
|
121 | 121 | |
|
122 | 122 | #content { |
|
123 | 123 | clear: both; |
|
124 | 124 | padding: 0 @contentpadding; |
|
125 | 125 | } |
|
126 | 126 | |
|
127 | 127 | .advanced-settings-fields{ |
|
128 | 128 | input{ |
|
129 | 129 | margin-left: @textmargin; |
|
130 | 130 | margin-right: @padding/2; |
|
131 | 131 | } |
|
132 | 132 | } |
|
133 | 133 | |
|
134 | 134 | .cs_files_title { |
|
135 | 135 | margin: @pagepadding 0 0; |
|
136 | 136 | } |
|
137 | 137 | |
|
138 | 138 | input.inline[type="file"] { |
|
139 | 139 | display: inline; |
|
140 | 140 | } |
|
141 | 141 | |
|
142 | 142 | .error_page { |
|
143 | 143 | margin: 10% auto; |
|
144 | 144 | |
|
145 | 145 | h1 { |
|
146 | 146 | color: @grey2; |
|
147 | 147 | } |
|
148 | 148 | |
|
149 | 149 | .alert { |
|
150 | 150 | margin: @padding 0; |
|
151 | 151 | } |
|
152 | 152 | |
|
153 | 153 | .error-branding { |
|
154 | 154 | font-family: @text-semibold; |
|
155 | 155 | color: @grey4; |
|
156 | 156 | } |
|
157 | 157 | |
|
158 | 158 | .error_message { |
|
159 | 159 | font-family: @text-regular; |
|
160 | 160 | } |
|
161 | 161 | |
|
162 | 162 | .sidebar { |
|
163 | 163 | min-height: 275px; |
|
164 | 164 | margin: 0; |
|
165 | 165 | padding: 0 0 @sidebarpadding @sidebarpadding; |
|
166 | 166 | border: none; |
|
167 | 167 | } |
|
168 | 168 | |
|
169 | 169 | .main-content { |
|
170 | 170 | position: relative; |
|
171 | 171 | margin: 0 @sidebarpadding @sidebarpadding; |
|
172 | 172 | padding: 0 0 0 @sidebarpadding; |
|
173 | 173 | border-left: @border-thickness solid @grey5; |
|
174 | 174 | |
|
175 | 175 | @media (max-width:767px) { |
|
176 | 176 | clear: both; |
|
177 | 177 | width: 100%; |
|
178 | 178 | margin: 0; |
|
179 | 179 | border: none; |
|
180 | 180 | } |
|
181 | 181 | } |
|
182 | 182 | |
|
183 | 183 | .inner-column { |
|
184 | 184 | float: left; |
|
185 | 185 | width: 29.75%; |
|
186 | 186 | min-height: 150px; |
|
187 | 187 | margin: @sidebarpadding 2% 0 0; |
|
188 | 188 | padding: 0 2% 0 0; |
|
189 | 189 | border-right: @border-thickness solid @grey5; |
|
190 | 190 | |
|
191 | 191 | @media (max-width:767px) { |
|
192 | 192 | clear: both; |
|
193 | 193 | width: 100%; |
|
194 | 194 | border: none; |
|
195 | 195 | } |
|
196 | 196 | |
|
197 | 197 | ul { |
|
198 | 198 | padding-left: 1.25em; |
|
199 | 199 | } |
|
200 | 200 | |
|
201 | 201 | &:last-child { |
|
202 | 202 | margin: @sidebarpadding 0 0; |
|
203 | 203 | border: none; |
|
204 | 204 | } |
|
205 | 205 | |
|
206 | 206 | h4 { |
|
207 | 207 | margin: 0 0 @padding; |
|
208 | 208 | font-family: @text-semibold; |
|
209 | 209 | } |
|
210 | 210 | } |
|
211 | 211 | } |
|
212 | 212 | .error-page-logo { |
|
213 | 213 | width: 130px; |
|
214 | 214 | height: 160px; |
|
215 | 215 | } |
|
216 | 216 | |
|
217 | 217 | // HEADER |
|
218 | 218 | .header { |
|
219 | 219 | |
|
220 | 220 | // TODO: johbo: Fix login pages, so that they work without a min-height |
|
221 | 221 | // for the header and then remove the min-height. I chose a smaller value |
|
222 | 222 | // intentionally here to avoid rendering issues in the main navigation. |
|
223 | 223 | min-height: 49px; |
|
224 | 224 | |
|
225 | 225 | position: relative; |
|
226 | 226 | vertical-align: bottom; |
|
227 | 227 | padding: 0 @header-padding; |
|
228 | 228 | background-color: @grey2; |
|
229 | 229 | color: @grey5; |
|
230 | 230 | |
|
231 | 231 | .title { |
|
232 | 232 | overflow: visible; |
|
233 | 233 | } |
|
234 | 234 | |
|
235 | 235 | &:before, |
|
236 | 236 | &:after { |
|
237 | 237 | content: ""; |
|
238 | 238 | clear: both; |
|
239 | 239 | width: 100%; |
|
240 | 240 | } |
|
241 | 241 | |
|
242 | 242 | // TODO: johbo: Avoids breaking "Repositories" chooser |
|
243 | 243 | .select2-container .select2-choice .select2-arrow { |
|
244 | 244 | display: none; |
|
245 | 245 | } |
|
246 | 246 | } |
|
247 | 247 | |
|
248 | 248 | #header-inner { |
|
249 | 249 | &.title { |
|
250 | 250 | margin: 0; |
|
251 | 251 | } |
|
252 | 252 | &:before, |
|
253 | 253 | &:after { |
|
254 | 254 | content: ""; |
|
255 | 255 | clear: both; |
|
256 | 256 | } |
|
257 | 257 | } |
|
258 | 258 | |
|
259 | 259 | // Gists |
|
260 | 260 | #files_data { |
|
261 | 261 | clear: both; //for firefox |
|
262 | 262 | } |
|
263 | 263 | #gistid { |
|
264 | 264 | margin-right: @padding; |
|
265 | 265 | } |
|
266 | 266 | |
|
267 | 267 | // Global Settings Editor |
|
268 | 268 | .textarea.editor { |
|
269 | 269 | float: left; |
|
270 | 270 | position: relative; |
|
271 | 271 | max-width: @texteditor-width; |
|
272 | 272 | |
|
273 | 273 | select { |
|
274 | 274 | position: absolute; |
|
275 | 275 | top:10px; |
|
276 | 276 | right:0; |
|
277 | 277 | } |
|
278 | 278 | |
|
279 | 279 | .CodeMirror { |
|
280 | 280 | margin: 0; |
|
281 | 281 | } |
|
282 | 282 | |
|
283 | 283 | .help-block { |
|
284 | 284 | margin: 0 0 @padding; |
|
285 | 285 | padding:.5em; |
|
286 | 286 | background-color: @grey6; |
|
287 | 287 | } |
|
288 | 288 | } |
|
289 | 289 | |
|
290 | 290 | ul.auth_plugins { |
|
291 | 291 | margin: @padding 0 @padding @legend-width; |
|
292 | 292 | padding: 0; |
|
293 | 293 | |
|
294 | 294 | li { |
|
295 | 295 | margin-bottom: @padding; |
|
296 | 296 | line-height: 1em; |
|
297 | 297 | list-style-type: none; |
|
298 | 298 | |
|
299 | 299 | .auth_buttons .btn { |
|
300 | 300 | margin-right: @padding; |
|
301 | 301 | } |
|
302 | 302 | |
|
303 | 303 | &:before { content: none; } |
|
304 | 304 | } |
|
305 | 305 | } |
|
306 | 306 | |
|
307 | 307 | |
|
308 | 308 | // My Account PR list |
|
309 | 309 | |
|
310 | 310 | #show_closed { |
|
311 | 311 | margin: 0 1em 0 0; |
|
312 | 312 | } |
|
313 | 313 | |
|
314 | 314 | .pullrequestlist { |
|
315 | 315 | .closed { |
|
316 | 316 | background-color: @grey6; |
|
317 | 317 | } |
|
318 | 318 | .td-status { |
|
319 | 319 | padding-left: .5em; |
|
320 | 320 | } |
|
321 | 321 | .log-container .truncate { |
|
322 | 322 | height: 2.75em; |
|
323 | 323 | white-space: pre-line; |
|
324 | 324 | } |
|
325 | 325 | table.rctable .user { |
|
326 | 326 | padding-left: 0; |
|
327 | 327 | } |
|
328 | 328 | table.rctable { |
|
329 | 329 | td.td-description, |
|
330 | 330 | .rc-user { |
|
331 | 331 | min-width: auto; |
|
332 | 332 | } |
|
333 | 333 | } |
|
334 | 334 | } |
|
335 | 335 | |
|
336 | 336 | // Pull Requests |
|
337 | 337 | |
|
338 | 338 | .pullrequests_section_head { |
|
339 | 339 | display: block; |
|
340 | 340 | clear: both; |
|
341 | 341 | margin: @padding 0; |
|
342 | 342 | font-family: @text-bold; |
|
343 | 343 | } |
|
344 | 344 | |
|
345 | 345 | .pr-origininfo, .pr-targetinfo { |
|
346 | 346 | position: relative; |
|
347 | 347 | |
|
348 | 348 | .tag { |
|
349 | 349 | display: inline-block; |
|
350 | 350 | margin: 0 1em .5em 0; |
|
351 | 351 | } |
|
352 | 352 | |
|
353 | 353 | .clone-url { |
|
354 | 354 | display: inline-block; |
|
355 | 355 | margin: 0 0 .5em 0; |
|
356 | 356 | padding: 0; |
|
357 | 357 | line-height: 1.2em; |
|
358 | 358 | } |
|
359 | 359 | } |
|
360 | 360 | |
|
361 | 361 | .pr-pullinfo { |
|
362 | 362 | clear: both; |
|
363 | 363 | margin: .5em 0; |
|
364 | 364 | } |
|
365 | 365 | |
|
366 | 366 | #pr-title-input { |
|
367 | 367 | width: 72%; |
|
368 | 368 | font-size: 1em; |
|
369 | 369 | font-family: @text-bold; |
|
370 | 370 | margin: 0; |
|
371 | 371 | padding: 0 0 0 @padding/4; |
|
372 | 372 | line-height: 1.7em; |
|
373 | 373 | color: @text-color; |
|
374 | 374 | letter-spacing: .02em; |
|
375 | 375 | } |
|
376 | 376 | |
|
377 | 377 | #pullrequest_title { |
|
378 | 378 | width: 100%; |
|
379 | 379 | box-sizing: border-box; |
|
380 | 380 | } |
|
381 | 381 | |
|
382 | 382 | #pr_open_message { |
|
383 | 383 | border: @border-thickness solid #fff; |
|
384 | 384 | border-radius: @border-radius; |
|
385 | 385 | padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0; |
|
386 | 386 | text-align: right; |
|
387 | 387 | overflow: hidden; |
|
388 | 388 | } |
|
389 | 389 | |
|
390 | 390 | .pr-submit-button { |
|
391 | 391 | float: right; |
|
392 | 392 | margin: 0 0 0 5px; |
|
393 | 393 | } |
|
394 | 394 | |
|
395 | 395 | .pr-spacing-container { |
|
396 | 396 | padding: 20px; |
|
397 | 397 | clear: both |
|
398 | 398 | } |
|
399 | 399 | |
|
400 | 400 | #pr-description-input { |
|
401 | 401 | margin-bottom: 0; |
|
402 | 402 | } |
|
403 | 403 | |
|
404 | 404 | .pr-description-label { |
|
405 | 405 | vertical-align: top; |
|
406 | 406 | } |
|
407 | 407 | |
|
408 | 408 | .perms_section_head { |
|
409 | 409 | min-width: 625px; |
|
410 | 410 | |
|
411 | 411 | h2 { |
|
412 | 412 | margin-bottom: 0; |
|
413 | 413 | } |
|
414 | 414 | |
|
415 | 415 | .label-checkbox { |
|
416 | 416 | float: left; |
|
417 | 417 | } |
|
418 | 418 | |
|
419 | 419 | &.field { |
|
420 | 420 | margin: @space 0 @padding; |
|
421 | 421 | } |
|
422 | 422 | |
|
423 | 423 | &:first-child.field { |
|
424 | 424 | margin-top: 0; |
|
425 | 425 | |
|
426 | 426 | .label { |
|
427 | 427 | margin-top: 0; |
|
428 | 428 | padding-top: 0; |
|
429 | 429 | } |
|
430 | 430 | |
|
431 | 431 | .radios { |
|
432 | 432 | padding-top: 0; |
|
433 | 433 | } |
|
434 | 434 | } |
|
435 | 435 | |
|
436 | 436 | .radios { |
|
437 | 437 | float: right; |
|
438 | 438 | position: relative; |
|
439 | 439 | width: 405px; |
|
440 | 440 | } |
|
441 | 441 | } |
|
442 | 442 | |
|
443 | 443 | //--- MODULES ------------------// |
|
444 | 444 | |
|
445 | 445 | |
|
446 | 446 | // Server Announcement |
|
447 | 447 | #server-announcement { |
|
448 | 448 | width: 95%; |
|
449 | 449 | margin: @padding auto; |
|
450 | 450 | padding: @padding; |
|
451 | 451 | border-width: 2px; |
|
452 | 452 | border-style: solid; |
|
453 | 453 | .border-radius(2px); |
|
454 | 454 | font-family: @text-bold; |
|
455 | 455 | |
|
456 | 456 | &.info { border-color: @alert4; background-color: @alert4-inner; } |
|
457 | 457 | &.warning { border-color: @alert3; background-color: @alert3-inner; } |
|
458 | 458 | &.error { border-color: @alert2; background-color: @alert2-inner; } |
|
459 | 459 | &.success { border-color: @alert1; background-color: @alert1-inner; } |
|
460 | 460 | &.neutral { border-color: @grey3; background-color: @grey6; } |
|
461 | 461 | } |
|
462 | 462 | |
|
463 | 463 | // Fixed Sidebar Column |
|
464 | 464 | .sidebar-col-wrapper { |
|
465 | 465 | padding-left: @sidebar-all-width; |
|
466 | 466 | |
|
467 | 467 | .sidebar { |
|
468 | 468 | width: @sidebar-width; |
|
469 | 469 | margin-left: -@sidebar-all-width; |
|
470 | 470 | } |
|
471 | 471 | } |
|
472 | 472 | |
|
473 | 473 | .sidebar-col-wrapper.scw-small { |
|
474 | 474 | padding-left: @sidebar-small-all-width; |
|
475 | 475 | |
|
476 | 476 | .sidebar { |
|
477 | 477 | width: @sidebar-small-width; |
|
478 | 478 | margin-left: -@sidebar-small-all-width; |
|
479 | 479 | } |
|
480 | 480 | } |
|
481 | 481 | |
|
482 | 482 | |
|
483 | 483 | // FOOTER |
|
484 | 484 | #footer { |
|
485 | 485 | padding: 0; |
|
486 | 486 | text-align: center; |
|
487 | 487 | vertical-align: middle; |
|
488 | 488 | color: @grey2; |
|
489 | 489 | background-color: @grey6; |
|
490 | 490 | |
|
491 | 491 | p { |
|
492 | 492 | margin: 0; |
|
493 | 493 | padding: 1em; |
|
494 | 494 | line-height: 1em; |
|
495 | 495 | } |
|
496 | 496 | |
|
497 | 497 | .server-instance { //server instance |
|
498 | 498 | display: none; |
|
499 | 499 | } |
|
500 | 500 | |
|
501 | 501 | .title { |
|
502 | 502 | float: none; |
|
503 | 503 | margin: 0 auto; |
|
504 | 504 | } |
|
505 | 505 | } |
|
506 | 506 | |
|
507 | 507 | button.close { |
|
508 | 508 | padding: 0; |
|
509 | 509 | cursor: pointer; |
|
510 | 510 | background: transparent; |
|
511 | 511 | border: 0; |
|
512 | 512 | .box-shadow(none); |
|
513 | 513 | -webkit-appearance: none; |
|
514 | 514 | } |
|
515 | 515 | |
|
516 | 516 | .close { |
|
517 | 517 | float: right; |
|
518 | 518 | font-size: 21px; |
|
519 | 519 | font-family: @text-bootstrap; |
|
520 | 520 | line-height: 1em; |
|
521 | 521 | font-weight: bold; |
|
522 | 522 | color: @grey2; |
|
523 | 523 | |
|
524 | 524 | &:hover, |
|
525 | 525 | &:focus { |
|
526 | 526 | color: @grey1; |
|
527 | 527 | text-decoration: none; |
|
528 | 528 | cursor: pointer; |
|
529 | 529 | } |
|
530 | 530 | } |
|
531 | 531 | |
|
532 | 532 | // GRID |
|
533 | 533 | .sorting, |
|
534 | 534 | .sorting_desc, |
|
535 | 535 | .sorting_asc { |
|
536 | 536 | cursor: pointer; |
|
537 | 537 | } |
|
538 | 538 | .sorting_desc:after { |
|
539 | 539 | content: "\00A0\25B2"; |
|
540 | 540 | font-size: .75em; |
|
541 | 541 | } |
|
542 | 542 | .sorting_asc:after { |
|
543 | 543 | content: "\00A0\25BC"; |
|
544 | 544 | font-size: .68em; |
|
545 | 545 | } |
|
546 | 546 | |
|
547 | 547 | |
|
548 | 548 | .user_auth_tokens { |
|
549 | 549 | |
|
550 | 550 | &.truncate { |
|
551 | 551 | white-space: nowrap; |
|
552 | 552 | overflow: hidden; |
|
553 | 553 | text-overflow: ellipsis; |
|
554 | 554 | } |
|
555 | 555 | |
|
556 | 556 | .fields .field .input { |
|
557 | 557 | margin: 0; |
|
558 | 558 | } |
|
559 | 559 | |
|
560 | 560 | input#description { |
|
561 | 561 | width: 100px; |
|
562 | 562 | margin: 0; |
|
563 | 563 | } |
|
564 | 564 | |
|
565 | 565 | .drop-menu { |
|
566 | 566 | // TODO: johbo: Remove this, should work out of the box when |
|
567 | 567 | // having multiple inputs inline |
|
568 | 568 | margin: 0 0 0 5px; |
|
569 | 569 | } |
|
570 | 570 | } |
|
571 | 571 | #user_list_table { |
|
572 | 572 | .closed { |
|
573 | 573 | background-color: @grey6; |
|
574 | 574 | } |
|
575 | 575 | } |
|
576 | 576 | |
|
577 | 577 | |
|
578 | 578 | input { |
|
579 | 579 | &.disabled { |
|
580 | 580 | opacity: .5; |
|
581 | 581 | } |
|
582 | 582 | } |
|
583 | 583 | |
|
584 | 584 | // remove extra padding in firefox |
|
585 | 585 | input::-moz-focus-inner { border:0; padding:0 } |
|
586 | 586 | |
|
587 | 587 | .adjacent input { |
|
588 | 588 | margin-bottom: @padding; |
|
589 | 589 | } |
|
590 | 590 | |
|
591 | 591 | .permissions_boxes { |
|
592 | 592 | display: block; |
|
593 | 593 | } |
|
594 | 594 | |
|
595 | 595 | //TODO: lisa: this should be in tables |
|
596 | 596 | .show_more_col { |
|
597 | 597 | width: 20px; |
|
598 | 598 | } |
|
599 | 599 | |
|
600 | 600 | //FORMS |
|
601 | 601 | |
|
602 | 602 | .medium-inline, |
|
603 | 603 | input#description.medium-inline { |
|
604 | 604 | display: inline; |
|
605 | 605 | width: @medium-inline-input-width; |
|
606 | 606 | min-width: 100px; |
|
607 | 607 | } |
|
608 | 608 | |
|
609 | 609 | select { |
|
610 | 610 | //reset |
|
611 | 611 | -webkit-appearance: none; |
|
612 | 612 | -moz-appearance: none; |
|
613 | 613 | |
|
614 | 614 | display: inline-block; |
|
615 | 615 | height: 28px; |
|
616 | 616 | width: auto; |
|
617 | 617 | margin: 0 @padding @padding 0; |
|
618 | 618 | padding: 0 18px 0 8px; |
|
619 | 619 | line-height:1em; |
|
620 | 620 | font-size: @basefontsize; |
|
621 | 621 | border: @border-thickness solid @rcblue; |
|
622 | 622 | background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%; |
|
623 | 623 | color: @rcblue; |
|
624 | 624 | |
|
625 | 625 | &:after { |
|
626 | 626 | content: "\00A0\25BE"; |
|
627 | 627 | } |
|
628 | 628 | |
|
629 | 629 | &:focus { |
|
630 | 630 | outline: none; |
|
631 | 631 | } |
|
632 | 632 | } |
|
633 | 633 | |
|
634 | 634 | option { |
|
635 | 635 | &:focus { |
|
636 | 636 | outline: none; |
|
637 | 637 | } |
|
638 | 638 | } |
|
639 | 639 | |
|
640 | 640 | input, |
|
641 | 641 | textarea { |
|
642 | 642 | padding: @input-padding; |
|
643 | 643 | border: @input-border-thickness solid @border-highlight-color; |
|
644 | 644 | .border-radius (@border-radius); |
|
645 | 645 | font-family: @text-light; |
|
646 | 646 | font-size: @basefontsize; |
|
647 | 647 | |
|
648 | 648 | &.input-sm { |
|
649 | 649 | padding: 5px; |
|
650 | 650 | } |
|
651 | 651 | |
|
652 | 652 | &#description { |
|
653 | 653 | min-width: @input-description-minwidth; |
|
654 | 654 | min-height: 1em; |
|
655 | 655 | padding: 10px; |
|
656 | 656 | } |
|
657 | 657 | } |
|
658 | 658 | |
|
659 | 659 | .field-sm { |
|
660 | 660 | input, |
|
661 | 661 | textarea { |
|
662 | 662 | padding: 5px; |
|
663 | 663 | } |
|
664 | 664 | } |
|
665 | 665 | |
|
666 | 666 | textarea { |
|
667 | 667 | display: block; |
|
668 | 668 | clear: both; |
|
669 | 669 | width: 100%; |
|
670 | 670 | min-height: 100px; |
|
671 | 671 | margin-bottom: @padding; |
|
672 | 672 | .box-sizing(border-box); |
|
673 | 673 | overflow: auto; |
|
674 | 674 | } |
|
675 | 675 | |
|
676 | 676 | label { |
|
677 | 677 | font-family: @text-light; |
|
678 | 678 | } |
|
679 | 679 | |
|
680 | 680 | // GRAVATARS |
|
681 | 681 | // centers gravatar on username to the right |
|
682 | 682 | |
|
683 | 683 | .gravatar { |
|
684 | 684 | display: inline; |
|
685 | 685 | min-width: 16px; |
|
686 | 686 | min-height: 16px; |
|
687 | 687 | margin: -5px 0; |
|
688 | 688 | padding: 0; |
|
689 | 689 | line-height: 1em; |
|
690 | 690 | border: 1px solid @grey4; |
|
691 | 691 | |
|
692 | 692 | &.gravatar-large { |
|
693 | 693 | margin: -0.5em .25em -0.5em 0; |
|
694 | 694 | } |
|
695 | 695 | |
|
696 | 696 | & + .user { |
|
697 | 697 | display: inline; |
|
698 | 698 | margin: 0; |
|
699 | 699 | padding: 0 0 0 .17em; |
|
700 | 700 | line-height: 1em; |
|
701 | 701 | } |
|
702 | 702 | } |
|
703 | 703 | |
|
704 | 704 | .user-inline-data { |
|
705 | 705 | display: inline-block; |
|
706 | 706 | float: left; |
|
707 | 707 | padding-left: .5em; |
|
708 | 708 | line-height: 1.3em; |
|
709 | 709 | } |
|
710 | 710 | |
|
711 | 711 | .rc-user { // gravatar + user wrapper |
|
712 | 712 | float: left; |
|
713 | 713 | position: relative; |
|
714 | 714 | min-width: 100px; |
|
715 | 715 | max-width: 200px; |
|
716 | 716 | min-height: (@gravatar-size + @border-thickness * 2); // account for border |
|
717 | 717 | display: block; |
|
718 | 718 | padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2); |
|
719 | 719 | |
|
720 | 720 | |
|
721 | 721 | .gravatar { |
|
722 | 722 | display: block; |
|
723 | 723 | position: absolute; |
|
724 | 724 | top: 0; |
|
725 | 725 | left: 0; |
|
726 | 726 | min-width: @gravatar-size; |
|
727 | 727 | min-height: @gravatar-size; |
|
728 | 728 | margin: 0; |
|
729 | 729 | } |
|
730 | 730 | |
|
731 | 731 | .user { |
|
732 | 732 | display: block; |
|
733 | 733 | max-width: 175px; |
|
734 | 734 | padding-top: 2px; |
|
735 | 735 | overflow: hidden; |
|
736 | 736 | text-overflow: ellipsis; |
|
737 | 737 | } |
|
738 | 738 | } |
|
739 | 739 | |
|
740 | 740 | .gist-gravatar, |
|
741 | 741 | .journal_container { |
|
742 | 742 | .gravatar-large { |
|
743 | 743 | margin: 0 .5em -10px 0; |
|
744 | 744 | } |
|
745 | 745 | } |
|
746 | 746 | |
|
747 | 747 | |
|
748 | 748 | // ADMIN SETTINGS |
|
749 | 749 | |
|
750 | 750 | // Tag Patterns |
|
751 | 751 | .tag_patterns { |
|
752 | 752 | .tag_input { |
|
753 | 753 | margin-bottom: @padding; |
|
754 | 754 | } |
|
755 | 755 | } |
|
756 | 756 | |
|
757 | 757 | .locked_input { |
|
758 | 758 | position: relative; |
|
759 | 759 | |
|
760 | 760 | input { |
|
761 | 761 | display: inline; |
|
762 | 762 | margin-top: 3px; |
|
763 | 763 | } |
|
764 | 764 | |
|
765 | 765 | br { |
|
766 | 766 | display: none; |
|
767 | 767 | } |
|
768 | 768 | |
|
769 | 769 | .error-message { |
|
770 | 770 | float: left; |
|
771 | 771 | width: 100%; |
|
772 | 772 | } |
|
773 | 773 | |
|
774 | 774 | .lock_input_button { |
|
775 | 775 | display: inline; |
|
776 | 776 | } |
|
777 | 777 | |
|
778 | 778 | .help-block { |
|
779 | 779 | clear: both; |
|
780 | 780 | } |
|
781 | 781 | } |
|
782 | 782 | |
|
783 | 783 | // Notifications |
|
784 | 784 | |
|
785 | 785 | .notifications_buttons { |
|
786 | 786 | margin: 0 0 @space 0; |
|
787 | 787 | padding: 0; |
|
788 | 788 | |
|
789 | 789 | .btn { |
|
790 | 790 | display: inline-block; |
|
791 | 791 | } |
|
792 | 792 | } |
|
793 | 793 | |
|
794 | 794 | .notification-list { |
|
795 | 795 | |
|
796 | 796 | div { |
|
797 | 797 | display: inline-block; |
|
798 | 798 | vertical-align: middle; |
|
799 | 799 | } |
|
800 | 800 | |
|
801 | 801 | .container { |
|
802 | 802 | display: block; |
|
803 | 803 | margin: 0 0 @padding 0; |
|
804 | 804 | } |
|
805 | 805 | |
|
806 | 806 | .delete-notifications { |
|
807 | 807 | margin-left: @padding; |
|
808 | 808 | text-align: right; |
|
809 | 809 | cursor: pointer; |
|
810 | 810 | } |
|
811 | 811 | |
|
812 | 812 | .read-notifications { |
|
813 | 813 | margin-left: @padding/2; |
|
814 | 814 | text-align: right; |
|
815 | 815 | width: 35px; |
|
816 | 816 | cursor: pointer; |
|
817 | 817 | } |
|
818 | 818 | |
|
819 | 819 | .icon-minus-sign { |
|
820 | 820 | color: @alert2; |
|
821 | 821 | } |
|
822 | 822 | |
|
823 | 823 | .icon-ok-sign { |
|
824 | 824 | color: @alert1; |
|
825 | 825 | } |
|
826 | 826 | } |
|
827 | 827 | |
|
828 | 828 | .user_settings { |
|
829 | 829 | float: left; |
|
830 | 830 | clear: both; |
|
831 | 831 | display: block; |
|
832 | 832 | width: 100%; |
|
833 | 833 | |
|
834 | 834 | .gravatar_box { |
|
835 | 835 | margin-bottom: @padding; |
|
836 | 836 | |
|
837 | 837 | &:after { |
|
838 | 838 | content: " "; |
|
839 | 839 | clear: both; |
|
840 | 840 | width: 100%; |
|
841 | 841 | } |
|
842 | 842 | } |
|
843 | 843 | |
|
844 | 844 | .fields .field { |
|
845 | 845 | clear: both; |
|
846 | 846 | } |
|
847 | 847 | } |
|
848 | 848 | |
|
849 | 849 | .advanced_settings { |
|
850 | 850 | margin-bottom: @space; |
|
851 | 851 | |
|
852 | 852 | .help-block { |
|
853 | 853 | margin-left: 0; |
|
854 | 854 | } |
|
855 | 855 | |
|
856 | 856 | button + .help-block { |
|
857 | 857 | margin-top: @padding; |
|
858 | 858 | } |
|
859 | 859 | } |
|
860 | 860 | |
|
861 | 861 | // admin settings radio buttons and labels |
|
862 | 862 | .label-2 { |
|
863 | 863 | float: left; |
|
864 | 864 | width: @label2-width; |
|
865 | 865 | |
|
866 | 866 | label { |
|
867 | 867 | color: @grey1; |
|
868 | 868 | } |
|
869 | 869 | } |
|
870 | 870 | .checkboxes { |
|
871 | 871 | float: left; |
|
872 | 872 | width: @checkboxes-width; |
|
873 | 873 | margin-bottom: @padding; |
|
874 | 874 | |
|
875 | 875 | .checkbox { |
|
876 | 876 | width: 100%; |
|
877 | 877 | |
|
878 | 878 | label { |
|
879 | 879 | margin: 0; |
|
880 | 880 | padding: 0; |
|
881 | 881 | } |
|
882 | 882 | } |
|
883 | 883 | |
|
884 | 884 | .checkbox + .checkbox { |
|
885 | 885 | display: inline-block; |
|
886 | 886 | } |
|
887 | 887 | |
|
888 | 888 | label { |
|
889 | 889 | margin-right: 1em; |
|
890 | 890 | } |
|
891 | 891 | } |
|
892 | 892 | |
|
893 | 893 | // CHANGELOG |
|
894 | 894 | .container_header { |
|
895 | 895 | float: left; |
|
896 | 896 | display: block; |
|
897 | 897 | width: 100%; |
|
898 | 898 | margin: @padding 0 @padding; |
|
899 | 899 | |
|
900 | 900 | #filter_changelog { |
|
901 | 901 | float: left; |
|
902 | 902 | margin-right: @padding; |
|
903 | 903 | } |
|
904 | 904 | |
|
905 | 905 | .breadcrumbs_light { |
|
906 | 906 | display: inline-block; |
|
907 | 907 | } |
|
908 | 908 | } |
|
909 | 909 | |
|
910 | 910 | .info_box { |
|
911 | 911 | float: right; |
|
912 | 912 | } |
|
913 | 913 | |
|
914 | 914 | |
|
915 | 915 | #graph_nodes { |
|
916 | 916 | padding-top: 43px; |
|
917 | 917 | } |
|
918 | 918 | |
|
919 | 919 | #graph_content{ |
|
920 | 920 | |
|
921 | 921 | // adjust for table headers so that graph renders properly |
|
922 | 922 | // #graph_nodes padding - table cell padding |
|
923 | 923 | padding-top: (@space - (@basefontsize * 2.4)); |
|
924 | 924 | |
|
925 | 925 | &.graph_full_width { |
|
926 | 926 | width: 100%; |
|
927 | 927 | max-width: 100%; |
|
928 | 928 | } |
|
929 | 929 | } |
|
930 | 930 | |
|
931 | 931 | #graph { |
|
932 | 932 | .flag_status { |
|
933 | 933 | margin: 0; |
|
934 | 934 | } |
|
935 | 935 | |
|
936 | 936 | .pagination-left { |
|
937 | 937 | float: left; |
|
938 | 938 | clear: both; |
|
939 | 939 | } |
|
940 | 940 | |
|
941 | 941 | .log-container { |
|
942 | 942 | max-width: 345px; |
|
943 | 943 | |
|
944 | 944 | .message{ |
|
945 | 945 | max-width: 340px; |
|
946 | 946 | } |
|
947 | 947 | } |
|
948 | 948 | |
|
949 | 949 | .graph-col-wrapper { |
|
950 | 950 | padding-left: 110px; |
|
951 | 951 | |
|
952 | 952 | #graph_nodes { |
|
953 | 953 | width: 100px; |
|
954 | 954 | margin-left: -110px; |
|
955 | 955 | float: left; |
|
956 | 956 | clear: left; |
|
957 | 957 | } |
|
958 | 958 | } |
|
959 | 959 | } |
|
960 | 960 | |
|
961 | 961 | #filter_changelog { |
|
962 | 962 | float: left; |
|
963 | 963 | } |
|
964 | 964 | |
|
965 | 965 | |
|
966 | 966 | //--- THEME ------------------// |
|
967 | 967 | |
|
968 | 968 | #logo { |
|
969 | 969 | float: left; |
|
970 | 970 | margin: 9px 0 0 0; |
|
971 | 971 | |
|
972 | 972 | .header { |
|
973 | 973 | background-color: transparent; |
|
974 | 974 | } |
|
975 | 975 | |
|
976 | 976 | a { |
|
977 | 977 | display: inline-block; |
|
978 | 978 | } |
|
979 | 979 | |
|
980 | 980 | img { |
|
981 | 981 | height:30px; |
|
982 | 982 | } |
|
983 | 983 | } |
|
984 | 984 | |
|
985 | 985 | .logo-wrapper { |
|
986 | 986 | float:left; |
|
987 | 987 | } |
|
988 | 988 | |
|
989 | 989 | .branding{ |
|
990 | 990 | float: left; |
|
991 | 991 | padding: 9px 2px; |
|
992 | 992 | line-height: 1em; |
|
993 | 993 | font-size: @navigation-fontsize; |
|
994 | 994 | } |
|
995 | 995 | |
|
996 | 996 | img { |
|
997 | 997 | border: none; |
|
998 | 998 | outline: none; |
|
999 | 999 | } |
|
1000 | 1000 | user-profile-header |
|
1001 | 1001 | label { |
|
1002 | 1002 | |
|
1003 | 1003 | input[type="checkbox"] { |
|
1004 | 1004 | margin-right: 1em; |
|
1005 | 1005 | } |
|
1006 | 1006 | input[type="radio"] { |
|
1007 | 1007 | margin-right: 1em; |
|
1008 | 1008 | } |
|
1009 | 1009 | } |
|
1010 | 1010 | |
|
1011 | 1011 | .flag_status { |
|
1012 | 1012 | margin: 2px 8px 6px 2px; |
|
1013 | 1013 | &.under_review { |
|
1014 | 1014 | .circle(5px, @alert3); |
|
1015 | 1015 | } |
|
1016 | 1016 | &.approved { |
|
1017 | 1017 | .circle(5px, @alert1); |
|
1018 | 1018 | } |
|
1019 | 1019 | &.rejected, |
|
1020 | 1020 | &.forced_closed{ |
|
1021 | 1021 | .circle(5px, @alert2); |
|
1022 | 1022 | } |
|
1023 | 1023 | &.not_reviewed { |
|
1024 | 1024 | .circle(5px, @grey5); |
|
1025 | 1025 | } |
|
1026 | 1026 | } |
|
1027 | 1027 | |
|
1028 | 1028 | .flag_status_comment_box { |
|
1029 | 1029 | margin: 5px 6px 0px 2px; |
|
1030 | 1030 | } |
|
1031 | 1031 | .test_pattern_preview { |
|
1032 | 1032 | margin: @space 0; |
|
1033 | 1033 | |
|
1034 | 1034 | p { |
|
1035 | 1035 | margin-bottom: 0; |
|
1036 | 1036 | border-bottom: @border-thickness solid @border-default-color; |
|
1037 | 1037 | color: @grey3; |
|
1038 | 1038 | } |
|
1039 | 1039 | |
|
1040 | 1040 | .btn { |
|
1041 | 1041 | margin-bottom: @padding; |
|
1042 | 1042 | } |
|
1043 | 1043 | } |
|
1044 | 1044 | #test_pattern_result { |
|
1045 | 1045 | display: none; |
|
1046 | 1046 | &:extend(pre); |
|
1047 | 1047 | padding: .9em; |
|
1048 | 1048 | color: @grey3; |
|
1049 | 1049 | background-color: @grey7; |
|
1050 | 1050 | border-right: @border-thickness solid @border-default-color; |
|
1051 | 1051 | border-bottom: @border-thickness solid @border-default-color; |
|
1052 | 1052 | border-left: @border-thickness solid @border-default-color; |
|
1053 | 1053 | } |
|
1054 | 1054 | |
|
1055 | 1055 | #repo_vcs_settings { |
|
1056 | 1056 | #inherit_overlay_vcs_default { |
|
1057 | 1057 | display: none; |
|
1058 | 1058 | } |
|
1059 | 1059 | #inherit_overlay_vcs_custom { |
|
1060 | 1060 | display: custom; |
|
1061 | 1061 | } |
|
1062 | 1062 | &.inherited { |
|
1063 | 1063 | #inherit_overlay_vcs_default { |
|
1064 | 1064 | display: block; |
|
1065 | 1065 | } |
|
1066 | 1066 | #inherit_overlay_vcs_custom { |
|
1067 | 1067 | display: none; |
|
1068 | 1068 | } |
|
1069 | 1069 | } |
|
1070 | 1070 | } |
|
1071 | 1071 | |
|
1072 | 1072 | .issue-tracker-link { |
|
1073 | 1073 | color: @rcblue; |
|
1074 | 1074 | } |
|
1075 | 1075 | |
|
1076 | 1076 | // Issue Tracker Table Show/Hide |
|
1077 | 1077 | #repo_issue_tracker { |
|
1078 | 1078 | #inherit_overlay { |
|
1079 | 1079 | display: none; |
|
1080 | 1080 | } |
|
1081 | 1081 | #custom_overlay { |
|
1082 | 1082 | display: custom; |
|
1083 | 1083 | } |
|
1084 | 1084 | &.inherited { |
|
1085 | 1085 | #inherit_overlay { |
|
1086 | 1086 | display: block; |
|
1087 | 1087 | } |
|
1088 | 1088 | #custom_overlay { |
|
1089 | 1089 | display: none; |
|
1090 | 1090 | } |
|
1091 | 1091 | } |
|
1092 | 1092 | } |
|
1093 | 1093 | table.issuetracker { |
|
1094 | 1094 | &.readonly { |
|
1095 | 1095 | tr, td { |
|
1096 | 1096 | color: @grey3; |
|
1097 | 1097 | } |
|
1098 | 1098 | } |
|
1099 | 1099 | .edit { |
|
1100 | 1100 | display: none; |
|
1101 | 1101 | } |
|
1102 | 1102 | .editopen { |
|
1103 | 1103 | .edit { |
|
1104 | 1104 | display: inline; |
|
1105 | 1105 | } |
|
1106 | 1106 | .entry { |
|
1107 | 1107 | display: none; |
|
1108 | 1108 | } |
|
1109 | 1109 | } |
|
1110 | 1110 | tr td.td-action { |
|
1111 | 1111 | min-width: 117px; |
|
1112 | 1112 | } |
|
1113 | 1113 | td input { |
|
1114 | 1114 | max-width: none; |
|
1115 | 1115 | min-width: 30px; |
|
1116 | 1116 | width: 80%; |
|
1117 | 1117 | } |
|
1118 | 1118 | .issuetracker_pref input { |
|
1119 | 1119 | width: 40%; |
|
1120 | 1120 | } |
|
1121 | 1121 | input.edit_issuetracker_update { |
|
1122 | 1122 | margin-right: 0; |
|
1123 | 1123 | width: auto; |
|
1124 | 1124 | } |
|
1125 | 1125 | } |
|
1126 | 1126 | |
|
1127 | 1127 | table.integrations { |
|
1128 | 1128 | .td-icon { |
|
1129 | 1129 | width: 20px; |
|
1130 | 1130 | .integration-icon { |
|
1131 | 1131 | height: 20px; |
|
1132 | 1132 | width: 20px; |
|
1133 | 1133 | } |
|
1134 | 1134 | } |
|
1135 | 1135 | } |
|
1136 | 1136 | |
|
1137 | 1137 | .integrations { |
|
1138 | 1138 | a.integration-box { |
|
1139 | 1139 | color: @text-color; |
|
1140 | 1140 | &:hover { |
|
1141 | 1141 | .panel { |
|
1142 | 1142 | background: #fbfbfb; |
|
1143 | 1143 | } |
|
1144 | 1144 | } |
|
1145 | 1145 | .integration-icon { |
|
1146 | 1146 | width: 30px; |
|
1147 | 1147 | height: 30px; |
|
1148 | 1148 | margin-right: 20px; |
|
1149 | 1149 | float: left; |
|
1150 | 1150 | } |
|
1151 | 1151 | |
|
1152 | 1152 | .panel-body { |
|
1153 | 1153 | padding: 10px; |
|
1154 | 1154 | } |
|
1155 | 1155 | .panel { |
|
1156 | 1156 | margin-bottom: 10px; |
|
1157 | 1157 | } |
|
1158 | 1158 | h2 { |
|
1159 | 1159 | display: inline-block; |
|
1160 | 1160 | margin: 0; |
|
1161 | 1161 | min-width: 140px; |
|
1162 | 1162 | } |
|
1163 | 1163 | } |
|
1164 | 1164 | } |
|
1165 | 1165 | |
|
1166 | 1166 | //Permissions Settings |
|
1167 | 1167 | #add_perm { |
|
1168 | 1168 | margin: 0 0 @padding; |
|
1169 | 1169 | cursor: pointer; |
|
1170 | 1170 | } |
|
1171 | 1171 | |
|
1172 | 1172 | .perm_ac { |
|
1173 | 1173 | input { |
|
1174 | 1174 | width: 95%; |
|
1175 | 1175 | } |
|
1176 | 1176 | } |
|
1177 | 1177 | |
|
1178 | 1178 | .autocomplete-suggestions { |
|
1179 | 1179 | width: auto !important; // overrides autocomplete.js |
|
1180 | 1180 | margin: 0; |
|
1181 | 1181 | border: @border-thickness solid @rcblue; |
|
1182 | 1182 | border-radius: @border-radius; |
|
1183 | 1183 | color: @rcblue; |
|
1184 | 1184 | background-color: white; |
|
1185 | 1185 | } |
|
1186 | 1186 | .autocomplete-selected { |
|
1187 | 1187 | background: #F0F0F0; |
|
1188 | 1188 | } |
|
1189 | 1189 | .ac-container-wrap { |
|
1190 | 1190 | margin: 0; |
|
1191 | 1191 | padding: 8px; |
|
1192 | 1192 | border-bottom: @border-thickness solid @rclightblue; |
|
1193 | 1193 | list-style-type: none; |
|
1194 | 1194 | cursor: pointer; |
|
1195 | 1195 | |
|
1196 | 1196 | &:hover { |
|
1197 | 1197 | background-color: @rclightblue; |
|
1198 | 1198 | } |
|
1199 | 1199 | |
|
1200 | 1200 | img { |
|
1201 | 1201 | height: @gravatar-size; |
|
1202 | 1202 | width: @gravatar-size; |
|
1203 | 1203 | margin-right: 1em; |
|
1204 | 1204 | } |
|
1205 | 1205 | |
|
1206 | 1206 | strong { |
|
1207 | 1207 | font-weight: normal; |
|
1208 | 1208 | } |
|
1209 | 1209 | } |
|
1210 | 1210 | |
|
1211 | 1211 | // Settings Dropdown |
|
1212 | 1212 | .user-menu .container { |
|
1213 | 1213 | padding: 0 4px; |
|
1214 | 1214 | margin: 0; |
|
1215 | 1215 | } |
|
1216 | 1216 | |
|
1217 | 1217 | .user-menu .gravatar { |
|
1218 | 1218 | cursor: pointer; |
|
1219 | 1219 | } |
|
1220 | 1220 | |
|
1221 | 1221 | .codeblock { |
|
1222 | 1222 | margin-bottom: @padding; |
|
1223 | 1223 | clear: both; |
|
1224 | 1224 | |
|
1225 | 1225 | .stats{ |
|
1226 | 1226 | overflow: hidden; |
|
1227 | 1227 | } |
|
1228 | 1228 | |
|
1229 | 1229 | .message{ |
|
1230 | 1230 | textarea{ |
|
1231 | 1231 | margin: 0; |
|
1232 | 1232 | } |
|
1233 | 1233 | } |
|
1234 | 1234 | |
|
1235 | 1235 | .code-header { |
|
1236 | 1236 | .stats { |
|
1237 | 1237 | line-height: 2em; |
|
1238 | 1238 | |
|
1239 | 1239 | .revision_id { |
|
1240 | 1240 | margin-left: 0; |
|
1241 | 1241 | } |
|
1242 | 1242 | .buttons { |
|
1243 | 1243 | padding-right: 0; |
|
1244 | 1244 | } |
|
1245 | 1245 | } |
|
1246 | 1246 | |
|
1247 | 1247 | .item{ |
|
1248 | 1248 | margin-right: 0.5em; |
|
1249 | 1249 | } |
|
1250 | 1250 | } |
|
1251 | 1251 | |
|
1252 | 1252 | #editor_container{ |
|
1253 | 1253 | position: relative; |
|
1254 | 1254 | margin: @padding; |
|
1255 | 1255 | } |
|
1256 | 1256 | } |
|
1257 | 1257 | |
|
1258 | 1258 | #file_history_container { |
|
1259 | 1259 | display: none; |
|
1260 | 1260 | } |
|
1261 | 1261 | |
|
1262 | 1262 | .file-history-inner { |
|
1263 | 1263 | margin-bottom: 10px; |
|
1264 | 1264 | } |
|
1265 | 1265 | |
|
1266 | 1266 | // Pull Requests |
|
1267 | 1267 | .summary-details { |
|
1268 | 1268 | width: 72%; |
|
1269 | 1269 | } |
|
1270 | 1270 | .pr-summary { |
|
1271 | 1271 | border-bottom: @border-thickness solid @grey5; |
|
1272 | 1272 | margin-bottom: @space; |
|
1273 | 1273 | } |
|
1274 | 1274 | .reviewers-title { |
|
1275 | 1275 | width: 25%; |
|
1276 | 1276 | min-width: 200px; |
|
1277 | 1277 | } |
|
1278 | 1278 | .reviewers { |
|
1279 | 1279 | width: 25%; |
|
1280 | 1280 | min-width: 200px; |
|
1281 | 1281 | } |
|
1282 | 1282 | .reviewers ul li { |
|
1283 | 1283 | position: relative; |
|
1284 | 1284 | width: 100%; |
|
1285 | 1285 | margin-bottom: 8px; |
|
1286 | 1286 | } |
|
1287 | 1287 | .reviewers_member { |
|
1288 | 1288 | width: 100%; |
|
1289 | 1289 | overflow: auto; |
|
1290 | 1290 | } |
|
1291 | 1291 | .reviewer_reason { |
|
1292 | 1292 | padding-left: 20px; |
|
1293 | 1293 | } |
|
1294 | 1294 | .reviewer_status { |
|
1295 | 1295 | display: inline-block; |
|
1296 | 1296 | vertical-align: top; |
|
1297 | 1297 | width: 7%; |
|
1298 | 1298 | min-width: 20px; |
|
1299 | 1299 | height: 1.2em; |
|
1300 | 1300 | margin-top: 3px; |
|
1301 | 1301 | line-height: 1em; |
|
1302 | 1302 | } |
|
1303 | 1303 | |
|
1304 | 1304 | .reviewer_name { |
|
1305 | 1305 | display: inline-block; |
|
1306 | 1306 | max-width: 83%; |
|
1307 | 1307 | padding-right: 20px; |
|
1308 | 1308 | vertical-align: middle; |
|
1309 | 1309 | line-height: 1; |
|
1310 | 1310 | |
|
1311 | 1311 | .rc-user { |
|
1312 | 1312 | min-width: 0; |
|
1313 | 1313 | margin: -2px 1em 0 0; |
|
1314 | 1314 | } |
|
1315 | 1315 | |
|
1316 | 1316 | .reviewer { |
|
1317 | 1317 | float: left; |
|
1318 | 1318 | } |
|
1319 | 1319 | |
|
1320 | 1320 | &.to-delete { |
|
1321 | 1321 | .user, |
|
1322 | 1322 | .reviewer { |
|
1323 | 1323 | text-decoration: line-through; |
|
1324 | 1324 | } |
|
1325 | 1325 | } |
|
1326 | 1326 | } |
|
1327 | 1327 | |
|
1328 | 1328 | .reviewer_member_remove { |
|
1329 | 1329 | position: absolute; |
|
1330 | 1330 | right: 0; |
|
1331 | 1331 | top: 0; |
|
1332 | 1332 | width: 16px; |
|
1333 | 1333 | margin-bottom: 10px; |
|
1334 | 1334 | padding: 0; |
|
1335 | 1335 | color: black; |
|
1336 | 1336 | } |
|
1337 | 1337 | .reviewer_member_status { |
|
1338 | 1338 | margin-top: 5px; |
|
1339 | 1339 | } |
|
1340 | 1340 | .pr-summary #summary{ |
|
1341 | 1341 | width: 100%; |
|
1342 | 1342 | } |
|
1343 | 1343 | .pr-summary .action_button:hover { |
|
1344 | 1344 | border: 0; |
|
1345 | 1345 | cursor: pointer; |
|
1346 | 1346 | } |
|
1347 | 1347 | .pr-details-title { |
|
1348 | 1348 | padding-bottom: 8px; |
|
1349 | 1349 | border-bottom: @border-thickness solid @grey5; |
|
1350 | 1350 | |
|
1351 | 1351 | .action_button.disabled { |
|
1352 | 1352 | color: @grey4; |
|
1353 | 1353 | cursor: inherit; |
|
1354 | 1354 | } |
|
1355 | 1355 | .action_button { |
|
1356 | 1356 | color: @rcblue; |
|
1357 | 1357 | } |
|
1358 | 1358 | } |
|
1359 | 1359 | .pr-details-content { |
|
1360 | 1360 | margin-top: @textmargin; |
|
1361 | 1361 | margin-bottom: @textmargin; |
|
1362 | 1362 | } |
|
1363 | 1363 | .pr-description { |
|
1364 | 1364 | white-space:pre-wrap; |
|
1365 | 1365 | } |
|
1366 | 1366 | .group_members { |
|
1367 | 1367 | margin-top: 0; |
|
1368 | 1368 | padding: 0; |
|
1369 | 1369 | list-style: outside none none; |
|
1370 | 1370 | |
|
1371 | 1371 | img { |
|
1372 | 1372 | height: @gravatar-size; |
|
1373 | 1373 | width: @gravatar-size; |
|
1374 | 1374 | margin-right: .5em; |
|
1375 | 1375 | margin-left: 3px; |
|
1376 | 1376 | } |
|
1377 | 1377 | |
|
1378 | 1378 | .to-delete { |
|
1379 | 1379 | .user { |
|
1380 | 1380 | text-decoration: line-through; |
|
1381 | 1381 | } |
|
1382 | 1382 | } |
|
1383 | 1383 | } |
|
1384 | 1384 | |
|
1385 | 1385 | .compare_view_commits_title { |
|
1386 | 1386 | .disabled { |
|
1387 | 1387 | cursor: inherit; |
|
1388 | 1388 | &:hover{ |
|
1389 | 1389 | background-color: inherit; |
|
1390 | 1390 | color: inherit; |
|
1391 | 1391 | } |
|
1392 | 1392 | } |
|
1393 | 1393 | } |
|
1394 | 1394 | |
|
1395 | 1395 | // new entry in group_members |
|
1396 | 1396 | .td-author-new-entry { |
|
1397 | 1397 | background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3); |
|
1398 | 1398 | } |
|
1399 | 1399 | |
|
1400 | 1400 | .usergroup_member_remove { |
|
1401 | 1401 | width: 16px; |
|
1402 | 1402 | margin-bottom: 10px; |
|
1403 | 1403 | padding: 0; |
|
1404 | 1404 | color: black !important; |
|
1405 | 1405 | cursor: pointer; |
|
1406 | 1406 | } |
|
1407 | 1407 | |
|
1408 | 1408 | .reviewer_ac .ac-input { |
|
1409 | 1409 | width: 92%; |
|
1410 | 1410 | margin-bottom: 1em; |
|
1411 | 1411 | } |
|
1412 | 1412 | |
|
1413 | 1413 | .compare_view_commits tr{ |
|
1414 | 1414 | height: 20px; |
|
1415 | 1415 | } |
|
1416 | 1416 | .compare_view_commits td { |
|
1417 | 1417 | vertical-align: top; |
|
1418 | 1418 | padding-top: 10px; |
|
1419 | 1419 | } |
|
1420 | 1420 | .compare_view_commits .author { |
|
1421 | 1421 | margin-left: 5px; |
|
1422 | 1422 | } |
|
1423 | 1423 | |
|
1424 | 1424 | .compare_view_files { |
|
1425 | 1425 | width: 100%; |
|
1426 | 1426 | |
|
1427 | 1427 | td { |
|
1428 | 1428 | vertical-align: middle; |
|
1429 | 1429 | } |
|
1430 | 1430 | } |
|
1431 | 1431 | |
|
1432 | 1432 | .compare_view_filepath { |
|
1433 | 1433 | color: @grey1; |
|
1434 | 1434 | } |
|
1435 | 1435 | |
|
1436 | 1436 | .show_more { |
|
1437 | 1437 | display: inline-block; |
|
1438 | 1438 | position: relative; |
|
1439 | 1439 | vertical-align: middle; |
|
1440 | 1440 | width: 4px; |
|
1441 | 1441 | height: @basefontsize; |
|
1442 | 1442 | |
|
1443 | 1443 | &:after { |
|
1444 | 1444 | content: "\00A0\25BE"; |
|
1445 | 1445 | display: inline-block; |
|
1446 | 1446 | width:10px; |
|
1447 | 1447 | line-height: 5px; |
|
1448 | 1448 | font-size: 12px; |
|
1449 | 1449 | cursor: pointer; |
|
1450 | 1450 | } |
|
1451 | 1451 | } |
|
1452 | 1452 | |
|
1453 | 1453 | .journal_more .show_more { |
|
1454 | 1454 | display: inline; |
|
1455 | 1455 | |
|
1456 | 1456 | &:after { |
|
1457 | 1457 | content: none; |
|
1458 | 1458 | } |
|
1459 | 1459 | } |
|
1460 | 1460 | |
|
1461 | 1461 | .open .show_more:after, |
|
1462 | 1462 | .select2-dropdown-open .show_more:after { |
|
1463 | 1463 | .rotate(180deg); |
|
1464 | 1464 | margin-left: 4px; |
|
1465 | 1465 | } |
|
1466 | 1466 | |
|
1467 | 1467 | |
|
1468 | 1468 | .compare_view_commits .collapse_commit:after { |
|
1469 | 1469 | cursor: pointer; |
|
1470 | 1470 | content: "\00A0\25B4"; |
|
1471 | 1471 | margin-left: -3px; |
|
1472 | 1472 | font-size: 17px; |
|
1473 | 1473 | color: @grey4; |
|
1474 | 1474 | } |
|
1475 | 1475 | |
|
1476 | 1476 | .diff_links { |
|
1477 | 1477 | margin-left: 8px; |
|
1478 | 1478 | } |
|
1479 | 1479 | |
|
1480 |
|
|
|
1480 | div.ancestor { | |
|
1481 | 1481 | margin: @padding 0; |
|
1482 | line-height: 3.0em; | |
|
1482 | 1483 | } |
|
1483 | 1484 | |
|
1484 | 1485 | .cs_icon_td input[type="checkbox"] { |
|
1485 | 1486 | display: none; |
|
1486 | 1487 | } |
|
1487 | 1488 | |
|
1488 | 1489 | .cs_icon_td .expand_file_icon:after { |
|
1489 | 1490 | cursor: pointer; |
|
1490 | 1491 | content: "\00A0\25B6"; |
|
1491 | 1492 | font-size: 12px; |
|
1492 | 1493 | color: @grey4; |
|
1493 | 1494 | } |
|
1494 | 1495 | |
|
1495 | 1496 | .cs_icon_td .collapse_file_icon:after { |
|
1496 | 1497 | cursor: pointer; |
|
1497 | 1498 | content: "\00A0\25BC"; |
|
1498 | 1499 | font-size: 12px; |
|
1499 | 1500 | color: @grey4; |
|
1500 | 1501 | } |
|
1501 | 1502 | |
|
1502 | 1503 | /*new binary |
|
1503 | 1504 | NEW_FILENODE = 1 |
|
1504 | 1505 | DEL_FILENODE = 2 |
|
1505 | 1506 | MOD_FILENODE = 3 |
|
1506 | 1507 | RENAMED_FILENODE = 4 |
|
1507 | 1508 | COPIED_FILENODE = 5 |
|
1508 | 1509 | CHMOD_FILENODE = 6 |
|
1509 | 1510 | BIN_FILENODE = 7 |
|
1510 | 1511 | */ |
|
1511 | 1512 | .cs_files_expand { |
|
1512 | 1513 | font-size: @basefontsize + 5px; |
|
1513 | 1514 | line-height: 1.8em; |
|
1514 | 1515 | float: right; |
|
1515 | 1516 | } |
|
1516 | 1517 | |
|
1517 | 1518 | .cs_files_expand span{ |
|
1518 | 1519 | color: @rcblue; |
|
1519 | 1520 | cursor: pointer; |
|
1520 | 1521 | } |
|
1521 | 1522 | .cs_files { |
|
1522 | 1523 | clear: both; |
|
1523 | 1524 | padding-bottom: @padding; |
|
1524 | 1525 | |
|
1525 | 1526 | .cur_cs { |
|
1526 | 1527 | margin: 10px 2px; |
|
1527 | 1528 | font-weight: bold; |
|
1528 | 1529 | } |
|
1529 | 1530 | |
|
1530 | 1531 | .node { |
|
1531 | 1532 | float: left; |
|
1532 | 1533 | } |
|
1533 | 1534 | |
|
1534 | 1535 | .changes { |
|
1535 | 1536 | float: right; |
|
1536 | 1537 | color: white; |
|
1537 | 1538 | font-size: @basefontsize - 4px; |
|
1538 | 1539 | margin-top: 4px; |
|
1539 | 1540 | opacity: 0.6; |
|
1540 | 1541 | filter: Alpha(opacity=60); /* IE8 and earlier */ |
|
1541 | 1542 | |
|
1542 | 1543 | .added { |
|
1543 | 1544 | background-color: @alert1; |
|
1544 | 1545 | float: left; |
|
1545 | 1546 | text-align: center; |
|
1546 | 1547 | } |
|
1547 | 1548 | |
|
1548 | 1549 | .deleted { |
|
1549 | 1550 | background-color: @alert2; |
|
1550 | 1551 | float: left; |
|
1551 | 1552 | text-align: center; |
|
1552 | 1553 | } |
|
1553 | 1554 | |
|
1554 | 1555 | .bin { |
|
1555 | 1556 | background-color: @alert1; |
|
1556 | 1557 | text-align: center; |
|
1557 | 1558 | } |
|
1558 | 1559 | |
|
1559 | 1560 | /*new binary*/ |
|
1560 | 1561 | .bin.bin1 { |
|
1561 | 1562 | background-color: @alert1; |
|
1562 | 1563 | text-align: center; |
|
1563 | 1564 | } |
|
1564 | 1565 | |
|
1565 | 1566 | /*deleted binary*/ |
|
1566 | 1567 | .bin.bin2 { |
|
1567 | 1568 | background-color: @alert2; |
|
1568 | 1569 | text-align: center; |
|
1569 | 1570 | } |
|
1570 | 1571 | |
|
1571 | 1572 | /*mod binary*/ |
|
1572 | 1573 | .bin.bin3 { |
|
1573 | 1574 | background-color: @grey2; |
|
1574 | 1575 | text-align: center; |
|
1575 | 1576 | } |
|
1576 | 1577 | |
|
1577 | 1578 | /*rename file*/ |
|
1578 | 1579 | .bin.bin4 { |
|
1579 | 1580 | background-color: @alert4; |
|
1580 | 1581 | text-align: center; |
|
1581 | 1582 | } |
|
1582 | 1583 | |
|
1583 | 1584 | /*copied file*/ |
|
1584 | 1585 | .bin.bin5 { |
|
1585 | 1586 | background-color: @alert4; |
|
1586 | 1587 | text-align: center; |
|
1587 | 1588 | } |
|
1588 | 1589 | |
|
1589 | 1590 | /*chmod file*/ |
|
1590 | 1591 | .bin.bin6 { |
|
1591 | 1592 | background-color: @grey2; |
|
1592 | 1593 | text-align: center; |
|
1593 | 1594 | } |
|
1594 | 1595 | } |
|
1595 | 1596 | } |
|
1596 | 1597 | |
|
1597 | 1598 | .cs_files .cs_added, .cs_files .cs_A, |
|
1598 | 1599 | .cs_files .cs_added, .cs_files .cs_M, |
|
1599 | 1600 | .cs_files .cs_added, .cs_files .cs_D { |
|
1600 | 1601 | height: 16px; |
|
1601 | 1602 | padding-right: 10px; |
|
1602 | 1603 | margin-top: 7px; |
|
1603 | 1604 | text-align: left; |
|
1604 | 1605 | } |
|
1605 | 1606 | |
|
1606 | 1607 | .cs_icon_td { |
|
1607 | 1608 | min-width: 16px; |
|
1608 | 1609 | width: 16px; |
|
1609 | 1610 | } |
|
1610 | 1611 | |
|
1611 | 1612 | .pull-request-merge { |
|
1612 | 1613 | padding: 10px 0; |
|
1613 | 1614 | margin-top: 10px; |
|
1614 | 1615 | margin-bottom: 20px; |
|
1615 | 1616 | } |
|
1616 | 1617 | |
|
1617 | 1618 | .pull-request-merge .pull-request-wrap { |
|
1618 | 1619 | height: 25px; |
|
1619 | 1620 | padding: 5px 0; |
|
1620 | 1621 | } |
|
1621 | 1622 | |
|
1622 | 1623 | .pull-request-merge span { |
|
1623 | 1624 | margin-right: 10px; |
|
1624 | 1625 | } |
|
1625 | 1626 | #close_pull_request { |
|
1626 | 1627 | margin-right: 0px; |
|
1627 | 1628 | } |
|
1628 | 1629 | |
|
1629 | 1630 | .empty_data { |
|
1630 | 1631 | color: @grey4; |
|
1631 | 1632 | } |
|
1632 | 1633 | |
|
1633 | 1634 | #changeset_compare_view_content { |
|
1634 | 1635 | margin-bottom: @space; |
|
1635 | 1636 | clear: both; |
|
1636 | 1637 | width: 100%; |
|
1637 | 1638 | box-sizing: border-box; |
|
1638 | 1639 | .border-radius(@border-radius); |
|
1639 | 1640 | |
|
1640 | 1641 | .help-block { |
|
1641 | 1642 | margin: @padding 0; |
|
1642 | 1643 | color: @text-color; |
|
1643 | 1644 | } |
|
1644 | 1645 | |
|
1645 | 1646 | .empty_data { |
|
1646 | 1647 | margin: @padding 0; |
|
1647 | 1648 | } |
|
1648 | 1649 | |
|
1649 | 1650 | .alert { |
|
1650 | 1651 | margin-bottom: @space; |
|
1651 | 1652 | } |
|
1652 | 1653 | } |
|
1653 | 1654 | |
|
1654 | 1655 | .table_disp { |
|
1655 | 1656 | .status { |
|
1656 | 1657 | width: auto; |
|
1657 | 1658 | |
|
1658 | 1659 | .flag_status { |
|
1659 | 1660 | float: left; |
|
1660 | 1661 | } |
|
1661 | 1662 | } |
|
1662 | 1663 | } |
|
1663 | 1664 | |
|
1664 | 1665 | .status_box_menu { |
|
1665 | 1666 | margin: 0; |
|
1666 | 1667 | } |
|
1667 | 1668 | |
|
1668 | 1669 | .notification-table{ |
|
1669 | 1670 | margin-bottom: @space; |
|
1670 | 1671 | display: table; |
|
1671 | 1672 | width: 100%; |
|
1672 | 1673 | |
|
1673 | 1674 | .container{ |
|
1674 | 1675 | display: table-row; |
|
1675 | 1676 | |
|
1676 | 1677 | .notification-header{ |
|
1677 | 1678 | border-bottom: @border-thickness solid @border-default-color; |
|
1678 | 1679 | } |
|
1679 | 1680 | |
|
1680 | 1681 | .notification-subject{ |
|
1681 | 1682 | display: table-cell; |
|
1682 | 1683 | } |
|
1683 | 1684 | } |
|
1684 | 1685 | } |
|
1685 | 1686 | |
|
1686 | 1687 | // Notifications |
|
1687 | 1688 | .notification-header{ |
|
1688 | 1689 | display: table; |
|
1689 | 1690 | width: 100%; |
|
1690 | 1691 | padding: floor(@basefontsize/2) 0; |
|
1691 | 1692 | line-height: 1em; |
|
1692 | 1693 | |
|
1693 | 1694 | .desc, .delete-notifications, .read-notifications{ |
|
1694 | 1695 | display: table-cell; |
|
1695 | 1696 | text-align: left; |
|
1696 | 1697 | } |
|
1697 | 1698 | |
|
1698 | 1699 | .desc{ |
|
1699 | 1700 | width: 1163px; |
|
1700 | 1701 | } |
|
1701 | 1702 | |
|
1702 | 1703 | .delete-notifications, .read-notifications{ |
|
1703 | 1704 | width: 35px; |
|
1704 | 1705 | min-width: 35px; //fixes when only one button is displayed |
|
1705 | 1706 | } |
|
1706 | 1707 | } |
|
1707 | 1708 | |
|
1708 | 1709 | .notification-body { |
|
1709 | 1710 | .markdown-block, |
|
1710 | 1711 | .rst-block { |
|
1711 | 1712 | padding: @padding 0; |
|
1712 | 1713 | } |
|
1713 | 1714 | |
|
1714 | 1715 | .notification-subject { |
|
1715 | 1716 | padding: @textmargin 0; |
|
1716 | 1717 | border-bottom: @border-thickness solid @border-default-color; |
|
1717 | 1718 | } |
|
1718 | 1719 | } |
|
1719 | 1720 | |
|
1720 | 1721 | |
|
1721 | 1722 | .notifications_buttons{ |
|
1722 | 1723 | float: right; |
|
1723 | 1724 | } |
|
1724 | 1725 | |
|
1725 | 1726 | #notification-status{ |
|
1726 | 1727 | display: inline; |
|
1727 | 1728 | } |
|
1728 | 1729 | |
|
1729 | 1730 | // Repositories |
|
1730 | 1731 | |
|
1731 | 1732 | #summary.fields{ |
|
1732 | 1733 | display: table; |
|
1733 | 1734 | |
|
1734 | 1735 | .field{ |
|
1735 | 1736 | display: table-row; |
|
1736 | 1737 | |
|
1737 | 1738 | .label-summary{ |
|
1738 | 1739 | display: table-cell; |
|
1739 | 1740 | min-width: @label-summary-minwidth; |
|
1740 | 1741 | padding-top: @padding/2; |
|
1741 | 1742 | padding-bottom: @padding/2; |
|
1742 | 1743 | padding-right: @padding/2; |
|
1743 | 1744 | } |
|
1744 | 1745 | |
|
1745 | 1746 | .input{ |
|
1746 | 1747 | display: table-cell; |
|
1747 | 1748 | padding: @padding/2; |
|
1748 | 1749 | |
|
1749 | 1750 | input{ |
|
1750 | 1751 | min-width: 29em; |
|
1751 | 1752 | padding: @padding/4; |
|
1752 | 1753 | } |
|
1753 | 1754 | } |
|
1754 | 1755 | .statistics, .downloads{ |
|
1755 | 1756 | .disabled{ |
|
1756 | 1757 | color: @grey4; |
|
1757 | 1758 | } |
|
1758 | 1759 | } |
|
1759 | 1760 | } |
|
1760 | 1761 | } |
|
1761 | 1762 | |
|
1762 | 1763 | #summary{ |
|
1763 | 1764 | width: 70%; |
|
1764 | 1765 | } |
|
1765 | 1766 | |
|
1766 | 1767 | |
|
1767 | 1768 | // Journal |
|
1768 | 1769 | .journal.title { |
|
1769 | 1770 | h5 { |
|
1770 | 1771 | float: left; |
|
1771 | 1772 | margin: 0; |
|
1772 | 1773 | width: 70%; |
|
1773 | 1774 | } |
|
1774 | 1775 | |
|
1775 | 1776 | ul { |
|
1776 | 1777 | float: right; |
|
1777 | 1778 | display: inline-block; |
|
1778 | 1779 | margin: 0; |
|
1779 | 1780 | width: 30%; |
|
1780 | 1781 | text-align: right; |
|
1781 | 1782 | |
|
1782 | 1783 | li { |
|
1783 | 1784 | display: inline; |
|
1784 | 1785 | font-size: @journal-fontsize; |
|
1785 | 1786 | line-height: 1em; |
|
1786 | 1787 | |
|
1787 | 1788 | &:before { content: none; } |
|
1788 | 1789 | } |
|
1789 | 1790 | } |
|
1790 | 1791 | } |
|
1791 | 1792 | |
|
1792 | 1793 | .filterexample { |
|
1793 | 1794 | position: absolute; |
|
1794 | 1795 | top: 95px; |
|
1795 | 1796 | left: @contentpadding; |
|
1796 | 1797 | color: @rcblue; |
|
1797 | 1798 | font-size: 11px; |
|
1798 | 1799 | font-family: @text-regular; |
|
1799 | 1800 | cursor: help; |
|
1800 | 1801 | |
|
1801 | 1802 | &:hover { |
|
1802 | 1803 | color: @rcdarkblue; |
|
1803 | 1804 | } |
|
1804 | 1805 | |
|
1805 | 1806 | @media (max-width:768px) { |
|
1806 | 1807 | position: relative; |
|
1807 | 1808 | top: auto; |
|
1808 | 1809 | left: auto; |
|
1809 | 1810 | display: block; |
|
1810 | 1811 | } |
|
1811 | 1812 | } |
|
1812 | 1813 | |
|
1813 | 1814 | |
|
1814 | 1815 | #journal{ |
|
1815 | 1816 | margin-bottom: @space; |
|
1816 | 1817 | |
|
1817 | 1818 | .journal_day{ |
|
1818 | 1819 | margin-bottom: @textmargin/2; |
|
1819 | 1820 | padding-bottom: @textmargin/2; |
|
1820 | 1821 | font-size: @journal-fontsize; |
|
1821 | 1822 | border-bottom: @border-thickness solid @border-default-color; |
|
1822 | 1823 | } |
|
1823 | 1824 | |
|
1824 | 1825 | .journal_container{ |
|
1825 | 1826 | margin-bottom: @space; |
|
1826 | 1827 | |
|
1827 | 1828 | .journal_user{ |
|
1828 | 1829 | display: inline-block; |
|
1829 | 1830 | } |
|
1830 | 1831 | .journal_action_container{ |
|
1831 | 1832 | display: block; |
|
1832 | 1833 | margin-top: @textmargin; |
|
1833 | 1834 | |
|
1834 | 1835 | div{ |
|
1835 | 1836 | display: inline; |
|
1836 | 1837 | } |
|
1837 | 1838 | |
|
1838 | 1839 | div.journal_action_params{ |
|
1839 | 1840 | display: block; |
|
1840 | 1841 | } |
|
1841 | 1842 | |
|
1842 | 1843 | div.journal_repo:after{ |
|
1843 | 1844 | content: "\A"; |
|
1844 | 1845 | white-space: pre; |
|
1845 | 1846 | } |
|
1846 | 1847 | |
|
1847 | 1848 | div.date{ |
|
1848 | 1849 | display: block; |
|
1849 | 1850 | margin-bottom: @textmargin; |
|
1850 | 1851 | } |
|
1851 | 1852 | } |
|
1852 | 1853 | } |
|
1853 | 1854 | } |
|
1854 | 1855 | |
|
1855 | 1856 | // Files |
|
1856 | 1857 | .edit-file-title { |
|
1857 | 1858 | border-bottom: @border-thickness solid @border-default-color; |
|
1858 | 1859 | |
|
1859 | 1860 | .breadcrumbs { |
|
1860 | 1861 | margin-bottom: 0; |
|
1861 | 1862 | } |
|
1862 | 1863 | } |
|
1863 | 1864 | |
|
1864 | 1865 | .edit-file-fieldset { |
|
1865 | 1866 | margin-top: @sidebarpadding; |
|
1866 | 1867 | |
|
1867 | 1868 | .fieldset { |
|
1868 | 1869 | .left-label { |
|
1869 | 1870 | width: 13%; |
|
1870 | 1871 | } |
|
1871 | 1872 | .right-content { |
|
1872 | 1873 | width: 87%; |
|
1873 | 1874 | max-width: 100%; |
|
1874 | 1875 | } |
|
1875 | 1876 | .filename-label { |
|
1876 | 1877 | margin-top: 13px; |
|
1877 | 1878 | } |
|
1878 | 1879 | .commit-message-label { |
|
1879 | 1880 | margin-top: 4px; |
|
1880 | 1881 | } |
|
1881 | 1882 | .file-upload-input { |
|
1882 | 1883 | input { |
|
1883 | 1884 | display: none; |
|
1884 | 1885 | } |
|
1885 | 1886 | } |
|
1886 | 1887 | p { |
|
1887 | 1888 | margin-top: 5px; |
|
1888 | 1889 | } |
|
1889 | 1890 | |
|
1890 | 1891 | } |
|
1891 | 1892 | .custom-path-link { |
|
1892 | 1893 | margin-left: 5px; |
|
1893 | 1894 | } |
|
1894 | 1895 | #commit { |
|
1895 | 1896 | resize: vertical; |
|
1896 | 1897 | } |
|
1897 | 1898 | } |
|
1898 | 1899 | |
|
1899 | 1900 | .delete-file-preview { |
|
1900 | 1901 | max-height: 250px; |
|
1901 | 1902 | } |
|
1902 | 1903 | |
|
1903 | 1904 | .new-file, |
|
1904 | 1905 | #filter_activate, |
|
1905 | 1906 | #filter_deactivate { |
|
1906 | 1907 | float: left; |
|
1907 | 1908 | margin: 0 0 0 15px; |
|
1908 | 1909 | } |
|
1909 | 1910 | |
|
1910 | 1911 | h3.files_location{ |
|
1911 | 1912 | line-height: 2.4em; |
|
1912 | 1913 | } |
|
1913 | 1914 | |
|
1914 | 1915 | .browser-nav { |
|
1915 | 1916 | display: table; |
|
1916 | 1917 | margin-bottom: @space; |
|
1917 | 1918 | |
|
1918 | 1919 | |
|
1919 | 1920 | .info_box { |
|
1920 | 1921 | display: inline-table; |
|
1921 | 1922 | height: 2.5em; |
|
1922 | 1923 | |
|
1923 | 1924 | .browser-cur-rev, .info_box_elem { |
|
1924 | 1925 | display: table-cell; |
|
1925 | 1926 | vertical-align: middle; |
|
1926 | 1927 | } |
|
1927 | 1928 | |
|
1928 | 1929 | .info_box_elem { |
|
1929 | 1930 | border-top: @border-thickness solid @rcblue; |
|
1930 | 1931 | border-bottom: @border-thickness solid @rcblue; |
|
1931 | 1932 | |
|
1932 | 1933 | #at_rev, a { |
|
1933 | 1934 | padding: 0.6em 0.9em; |
|
1934 | 1935 | margin: 0; |
|
1935 | 1936 | .box-shadow(none); |
|
1936 | 1937 | border: 0; |
|
1937 | 1938 | height: 12px; |
|
1938 | 1939 | } |
|
1939 | 1940 | |
|
1940 | 1941 | input#at_rev { |
|
1941 | 1942 | max-width: 50px; |
|
1942 | 1943 | text-align: right; |
|
1943 | 1944 | } |
|
1944 | 1945 | |
|
1945 | 1946 | &.previous { |
|
1946 | 1947 | border: @border-thickness solid @rcblue; |
|
1947 | 1948 | .disabled { |
|
1948 | 1949 | color: @grey4; |
|
1949 | 1950 | cursor: not-allowed; |
|
1950 | 1951 | } |
|
1951 | 1952 | } |
|
1952 | 1953 | |
|
1953 | 1954 | &.next { |
|
1954 | 1955 | border: @border-thickness solid @rcblue; |
|
1955 | 1956 | .disabled { |
|
1956 | 1957 | color: @grey4; |
|
1957 | 1958 | cursor: not-allowed; |
|
1958 | 1959 | } |
|
1959 | 1960 | } |
|
1960 | 1961 | } |
|
1961 | 1962 | |
|
1962 | 1963 | .browser-cur-rev { |
|
1963 | 1964 | |
|
1964 | 1965 | span{ |
|
1965 | 1966 | margin: 0; |
|
1966 | 1967 | color: @rcblue; |
|
1967 | 1968 | height: 12px; |
|
1968 | 1969 | display: inline-block; |
|
1969 | 1970 | padding: 0.7em 1em ; |
|
1970 | 1971 | border: @border-thickness solid @rcblue; |
|
1971 | 1972 | margin-right: @padding; |
|
1972 | 1973 | } |
|
1973 | 1974 | } |
|
1974 | 1975 | } |
|
1975 | 1976 | |
|
1976 | 1977 | .search_activate { |
|
1977 | 1978 | display: table-cell; |
|
1978 | 1979 | vertical-align: middle; |
|
1979 | 1980 | |
|
1980 | 1981 | input, label{ |
|
1981 | 1982 | margin: 0; |
|
1982 | 1983 | padding: 0; |
|
1983 | 1984 | } |
|
1984 | 1985 | |
|
1985 | 1986 | input{ |
|
1986 | 1987 | margin-left: @textmargin; |
|
1987 | 1988 | } |
|
1988 | 1989 | |
|
1989 | 1990 | } |
|
1990 | 1991 | } |
|
1991 | 1992 | |
|
1992 | 1993 | .browser-cur-rev{ |
|
1993 | 1994 | margin-bottom: @textmargin; |
|
1994 | 1995 | } |
|
1995 | 1996 | |
|
1996 | 1997 | #node_filter_box_loading{ |
|
1997 | 1998 | .info_text; |
|
1998 | 1999 | } |
|
1999 | 2000 | |
|
2000 | 2001 | .browser-search { |
|
2001 | 2002 | margin: -25px 0px 5px 0px; |
|
2002 | 2003 | } |
|
2003 | 2004 | |
|
2004 | 2005 | .node-filter { |
|
2005 | 2006 | font-size: @repo-title-fontsize; |
|
2006 | 2007 | padding: 4px 0px 0px 0px; |
|
2007 | 2008 | |
|
2008 | 2009 | .node-filter-path { |
|
2009 | 2010 | float: left; |
|
2010 | 2011 | color: @grey4; |
|
2011 | 2012 | } |
|
2012 | 2013 | .node-filter-input { |
|
2013 | 2014 | float: left; |
|
2014 | 2015 | margin: -2px 0px 0px 2px; |
|
2015 | 2016 | input { |
|
2016 | 2017 | padding: 2px; |
|
2017 | 2018 | border: none; |
|
2018 | 2019 | font-size: @repo-title-fontsize; |
|
2019 | 2020 | } |
|
2020 | 2021 | } |
|
2021 | 2022 | } |
|
2022 | 2023 | |
|
2023 | 2024 | |
|
2024 | 2025 | .browser-result{ |
|
2025 | 2026 | td a{ |
|
2026 | 2027 | margin-left: 0.5em; |
|
2027 | 2028 | display: inline-block; |
|
2028 | 2029 | |
|
2029 | 2030 | em{ |
|
2030 | 2031 | font-family: @text-bold; |
|
2031 | 2032 | } |
|
2032 | 2033 | } |
|
2033 | 2034 | } |
|
2034 | 2035 | |
|
2035 | 2036 | .browser-highlight{ |
|
2036 | 2037 | background-color: @grey5-alpha; |
|
2037 | 2038 | } |
|
2038 | 2039 | |
|
2039 | 2040 | |
|
2040 | 2041 | // Search |
|
2041 | 2042 | |
|
2042 | 2043 | .search-form{ |
|
2043 | 2044 | #q { |
|
2044 | 2045 | width: @search-form-width; |
|
2045 | 2046 | } |
|
2046 | 2047 | .fields{ |
|
2047 | 2048 | margin: 0 0 @space; |
|
2048 | 2049 | } |
|
2049 | 2050 | |
|
2050 | 2051 | label{ |
|
2051 | 2052 | display: inline-block; |
|
2052 | 2053 | margin-right: @textmargin; |
|
2053 | 2054 | padding-top: 0.25em; |
|
2054 | 2055 | } |
|
2055 | 2056 | |
|
2056 | 2057 | |
|
2057 | 2058 | .results{ |
|
2058 | 2059 | clear: both; |
|
2059 | 2060 | margin: 0 0 @padding; |
|
2060 | 2061 | } |
|
2061 | 2062 | } |
|
2062 | 2063 | |
|
2063 | 2064 | div.search-feedback-items { |
|
2064 | 2065 | display: inline-block; |
|
2065 | 2066 | padding:0px 0px 0px 96px; |
|
2066 | 2067 | } |
|
2067 | 2068 | |
|
2068 | 2069 | div.search-code-body { |
|
2069 | 2070 | background-color: #ffffff; padding: 5px 0 5px 10px; |
|
2070 | 2071 | pre { |
|
2071 | 2072 | .match { background-color: #faffa6;} |
|
2072 | 2073 | .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; } |
|
2073 | 2074 | } |
|
2074 | 2075 | } |
|
2075 | 2076 | |
|
2076 | 2077 | .expand_commit.search { |
|
2077 | 2078 | .show_more.open { |
|
2078 | 2079 | height: auto; |
|
2079 | 2080 | max-height: none; |
|
2080 | 2081 | } |
|
2081 | 2082 | } |
|
2082 | 2083 | |
|
2083 | 2084 | .search-results { |
|
2084 | 2085 | |
|
2085 | 2086 | h2 { |
|
2086 | 2087 | margin-bottom: 0; |
|
2087 | 2088 | } |
|
2088 | 2089 | .codeblock { |
|
2089 | 2090 | border: none; |
|
2090 | 2091 | background: transparent; |
|
2091 | 2092 | } |
|
2092 | 2093 | |
|
2093 | 2094 | .codeblock-header { |
|
2094 | 2095 | border: none; |
|
2095 | 2096 | background: transparent; |
|
2096 | 2097 | } |
|
2097 | 2098 | |
|
2098 | 2099 | .code-body { |
|
2099 | 2100 | border: @border-thickness solid @border-default-color; |
|
2100 | 2101 | .border-radius(@border-radius); |
|
2101 | 2102 | } |
|
2102 | 2103 | |
|
2103 | 2104 | .td-commit { |
|
2104 | 2105 | &:extend(pre); |
|
2105 | 2106 | border-bottom: @border-thickness solid @border-default-color; |
|
2106 | 2107 | } |
|
2107 | 2108 | |
|
2108 | 2109 | .message { |
|
2109 | 2110 | height: auto; |
|
2110 | 2111 | max-width: 350px; |
|
2111 | 2112 | white-space: normal; |
|
2112 | 2113 | text-overflow: initial; |
|
2113 | 2114 | overflow: visible; |
|
2114 | 2115 | |
|
2115 | 2116 | .match { background-color: #faffa6;} |
|
2116 | 2117 | .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; } |
|
2117 | 2118 | } |
|
2118 | 2119 | |
|
2119 | 2120 | } |
|
2120 | 2121 | |
|
2121 | 2122 | table.rctable td.td-search-results div { |
|
2122 | 2123 | max-width: 100%; |
|
2123 | 2124 | } |
|
2124 | 2125 | |
|
2125 | 2126 | #tip-box, .tip-box{ |
|
2126 | 2127 | padding: @menupadding/2; |
|
2127 | 2128 | display: block; |
|
2128 | 2129 | border: @border-thickness solid @border-highlight-color; |
|
2129 | 2130 | .border-radius(@border-radius); |
|
2130 | 2131 | background-color: white; |
|
2131 | 2132 | z-index: 99; |
|
2132 | 2133 | white-space: pre-wrap; |
|
2133 | 2134 | } |
|
2134 | 2135 | |
|
2135 | 2136 | #linktt { |
|
2136 | 2137 | width: 79px; |
|
2137 | 2138 | } |
|
2138 | 2139 | |
|
2139 | 2140 | #help_kb .modal-content{ |
|
2140 | 2141 | max-width: 750px; |
|
2141 | 2142 | margin: 10% auto; |
|
2142 | 2143 | |
|
2143 | 2144 | table{ |
|
2144 | 2145 | td,th{ |
|
2145 | 2146 | border-bottom: none; |
|
2146 | 2147 | line-height: 2.5em; |
|
2147 | 2148 | } |
|
2148 | 2149 | th{ |
|
2149 | 2150 | padding-bottom: @textmargin/2; |
|
2150 | 2151 | } |
|
2151 | 2152 | td.keys{ |
|
2152 | 2153 | text-align: center; |
|
2153 | 2154 | } |
|
2154 | 2155 | } |
|
2155 | 2156 | |
|
2156 | 2157 | .block-left{ |
|
2157 | 2158 | width: 45%; |
|
2158 | 2159 | margin-right: 5%; |
|
2159 | 2160 | } |
|
2160 | 2161 | .modal-footer{ |
|
2161 | 2162 | clear: both; |
|
2162 | 2163 | } |
|
2163 | 2164 | .key.tag{ |
|
2164 | 2165 | padding: 0.5em; |
|
2165 | 2166 | background-color: @rcblue; |
|
2166 | 2167 | color: white; |
|
2167 | 2168 | border-color: @rcblue; |
|
2168 | 2169 | .box-shadow(none); |
|
2169 | 2170 | } |
|
2170 | 2171 | } |
|
2171 | 2172 | |
|
2172 | 2173 | |
|
2173 | 2174 | |
|
2174 | 2175 | //--- IMPORTS FOR REFACTORED STYLES ------------------// |
|
2175 | 2176 | |
|
2176 | 2177 | @import 'statistics-graph'; |
|
2177 | 2178 | @import 'tables'; |
|
2178 | 2179 | @import 'forms'; |
|
2179 | 2180 | @import 'diff'; |
|
2180 | 2181 | @import 'summary'; |
|
2181 | 2182 | @import 'navigation'; |
|
2182 | 2183 | |
|
2183 | 2184 | //--- SHOW/HIDE SECTIONS --// |
|
2184 | 2185 | |
|
2185 | 2186 | .btn-collapse { |
|
2186 | 2187 | float: right; |
|
2187 | 2188 | text-align: right; |
|
2188 | 2189 | font-family: @text-light; |
|
2189 | 2190 | font-size: @basefontsize; |
|
2190 | 2191 | cursor: pointer; |
|
2191 | 2192 | border: none; |
|
2192 | 2193 | color: @rcblue; |
|
2193 | 2194 | } |
|
2194 | 2195 | |
|
2195 | 2196 | table.rctable, |
|
2196 | 2197 | table.dataTable { |
|
2197 | 2198 | .btn-collapse { |
|
2198 | 2199 | float: right; |
|
2199 | 2200 | text-align: right; |
|
2200 | 2201 | } |
|
2201 | 2202 | } |
|
2202 | 2203 | |
|
2203 | 2204 | |
|
2204 | 2205 | // TODO: johbo: Fix for IE10, this avoids that we see a border |
|
2205 | 2206 | // and padding around checkboxes and radio boxes. Move to the right place, |
|
2206 | 2207 | // or better: Remove this once we did the form refactoring. |
|
2207 | 2208 | input[type=checkbox], |
|
2208 | 2209 | input[type=radio] { |
|
2209 | 2210 | padding: 0; |
|
2210 | 2211 | border: none; |
|
2211 | 2212 | } |
|
2212 | 2213 | |
|
2213 | 2214 | .toggle-ajax-spinner{ |
|
2214 | 2215 | height: 16px; |
|
2215 | 2216 | width: 16px; |
|
2216 | 2217 | } |
@@ -1,264 +1,265 b'' | |||
|
1 | 1 | // summary.less |
|
2 | 2 | // For use in RhodeCode applications; |
|
3 | 3 | // Used for headers and file detail summary screens. |
|
4 | 4 | |
|
5 | 5 | .summary { |
|
6 | 6 | float: left; |
|
7 | 7 | position: relative; |
|
8 | 8 | width: 100%; |
|
9 | 9 | margin: 0; |
|
10 | 10 | padding: 0; |
|
11 | 11 | |
|
12 | 12 | .summary-detail-header { |
|
13 | 13 | float: left; |
|
14 | 14 | display: block; |
|
15 | 15 | width: 100%; |
|
16 | 16 | margin-bottom: @textmargin; |
|
17 | 17 | padding: 0 0 .5em 0; |
|
18 | 18 | border-bottom: @border-thickness solid @border-default-color; |
|
19 | 19 | |
|
20 | 20 | .breadcrumbs { |
|
21 | 21 | float: left; |
|
22 | 22 | display: inline; |
|
23 | 23 | margin: 0; |
|
24 | 24 | padding: 0; |
|
25 | 25 | } |
|
26 | 26 | h4 { |
|
27 | 27 | float: left; |
|
28 | 28 | margin: 0 1em 0 0; |
|
29 | 29 | padding: 0; |
|
30 | 30 | line-height: 1.2em; |
|
31 | 31 | font-size: @basefontsize; |
|
32 | 32 | } |
|
33 | 33 | |
|
34 | 34 | .action_link { |
|
35 | 35 | float: right; |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | .new-file { |
|
39 | 39 | float: right; |
|
40 | 40 | margin-top: -1.5em; |
|
41 | 41 | } |
|
42 | 42 | } |
|
43 | 43 | |
|
44 | 44 | .summary-detail { |
|
45 | 45 | float: left; |
|
46 | 46 | position: relative; |
|
47 | 47 | width: 73%; |
|
48 | 48 | margin: 0 3% @space 0; |
|
49 | 49 | padding: 0; |
|
50 | 50 | |
|
51 | 51 | .file_diff_buttons { |
|
52 | 52 | margin-top: @space; |
|
53 | 53 | } |
|
54 | 54 | |
|
55 | 55 | // commit message |
|
56 | 56 | .commit { |
|
57 | 57 | white-space: pre-wrap; |
|
58 | 58 | } |
|
59 | 59 | |
|
60 | 60 | #clone_url, |
|
61 | 61 | #clone_url_id { |
|
62 | 62 | min-width: 29em; |
|
63 | 63 | padding: @padding/4; |
|
64 | 64 | } |
|
65 | 65 | |
|
66 | 66 | &.directory { |
|
67 | 67 | margin-bottom: 0; |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | .desc { |
|
71 | 71 | white-space: pre-wrap; |
|
72 | 72 | } |
|
73 | 73 | .disabled { |
|
74 | 74 | opacity: .5; |
|
75 | cursor: inherit; | |
|
75 | 76 | } |
|
76 | 77 | .help-block { |
|
77 | 78 | color: inherit; |
|
78 | 79 | margin: 0; |
|
79 | 80 | } |
|
80 | 81 | } |
|
81 | 82 | |
|
82 | 83 | .sidebar-right { |
|
83 | 84 | float: left; |
|
84 | 85 | width: 24%; |
|
85 | 86 | margin: 0; |
|
86 | 87 | padding: 0; |
|
87 | 88 | |
|
88 | 89 | ul { |
|
89 | 90 | margin-left: 0; |
|
90 | 91 | padding-left: 0; |
|
91 | 92 | |
|
92 | 93 | li { |
|
93 | 94 | |
|
94 | 95 | &:before { |
|
95 | 96 | content: none; |
|
96 | 97 | width: 0; |
|
97 | 98 | } |
|
98 | 99 | } |
|
99 | 100 | } |
|
100 | 101 | } |
|
101 | 102 | |
|
102 | 103 | #clone_by_name, #clone_by_id{ |
|
103 | 104 | display: inline-block; |
|
104 | 105 | margin-left: @padding; |
|
105 | 106 | } |
|
106 | 107 | |
|
107 | 108 | .codeblock { |
|
108 | 109 | border: none; |
|
109 | 110 | background-color: transparent; |
|
110 | 111 | } |
|
111 | 112 | |
|
112 | 113 | .code-body { |
|
113 | 114 | border: @border-thickness solid @border-default-color; |
|
114 | 115 | .border-radius(@border-radius); |
|
115 | 116 | } |
|
116 | 117 | } |
|
117 | 118 | |
|
118 | 119 | // this is used outside of just the summary |
|
119 | 120 | .fieldset, // similar to form fieldset |
|
120 | 121 | .summary .sidebar-right-content { // these have to match |
|
121 | 122 | clear: both; |
|
122 | 123 | float: left; |
|
123 | 124 | position: relative; |
|
124 | 125 | display:block; |
|
125 | 126 | width: 100%; |
|
126 | 127 | min-height: 1em; |
|
127 | 128 | margin-bottom: @textmargin; |
|
128 | 129 | padding: 0; |
|
129 | 130 | line-height: 1.2em; |
|
130 | 131 | |
|
131 | 132 | &:after { // clearfix |
|
132 | 133 | content: ""; |
|
133 | 134 | clear: both; |
|
134 | 135 | width: 100%; |
|
135 | 136 | height: 1em; |
|
136 | 137 | } |
|
137 | 138 | } |
|
138 | 139 | |
|
139 | 140 | .summary .sidebar-right-content { |
|
140 | 141 | margin-bottom: @space; |
|
141 | 142 | |
|
142 | 143 | .rc-user { |
|
143 | 144 | min-width: 0; |
|
144 | 145 | } |
|
145 | 146 | } |
|
146 | 147 | |
|
147 | 148 | .fieldset { |
|
148 | 149 | |
|
149 | 150 | .left-label { // similar to form legend |
|
150 | 151 | float: left; |
|
151 | 152 | display: block; |
|
152 | 153 | width: 25%; |
|
153 | 154 | margin: 0; |
|
154 | 155 | padding: 0; |
|
155 | 156 | font-family: @text-semibold; |
|
156 | 157 | } |
|
157 | 158 | |
|
158 | 159 | .right-content { // similar to form fields |
|
159 | 160 | float: left; |
|
160 | 161 | display: block; |
|
161 | 162 | width: 75%; |
|
162 | 163 | margin: 0 0 0 -15%; |
|
163 | 164 | padding: 0 0 0 15%; |
|
164 | 165 | |
|
165 | 166 | .truncate-wrap, |
|
166 | 167 | .truncate { |
|
167 | 168 | max-width: 100%; |
|
168 | 169 | width: 100%; |
|
169 | 170 | } |
|
170 | 171 | |
|
171 | 172 | .commit-long { |
|
172 | 173 | overflow-x: auto; |
|
173 | 174 | } |
|
174 | 175 | } |
|
175 | 176 | .commit.truncate-wrap { |
|
176 | 177 | overflow:hidden; |
|
177 | 178 | text-overflow: ellipsis; |
|
178 | 179 | } |
|
179 | 180 | } |
|
180 | 181 | |
|
181 | 182 | // expand commit message |
|
182 | 183 | #message_expand { |
|
183 | 184 | clear: both; |
|
184 | 185 | display: block; |
|
185 | 186 | color: @rcblue; |
|
186 | 187 | cursor: pointer; |
|
187 | 188 | } |
|
188 | 189 | |
|
189 | 190 | #trimmed_message_box { |
|
190 | 191 | max-height: floor(2 * @basefontsize * 1.2); // 2 lines * line-height |
|
191 | 192 | overflow: hidden; |
|
192 | 193 | } |
|
193 | 194 | |
|
194 | 195 | // show/hide comments button |
|
195 | 196 | .show-inline-comments { |
|
196 | 197 | display: inline; |
|
197 | 198 | cursor: pointer; |
|
198 | 199 | |
|
199 | 200 | .comments-show { display: inline; } |
|
200 | 201 | .comments-hide { display: none; } |
|
201 | 202 | |
|
202 | 203 | &.comments-visible { |
|
203 | 204 | .comments-show { display: none; } |
|
204 | 205 | .comments-hide { display: inline; } |
|
205 | 206 | } |
|
206 | 207 | } |
|
207 | 208 | |
|
208 | 209 | // Quick Start section |
|
209 | 210 | .quick_start { |
|
210 | 211 | float: left; |
|
211 | 212 | display: block; |
|
212 | 213 | position: relative; |
|
213 | 214 | |
|
214 | 215 | // adds some space to make copy and paste easier |
|
215 | 216 | .left-label, |
|
216 | 217 | .right-content { |
|
217 | 218 | line-height: 1.6em; |
|
218 | 219 | } |
|
219 | 220 | } |
|
220 | 221 | |
|
221 | 222 | .submodule { |
|
222 | 223 | .summary-detail { |
|
223 | 224 | width: 100%; |
|
224 | 225 | |
|
225 | 226 | .btn-collapse { |
|
226 | 227 | display: none; |
|
227 | 228 | } |
|
228 | 229 | } |
|
229 | 230 | } |
|
230 | 231 | |
|
231 | 232 | .codeblock-header { |
|
232 | 233 | float: left; |
|
233 | 234 | display: block; |
|
234 | 235 | width: 100%; |
|
235 | 236 | margin: 0; |
|
236 | 237 | padding: @space 0 @padding 0; |
|
237 | 238 | border-top: @border-thickness solid @border-default-color; |
|
238 | 239 | |
|
239 | 240 | .stats { |
|
240 | 241 | float: left; |
|
241 | 242 | width: 50%; |
|
242 | 243 | } |
|
243 | 244 | |
|
244 | 245 | .buttons { |
|
245 | 246 | float: right; |
|
246 | 247 | width: 50%; |
|
247 | 248 | text-align: right; |
|
248 | 249 | color: @grey4; |
|
249 | 250 | } |
|
250 | 251 | } |
|
251 | 252 | |
|
252 | 253 | #summary-menu-stats { |
|
253 | 254 | |
|
254 | 255 | .stats-bullet { |
|
255 | 256 | color: @grey3; |
|
256 | 257 | min-width: 3em; |
|
257 | 258 | } |
|
258 | 259 | |
|
259 | 260 | .repo-size { |
|
260 | 261 | margin-bottom: .5em; |
|
261 | 262 | } |
|
262 | 263 | |
|
263 | 264 | } |
|
264 | 265 |
@@ -1,174 +1,184 b'' | |||
|
1 | 1 | // # Copyright (C) 2010-2016 RhodeCode GmbH |
|
2 | 2 | // # |
|
3 | 3 | // # This program is free software: you can redistribute it and/or modify |
|
4 | 4 | // # it under the terms of the GNU Affero General Public License, version 3 |
|
5 | 5 | // # (only), as published by the Free Software Foundation. |
|
6 | 6 | // # |
|
7 | 7 | // # This program is distributed in the hope that it will be useful, |
|
8 | 8 | // # but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
9 | 9 | // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
10 | 10 | // # GNU General Public License for more details. |
|
11 | 11 | // # |
|
12 | 12 | // # You should have received a copy of the GNU Affero General Public License |
|
13 | 13 | // # along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
14 | 14 | // # |
|
15 | 15 | // # This program is dual-licensed. If you wish to learn more about the |
|
16 | 16 | // # RhodeCode Enterprise Edition, including its added features, Support services, |
|
17 | 17 | // # and proprietary license terms, please see https://rhodecode.com/licenses/ |
|
18 | 18 | |
|
19 | 19 | /** |
|
20 | 20 | * INJECT .format function into String |
|
21 | 21 | * Usage: "My name is {0} {1}".format("Johny","Bravo") |
|
22 | 22 | * Return "My name is Johny Bravo" |
|
23 | 23 | * Inspired by https://gist.github.com/1049426 |
|
24 | 24 | */ |
|
25 | 25 | String.prototype.format = function() { |
|
26 | 26 | |
|
27 | 27 | function format() { |
|
28 | 28 | var str = this; |
|
29 | 29 | var len = arguments.length+1; |
|
30 | 30 | var safe = undefined; |
|
31 | 31 | var arg = undefined; |
|
32 | 32 | |
|
33 | 33 | // For each {0} {1} {n...} replace with the argument in that position. If |
|
34 | 34 | // the argument is an object or an array it will be stringified to JSON. |
|
35 | 35 | for (var i=0; i < len; arg = arguments[i++]) { |
|
36 | 36 | safe = typeof arg === 'object' ? JSON.stringify(arg) : arg; |
|
37 | 37 | str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe); |
|
38 | 38 | } |
|
39 | 39 | return str; |
|
40 | 40 | } |
|
41 | 41 | |
|
42 | 42 | // Save a reference of what may already exist under the property native. |
|
43 | 43 | // Allows for doing something like: if("".format.native) { /* use native */ } |
|
44 | 44 | format.native = String.prototype.format; |
|
45 | 45 | |
|
46 | 46 | // Replace the prototype property |
|
47 | 47 | return format; |
|
48 | 48 | }(); |
|
49 | 49 | |
|
50 | 50 | String.prototype.strip = function(char) { |
|
51 | 51 | if(char === undefined){ |
|
52 | 52 | char = '\\s'; |
|
53 | 53 | } |
|
54 | 54 | return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), ''); |
|
55 | 55 | }; |
|
56 | 56 | |
|
57 | 57 | String.prototype.lstrip = function(char) { |
|
58 | 58 | if(char === undefined){ |
|
59 | 59 | char = '\\s'; |
|
60 | 60 | } |
|
61 | 61 | return this.replace(new RegExp('^'+char+'+'),''); |
|
62 | 62 | }; |
|
63 | 63 | |
|
64 | 64 | String.prototype.rstrip = function(char) { |
|
65 | 65 | if(char === undefined){ |
|
66 | 66 | char = '\\s'; |
|
67 | 67 | } |
|
68 | 68 | return this.replace(new RegExp(''+char+'+$'),''); |
|
69 | 69 | }; |
|
70 | 70 | |
|
71 | 71 | String.prototype.capitalizeFirstLetter = function() { |
|
72 | 72 | return this.charAt(0).toUpperCase() + this.slice(1); |
|
73 | 73 | }; |
|
74 | 74 | |
|
75 | 75 | |
|
76 | String.prototype.truncateAfter = function(chars, suffix) { | |
|
77 | var suffix = suffix || ''; | |
|
78 | if (this.length > chars) { | |
|
79 | return this.substr(0, chars) + suffix; | |
|
80 | } else { | |
|
81 | return this; | |
|
82 | } | |
|
83 | }; | |
|
84 | ||
|
85 | ||
|
76 | 86 | /** |
|
77 | 87 | * Splits remainder |
|
78 | 88 | * |
|
79 | 89 | * @param input |
|
80 | 90 | */ |
|
81 | 91 | function splitDelimitedHash(input){ |
|
82 | 92 | var splitIx = input.indexOf('/?/'); |
|
83 | 93 | if (splitIx !== -1){ |
|
84 | 94 | var loc = input.slice(0, splitIx); |
|
85 | 95 | var remainder = input.slice(splitIx + 2); |
|
86 | 96 | } |
|
87 | 97 | else{ |
|
88 | 98 | var loc = input; |
|
89 | 99 | var remainder = null; |
|
90 | 100 | } |
|
91 | 101 | //fixes for some urls generated incorrectly |
|
92 | 102 | var result = loc.match('#+(.*)'); |
|
93 | 103 | if (result !== null){ |
|
94 | 104 | loc = '#' + result[1]; |
|
95 | 105 | } |
|
96 | 106 | return {loc:loc, remainder: remainder} |
|
97 | 107 | } |
|
98 | 108 | |
|
99 | 109 | /** |
|
100 | 110 | * Escape html characters in string |
|
101 | 111 | */ |
|
102 | 112 | var entityMap = { |
|
103 | 113 | "&": "&", |
|
104 | 114 | "<": "<", |
|
105 | 115 | ">": ">", |
|
106 | 116 | '"': '"', |
|
107 | 117 | "'": ''', |
|
108 | 118 | "/": '/' |
|
109 | 119 | }; |
|
110 | 120 | |
|
111 | 121 | function escapeHtml(string) { |
|
112 | 122 | return String(string).replace(/[&<>"'\/]/g, function (s) { |
|
113 | 123 | return entityMap[s]; |
|
114 | 124 | }); |
|
115 | 125 | } |
|
116 | 126 | |
|
117 | 127 | /** encode/decode html special chars**/ |
|
118 | 128 | var htmlEnDeCode = (function() { |
|
119 | 129 | var charToEntityRegex, |
|
120 | 130 | entityToCharRegex, |
|
121 | 131 | charToEntity, |
|
122 | 132 | entityToChar; |
|
123 | 133 | |
|
124 | 134 | function resetCharacterEntities() { |
|
125 | 135 | charToEntity = {}; |
|
126 | 136 | entityToChar = {}; |
|
127 | 137 | // add the default set |
|
128 | 138 | addCharacterEntities({ |
|
129 | 139 | '&' : '&', |
|
130 | 140 | '>' : '>', |
|
131 | 141 | '<' : '<', |
|
132 | 142 | '"' : '"', |
|
133 | 143 | ''' : "'" |
|
134 | 144 | }); |
|
135 | 145 | } |
|
136 | 146 | |
|
137 | 147 | function addCharacterEntities(newEntities) { |
|
138 | 148 | var charKeys = [], |
|
139 | 149 | entityKeys = [], |
|
140 | 150 | key, echar; |
|
141 | 151 | for (key in newEntities) { |
|
142 | 152 | echar = newEntities[key]; |
|
143 | 153 | entityToChar[key] = echar; |
|
144 | 154 | charToEntity[echar] = key; |
|
145 | 155 | charKeys.push(echar); |
|
146 | 156 | entityKeys.push(key); |
|
147 | 157 | } |
|
148 | 158 | charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g'); |
|
149 | 159 | entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g'); |
|
150 | 160 | } |
|
151 | 161 | |
|
152 | 162 | function htmlEncode(value){ |
|
153 | 163 | var htmlEncodeReplaceFn = function(match, capture) { |
|
154 | 164 | return charToEntity[capture]; |
|
155 | 165 | }; |
|
156 | 166 | |
|
157 | 167 | return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn); |
|
158 | 168 | } |
|
159 | 169 | |
|
160 | 170 | function htmlDecode(value) { |
|
161 | 171 | var htmlDecodeReplaceFn = function(match, capture) { |
|
162 | 172 | return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10)); |
|
163 | 173 | }; |
|
164 | 174 | |
|
165 | 175 | return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn); |
|
166 | 176 | } |
|
167 | 177 | |
|
168 | 178 | resetCharacterEntities(); |
|
169 | 179 | |
|
170 | 180 | return { |
|
171 | 181 | htmlEncode: htmlEncode, |
|
172 | 182 | htmlDecode: htmlDecode |
|
173 | 183 | }; |
|
174 | 184 | })(); |
@@ -1,314 +1,314 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | 2 | |
|
3 | 3 | <%inherit file="/base/base.html"/> |
|
4 | 4 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
5 | 5 | |
|
6 | 6 | <%def name="title()"> |
|
7 | 7 | ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)} |
|
8 | 8 | %if c.rhodecode_name: |
|
9 | 9 | · ${h.branding(c.rhodecode_name)} |
|
10 | 10 | %endif |
|
11 | 11 | </%def> |
|
12 | 12 | |
|
13 | 13 | <%def name="menu_bar_nav()"> |
|
14 | 14 | ${self.menu_items(active='repositories')} |
|
15 | 15 | </%def> |
|
16 | 16 | |
|
17 | 17 | <%def name="menu_bar_subnav()"> |
|
18 | 18 | ${self.repo_menu(active='changelog')} |
|
19 | 19 | </%def> |
|
20 | 20 | |
|
21 | 21 | <%def name="main()"> |
|
22 | 22 | <script> |
|
23 | 23 | // TODO: marcink switch this to pyroutes |
|
24 | 24 | AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}"; |
|
25 | 25 | templateContext.commit_data.commit_id = "${c.commit.raw_id}"; |
|
26 | 26 | </script> |
|
27 | 27 | <div class="box"> |
|
28 | 28 | <div class="title"> |
|
29 | 29 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
30 | 30 | </div> |
|
31 | 31 | |
|
32 | 32 | <div id="changeset_compare_view_content" class="summary changeset"> |
|
33 | 33 | <div class="summary-detail"> |
|
34 | 34 | <div class="summary-detail-header"> |
|
35 | 35 | <span class="breadcrumbs files_location"> |
|
36 | 36 | <h4>${_('Commit')} |
|
37 | 37 | <code> |
|
38 | 38 | ${h.show_id(c.commit)} |
|
39 | 39 | </code> |
|
40 | 40 | </h4> |
|
41 | 41 | </span> |
|
42 | 42 | <span id="parent_link"> |
|
43 | 43 | <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a> |
|
44 | 44 | </span> |
|
45 | 45 | | |
|
46 | 46 | <span id="child_link"> |
|
47 | 47 | <a href="#" title="${_('Child Commit')}">${_('Child')}</a> |
|
48 | 48 | </span> |
|
49 | 49 | </div> |
|
50 | 50 | |
|
51 | 51 | <div class="fieldset"> |
|
52 | 52 | <div class="left-label"> |
|
53 | 53 | ${_('Description')}: |
|
54 | 54 | </div> |
|
55 | 55 | <div class="right-content"> |
|
56 | 56 | <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div> |
|
57 | 57 | <div id="message_expand" style="display:none;"> |
|
58 | 58 | ${_('Expand')} |
|
59 | 59 | </div> |
|
60 | 60 | </div> |
|
61 | 61 | </div> |
|
62 | 62 | |
|
63 | 63 | %if c.statuses: |
|
64 | 64 | <div class="fieldset"> |
|
65 | 65 | <div class="left-label"> |
|
66 | 66 | ${_('Commit status')}: |
|
67 | 67 | </div> |
|
68 | 68 | <div class="right-content"> |
|
69 | 69 | <div class="changeset-status-ico"> |
|
70 | 70 | <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div> |
|
71 | 71 | </div> |
|
72 | 72 | <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div> |
|
73 | 73 | </div> |
|
74 | 74 | </div> |
|
75 | 75 | %endif |
|
76 | 76 | |
|
77 | 77 | <div class="fieldset"> |
|
78 | 78 | <div class="left-label"> |
|
79 | 79 | ${_('References')}: |
|
80 | 80 | </div> |
|
81 | 81 | <div class="right-content"> |
|
82 | 82 | <div class="tags"> |
|
83 | 83 | |
|
84 | 84 | %if c.commit.merge: |
|
85 | 85 | <span class="mergetag tag"> |
|
86 | 86 | <i class="icon-merge"></i>${_('merge')} |
|
87 | 87 | </span> |
|
88 | 88 | %endif |
|
89 | 89 | |
|
90 | 90 | %if h.is_hg(c.rhodecode_repo): |
|
91 | 91 | %for book in c.commit.bookmarks: |
|
92 | 92 | <span class="booktag tag" title="${_('Bookmark %s') % book}"> |
|
93 | 93 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-bookmark"></i>${h.shorter(book)}</a> |
|
94 | 94 | </span> |
|
95 | 95 | %endfor |
|
96 | 96 | %endif |
|
97 | 97 | |
|
98 | 98 | %for tag in c.commit.tags: |
|
99 | 99 | <span class="tagtag tag" title="${_('Tag %s') % tag}"> |
|
100 | 100 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a> |
|
101 | 101 | </span> |
|
102 | 102 | %endfor |
|
103 | 103 | |
|
104 | 104 | %if c.commit.branch: |
|
105 | 105 | <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}"> |
|
106 | 106 | <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-code-fork"></i>${h.shorter(c.commit.branch)}</a> |
|
107 | 107 | </span> |
|
108 | 108 | %endif |
|
109 | 109 | </div> |
|
110 | 110 | </div> |
|
111 | 111 | </div> |
|
112 | 112 | |
|
113 | 113 | <div class="fieldset"> |
|
114 | 114 | <div class="left-label"> |
|
115 | ${_('Diffs')}: | |
|
115 | ${_('Diff options')}: | |
|
116 | 116 | </div> |
|
117 | 117 | <div class="right-content"> |
|
118 | 118 | <div class="diff-actions"> |
|
119 | 119 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> |
|
120 | 120 | ${_('Raw Diff')} |
|
121 | 121 | </a> |
|
122 | 122 | | |
|
123 | 123 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision=c.commit.raw_id)}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> |
|
124 | 124 | ${_('Patch Diff')} |
|
125 | 125 | </a> |
|
126 | 126 | | |
|
127 | 127 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision=c.commit.raw_id,diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> |
|
128 | 128 | ${_('Download Diff')} |
|
129 | 129 | </a> |
|
130 | 130 | | |
|
131 | 131 | ${c.ignorews_url(request.GET)} |
|
132 | 132 | | |
|
133 | 133 | ${c.context_url(request.GET)} |
|
134 | 134 | </div> |
|
135 | 135 | </div> |
|
136 | 136 | </div> |
|
137 | 137 | |
|
138 | 138 | <div class="fieldset"> |
|
139 | 139 | <div class="left-label"> |
|
140 | 140 | ${_('Comments')}: |
|
141 | 141 | </div> |
|
142 | 142 | <div class="right-content"> |
|
143 | 143 | <div class="comments-number"> |
|
144 | 144 | %if c.comments: |
|
145 | 145 | <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>, |
|
146 | 146 | %else: |
|
147 | 147 | ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)} |
|
148 | 148 | %endif |
|
149 | 149 | %if c.inline_cnt: |
|
150 | 150 | <a href="#" onclick="return Rhodecode.comments.nextComment();" id="inline-comments-counter">${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}</a> |
|
151 | 151 | %else: |
|
152 | 152 | ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt} |
|
153 | 153 | %endif |
|
154 | 154 | </div> |
|
155 | 155 | </div> |
|
156 | 156 | </div> |
|
157 | 157 | |
|
158 | 158 | </div> <!-- end summary-detail --> |
|
159 | 159 | |
|
160 | 160 | <div id="commit-stats" class="sidebar-right"> |
|
161 | 161 | <div class="summary-detail-header"> |
|
162 | 162 | <h4 class="item"> |
|
163 | 163 | ${_('Author')} |
|
164 | 164 | </h4> |
|
165 | 165 | </div> |
|
166 | 166 | <div class="sidebar-right-content"> |
|
167 | 167 | ${self.gravatar_with_user(c.commit.author)} |
|
168 | 168 | <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div> |
|
169 | 169 | </div> |
|
170 | 170 | </div><!-- end sidebar --> |
|
171 | 171 | </div> <!-- end summary --> |
|
172 | 172 | <div class="cs_files"> |
|
173 | 173 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> |
|
174 | 174 | ${cbdiffs.render_diffset_menu()} |
|
175 | 175 | ${cbdiffs.render_diffset( |
|
176 | 176 | c.changes[c.commit.raw_id], commit=c.commit, use_comments=True)} |
|
177 | 177 | </div> |
|
178 | 178 | |
|
179 | 179 | ## template for inline comment form |
|
180 | 180 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
181 | 181 | |
|
182 | 182 | ## render comments |
|
183 | 183 | ${comment.generate_comments()} |
|
184 | 184 | |
|
185 | 185 | ## main comment form and it status |
|
186 | 186 | ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id), |
|
187 | 187 | h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))} |
|
188 | 188 | </div> |
|
189 | 189 | |
|
190 | 190 | ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS |
|
191 | 191 | <script type="text/javascript"> |
|
192 | 192 | |
|
193 | 193 | $(document).ready(function() { |
|
194 | 194 | |
|
195 | 195 | var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10); |
|
196 | 196 | if($('#trimmed_message_box').height() === boxmax){ |
|
197 | 197 | $('#message_expand').show(); |
|
198 | 198 | } |
|
199 | 199 | |
|
200 | 200 | $('#message_expand').on('click', function(e){ |
|
201 | 201 | $('#trimmed_message_box').css('max-height', 'none'); |
|
202 | 202 | $(this).hide(); |
|
203 | 203 | }); |
|
204 | 204 | |
|
205 | 205 | $('.show-inline-comments').on('click', function(e){ |
|
206 | 206 | var boxid = $(this).attr('data-comment-id'); |
|
207 | 207 | var button = $(this); |
|
208 | 208 | |
|
209 | 209 | if(button.hasClass("comments-visible")) { |
|
210 | 210 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
211 | 211 | $(this).hide(); |
|
212 | 212 | }); |
|
213 | 213 | button.removeClass("comments-visible"); |
|
214 | 214 | } else { |
|
215 | 215 | $('#{0} .inline-comments'.format(boxid)).each(function(index){ |
|
216 | 216 | $(this).show(); |
|
217 | 217 | }); |
|
218 | 218 | button.addClass("comments-visible"); |
|
219 | 219 | } |
|
220 | 220 | }); |
|
221 | 221 | |
|
222 | 222 | |
|
223 | 223 | // next links |
|
224 | 224 | $('#child_link').on('click', function(e){ |
|
225 | 225 | // fetch via ajax what is going to be the next link, if we have |
|
226 | 226 | // >1 links show them to user to choose |
|
227 | 227 | if(!$('#child_link').hasClass('disabled')){ |
|
228 | 228 | $.ajax({ |
|
229 | 229 | url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}', |
|
230 | 230 | success: function(data) { |
|
231 | 231 | if(data.results.length === 0){ |
|
232 | 232 | $('#child_link').html("${_('No Child Commits')}").addClass('disabled'); |
|
233 | 233 | } |
|
234 | 234 | if(data.results.length === 1){ |
|
235 | 235 | var commit = data.results[0]; |
|
236 | 236 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); |
|
237 | 237 | } |
|
238 | 238 | else if(data.results.length === 2){ |
|
239 | 239 | $('#child_link').addClass('disabled'); |
|
240 | 240 | $('#child_link').addClass('double'); |
|
241 | 241 | var _html = ''; |
|
242 | 242 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
243 | 243 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
244 | 244 | .replace('__title__', data.results[0].message) |
|
245 | 245 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); |
|
246 | 246 | _html +=' | ' |
|
247 | 247 | _html +='<a title="__title__" href="__url__">__rev__</a> ' |
|
248 | 248 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
249 | 249 | .replace('__title__', data.results[1].message) |
|
250 | 250 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); |
|
251 | 251 | $('#child_link').html(_html); |
|
252 | 252 | } |
|
253 | 253 | } |
|
254 | 254 | }); |
|
255 | 255 | e.preventDefault(); |
|
256 | 256 | } |
|
257 | 257 | }); |
|
258 | 258 | |
|
259 | 259 | // prev links |
|
260 | 260 | $('#parent_link').on('click', function(e){ |
|
261 | 261 | // fetch via ajax what is going to be the next link, if we have |
|
262 | 262 | // >1 links show them to user to choose |
|
263 | 263 | if(!$('#parent_link').hasClass('disabled')){ |
|
264 | 264 | $.ajax({ |
|
265 | 265 | url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}', |
|
266 | 266 | success: function(data) { |
|
267 | 267 | if(data.results.length === 0){ |
|
268 | 268 | $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled'); |
|
269 | 269 | } |
|
270 | 270 | if(data.results.length === 1){ |
|
271 | 271 | var commit = data.results[0]; |
|
272 | 272 | window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id}); |
|
273 | 273 | } |
|
274 | 274 | else if(data.results.length === 2){ |
|
275 | 275 | $('#parent_link').addClass('disabled'); |
|
276 | 276 | $('#parent_link').addClass('double'); |
|
277 | 277 | var _html = ''; |
|
278 | 278 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
279 | 279 | .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6))) |
|
280 | 280 | .replace('__title__', data.results[0].message) |
|
281 | 281 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id})); |
|
282 | 282 | _html +=' | ' |
|
283 | 283 | _html +='<a title="__title__" href="__url__">Parent __rev__</a>' |
|
284 | 284 | .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6))) |
|
285 | 285 | .replace('__title__', data.results[1].message) |
|
286 | 286 | .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id})); |
|
287 | 287 | $('#parent_link').html(_html); |
|
288 | 288 | } |
|
289 | 289 | } |
|
290 | 290 | }); |
|
291 | 291 | e.preventDefault(); |
|
292 | 292 | } |
|
293 | 293 | }); |
|
294 | 294 | |
|
295 | 295 | if (location.hash) { |
|
296 | 296 | var result = splitDelimitedHash(location.hash); |
|
297 | 297 | var line = $('html').find(result.loc); |
|
298 | 298 | if (line.length > 0){ |
|
299 | 299 | offsetScroll(line, 70); |
|
300 | 300 | } |
|
301 | 301 | } |
|
302 | 302 | |
|
303 | 303 | // browse tree @ revision |
|
304 | 304 | $('#files_link').on('click', function(e){ |
|
305 | 305 | window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}'; |
|
306 | 306 | e.preventDefault(); |
|
307 | 307 | }); |
|
308 | 308 | |
|
309 | 309 | // inject comments into their proper positions |
|
310 | 310 | var file_comments = $('.inline-comment-placeholder'); |
|
311 | 311 | }) |
|
312 | 312 | </script> |
|
313 | 313 | |
|
314 | 314 | </%def> |
@@ -1,71 +1,125 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | 2 | <%inherit file="/base/base.html"/> |
|
3 | 3 | |
|
4 | 4 | <%def name="title()"> |
|
5 | 5 | ${_('%s Commits') % c.repo_name} - |
|
6 | 6 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} |
|
7 | 7 | ... |
|
8 | 8 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} |
|
9 | 9 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} |
|
10 | 10 | %if c.rhodecode_name: |
|
11 | 11 | · ${h.branding(c.rhodecode_name)} |
|
12 | 12 | %endif |
|
13 | 13 | </%def> |
|
14 | 14 | |
|
15 | 15 | <%def name="breadcrumbs_links()"> |
|
16 | 16 | ${_('Commits')} - |
|
17 | 17 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)} |
|
18 | 18 | ... |
|
19 | 19 | r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} |
|
20 | 20 | ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)} |
|
21 | 21 | </%def> |
|
22 | 22 | |
|
23 | 23 | <%def name="menu_bar_nav()"> |
|
24 | 24 | ${self.menu_items(active='repositories')} |
|
25 | 25 | </%def> |
|
26 | 26 | |
|
27 | 27 | <%def name="menu_bar_subnav()"> |
|
28 | 28 | ${self.repo_menu(active='changelog')} |
|
29 | 29 | </%def> |
|
30 | 30 | |
|
31 | 31 | <%def name="main()"> |
|
32 | <div class="summary-header"> | |
|
32 | <div class="summary-header"> | |
|
33 | 33 | <div class="title"> |
|
34 | <div class="title-content"> | |
|
35 | 34 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
36 | </div> | |
|
37 | </div> | |
|
38 | <div class="header-buttons"> | |
|
39 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}" | |
|
40 | class="btn btn-default"> | |
|
41 | ${_('Show combined compare')} | |
|
42 | </a> | |
|
43 | 35 | </div> |
|
44 | </div> | |
|
36 | </div> | |
|
37 | ||
|
38 | ||
|
39 | <div class="summary changeset"> | |
|
40 | <div class="summary-detail"> | |
|
41 | <div class="summary-detail-header"> | |
|
42 | <span class="breadcrumbs files_location"> | |
|
43 | <h4> | |
|
44 | ${_('Commit Range')} | |
|
45 | <code> | |
|
46 | r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}...r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)} | |
|
47 | </code> | |
|
48 | </h4> | |
|
49 | </span> | |
|
50 | </div> | |
|
51 | ||
|
52 | <div class="fieldset"> | |
|
53 | <div class="left-label"> | |
|
54 | ${_('Diff option')}: | |
|
55 | </div> | |
|
56 | <div class="right-content"> | |
|
57 | <div class="header-buttons"> | |
|
58 | <a href="${h.url('compare_url', repo_name=c.repo_name, source_ref_type='rev', source_ref=getattr(c.commit_ranges[0].parents[0] if c.commit_ranges[0].parents else h.EmptyCommit(), 'raw_id'), target_ref_type='rev', target_ref=c.commit_ranges[-1].raw_id)}"> | |
|
59 | ${_('Show combined compare')} | |
|
60 | </a> | |
|
61 | </div> | |
|
62 | </div> | |
|
63 | </div> | |
|
45 | 64 | |
|
46 | <div class="summary-detail"> | |
|
47 | <div class="title"> | |
|
48 | <h2> | |
|
49 | ${self.breadcrumbs_links()} | |
|
50 | </h2> | |
|
65 | <%doc> | |
|
66 | ##TODO(marcink): implement this and diff menus | |
|
67 | <div class="fieldset"> | |
|
68 | <div class="left-label"> | |
|
69 | ${_('Diff options')}: | |
|
70 | </div> | |
|
71 | <div class="right-content"> | |
|
72 | <div class="diff-actions"> | |
|
73 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
|
74 | ${_('Raw Diff')} | |
|
75 | </a> | |
|
76 | | | |
|
77 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |
|
78 | ${_('Patch Diff')} | |
|
79 | </a> | |
|
80 | | | |
|
81 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |
|
82 | ${_('Download Diff')} | |
|
83 | </a> | |
|
84 | </div> | |
|
85 | </div> | |
|
86 | </div> | |
|
87 | </%doc> | |
|
88 | </div> <!-- end summary-detail --> | |
|
89 | ||
|
90 | </div> <!-- end summary --> | |
|
91 | ||
|
92 | <div id="changeset_compare_view_content"> | |
|
93 | <div class="pull-left"> | |
|
94 | <div class="btn-group"> | |
|
95 | <a | |
|
96 | class="btn" | |
|
97 | href="#" | |
|
98 | onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false"> | |
|
99 | ${ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |
|
100 | </a> | |
|
101 | <a | |
|
102 | class="btn" | |
|
103 | href="#" | |
|
104 | onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false"> | |
|
105 | ${ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |
|
106 | </a> | |
|
107 | </div> | |
|
51 | 108 | </div> |
|
52 | </div> | |
|
53 | <div id="changeset_compare_view_content"> | |
|
54 | ##CS | |
|
109 | ## Commit range generated below | |
|
55 | 110 | <%include file="../compare/compare_commits.html"/> |
|
56 | 111 | <div class="cs_files"> |
|
57 | 112 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> |
|
58 | 113 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
59 | 114 | <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
60 | 115 | ${cbdiffs.render_diffset_menu()} |
|
61 | 116 | %for commit in c.commit_ranges: |
|
62 | 117 | ${cbdiffs.render_diffset( |
|
63 | 118 | diffset=c.changes[commit.raw_id], |
|
64 | 119 | collapse_when_files_over=5, |
|
65 | 120 | commit=commit, |
|
66 | 121 | )} |
|
67 | 122 | %endfor |
|
68 | </table> | |
|
69 | 123 | </div> |
|
70 | 124 | </div> |
|
71 | 125 | </%def> |
@@ -1,103 +1,64 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | 2 | ##usage: |
|
3 | 3 | ## <%namespace name="diff_block" file="/changeset/diff_block.html"/> |
|
4 | 4 | ## ${diff_block.diff_block_changeset_table(change)} |
|
5 | 5 | ## |
|
6 | 6 | <%def name="changeset_message()"> |
|
7 | 7 | <h5>${_('The requested commit is too big and content was truncated.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5> |
|
8 | 8 | </%def> |
|
9 | 9 | <%def name="file_message()"> |
|
10 | 10 | <h5>${_('The requested file is too big and its content is not shown.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5> |
|
11 | 11 | </%def> |
|
12 | 12 | |
|
13 | 13 | <%def name="diff_block_changeset_table(change)"> |
|
14 | 14 | <div class="diff-container" id="${'diff-container-%s' % (id(change))}"> |
|
15 | 15 | %for FID,(cs1, cs2, change, filenode_path, diff, stats, file) in change.iteritems(): |
|
16 | 16 | <div id="${h.FID('',filenode_path)}_target" ></div> |
|
17 | 17 | <div id="${h.FID('',filenode_path)}" class="diffblock margined comm"> |
|
18 | 18 | <div class="code-body"> |
|
19 | 19 | <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none"></div> |
|
20 | 20 | ${diff|n} |
|
21 | 21 | % if file["is_limited_diff"]: |
|
22 | 22 | % if file["exceeds_limit"]: |
|
23 | 23 | ${self.file_message()} |
|
24 | 24 | % else: |
|
25 | 25 | <h5>${_('Diff was truncated. File content available only in full diff.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5> |
|
26 | 26 | % endif |
|
27 | 27 | % endif |
|
28 | 28 | </div> |
|
29 | 29 | </div> |
|
30 | 30 | %endfor |
|
31 | 31 | </div> |
|
32 | 32 | </%def> |
|
33 | 33 | |
|
34 | 34 | <%def name="diff_block_simple(change)"> |
|
35 | 35 | <div class="diff-container" id="${'diff-container-%s' % (id(change))}"> |
|
36 | 36 | %for op,filenode_path,diff,file in change: |
|
37 | 37 | <div id="${h.FID('',filenode_path)}_target" ></div> |
|
38 | 38 | <div id="${h.FID('',filenode_path)}" class="diffblock margined comm" > |
|
39 | 39 | <div class="code-body"> |
|
40 | 40 | <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none;"></div> |
|
41 | 41 | ${diff|n} |
|
42 | 42 | % if file["is_limited_diff"]: |
|
43 | 43 | % if file["exceeds_limit"]: |
|
44 | 44 | ${self.file_message()} |
|
45 | 45 | % else: |
|
46 | 46 | <h5>${_('Diff was truncated. File content available only in full diff.')} <a href="${h.url.current(fulldiff=1, **request.GET.mixed())}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a></h5> |
|
47 | 47 | % endif |
|
48 | 48 | % endif |
|
49 | 49 | </div> |
|
50 | 50 | </div> |
|
51 | 51 | %endfor |
|
52 | 52 | </div> |
|
53 | 53 | </%def> |
|
54 | 54 | |
|
55 | <%def name="diff_menu(repo_name, f_path, cs1, cs2, change, file=None)"> | |
|
56 | <% | |
|
57 | onclick_diff2way = '' | |
|
58 | if (file and file["exceeds_limit"]): | |
|
59 | onclick_diff2way = '''return confirm('%s');''' % _("Showing a big diff might take some time and resources, continue?") | |
|
60 | %> | |
|
61 | ||
|
62 | % if change in ['A', 'M']: | |
|
63 | <a href="${h.url('files_home',repo_name=repo_name,f_path=f_path,revision=cs2)}" | |
|
64 | class="tooltip" title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': cs2[:12]})}"> | |
|
65 | ${_('Show File')} | |
|
66 | </a> | |
|
67 | % else: | |
|
68 | <span | |
|
69 | class="tooltip" title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': cs2[:12]})}"> | |
|
70 | ${_('Show File')} | |
|
71 | </span> | |
|
72 | % endif | |
|
73 | | | |
|
74 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" | |
|
75 | class="tooltip" title="${h.tooltip(_('Show full diff for this file'))}"> | |
|
76 | ${_('Unified Diff')} | |
|
77 | </a> | |
|
78 | | | |
|
79 | <a href="${h.url('files_diff_2way_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='diff',fulldiff=1)}" | |
|
80 | class="tooltip" title="${h.tooltip(_('Show full side-by-side diff for this file'))}"} onclick="${onclick_diff2way}"> | |
|
81 | ${_('Side-by-side Diff')} | |
|
82 | </a> | |
|
83 | | | |
|
84 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='raw')}" | |
|
85 | class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
|
86 | ${_('Raw Diff')} | |
|
87 | </a> | |
|
88 | | | |
|
89 | <a href="${h.url('files_diff_home',repo_name=repo_name,f_path=f_path,diff2=cs2,diff1=cs1,diff='download')}" | |
|
90 | class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |
|
91 | ${_('Download Diff')} | |
|
92 | </a> | |
|
93 | </%def> | |
|
94 | 55 | |
|
95 | 56 | <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)"> |
|
96 | 57 | % if limited_diff: |
|
97 | 58 | ${ungettext('%(num)s file changed', '%(num)s files changed', changed_files) % {'num': changed_files}} |
|
98 | 59 | % else: |
|
99 | 60 | ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', |
|
100 | 61 | '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', changed_files) % {'num': changed_files, 'linesadd': lines_added, 'linesdel': lines_deleted}} |
|
101 | 62 | %endif |
|
102 | 63 | </%def> |
|
103 | 64 |
@@ -1,577 +1,581 b'' | |||
|
1 | 1 | <%def name="diff_line_anchor(filename, line, type)"><% |
|
2 | 2 | return '%s_%s_%i' % (h.safeid(filename), type, line) |
|
3 | 3 | %></%def> |
|
4 | 4 | |
|
5 | 5 | <%def name="action_class(action)"><% |
|
6 | 6 | return { |
|
7 | 7 | '-': 'cb-deletion', |
|
8 | 8 | '+': 'cb-addition', |
|
9 | 9 | ' ': 'cb-context', |
|
10 | 10 | }.get(action, 'cb-empty') |
|
11 | 11 | %></%def> |
|
12 | 12 | |
|
13 | 13 | <%def name="op_class(op_id)"><% |
|
14 | 14 | return { |
|
15 | 15 | DEL_FILENODE: 'deletion', # file deleted |
|
16 | 16 | BIN_FILENODE: 'warning' # binary diff hidden |
|
17 | 17 | }.get(op_id, 'addition') |
|
18 | 18 | %></%def> |
|
19 | 19 | |
|
20 | 20 | <%def name="link_for(**kw)"><% |
|
21 | 21 | new_args = request.GET.mixed() |
|
22 | 22 | new_args.update(kw) |
|
23 | 23 | return h.url('', **new_args) |
|
24 | 24 | %></%def> |
|
25 | 25 | |
|
26 | 26 | <%def name="render_diffset(diffset, commit=None, |
|
27 | 27 | |
|
28 | 28 | # collapse all file diff entries when there are more than this amount of files in the diff |
|
29 | 29 | collapse_when_files_over=20, |
|
30 | 30 | |
|
31 | 31 | # collapse lines in the diff when more than this amount of lines changed in the file diff |
|
32 | 32 | lines_changed_limit=500, |
|
33 | 33 | |
|
34 | 34 | # add a ruler at to the output |
|
35 | 35 | ruler_at_chars=0, |
|
36 | 36 | |
|
37 | 37 | # show inline comments |
|
38 | 38 | use_comments=False, |
|
39 | 39 | |
|
40 | 40 | # disable new comments |
|
41 | 41 | disable_new_comments=False, |
|
42 | 42 | |
|
43 | 43 | )"> |
|
44 | 44 | |
|
45 | 45 | %if use_comments: |
|
46 | 46 | <div id="cb-comments-inline-container-template" class="js-template"> |
|
47 | 47 | ${inline_comments_container([])} |
|
48 | 48 | </div> |
|
49 | 49 | <div class="js-template" id="cb-comment-inline-form-template"> |
|
50 | 50 | <div class="comment-inline-form ac"> |
|
51 | 51 | %if c.rhodecode_user.username != h.DEFAULT_USER: |
|
52 | 52 | ${h.form('#', method='get')} |
|
53 | 53 | <div id="edit-container_{1}" class="clearfix"> |
|
54 | 54 | <div class="comment-title pull-left"> |
|
55 | 55 | ${_('Create a comment on line {1}.')} |
|
56 | 56 | </div> |
|
57 | 57 | <div class="comment-help pull-right"> |
|
58 | 58 | ${(_('Comments parsed using %s syntax with %s support.') % ( |
|
59 | 59 | ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())), |
|
60 | 60 | ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user')) |
|
61 | 61 | ) |
|
62 | 62 | )|n |
|
63 | 63 | } |
|
64 | 64 | </div> |
|
65 | 65 | <div style="clear: both"></div> |
|
66 | 66 | <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea> |
|
67 | 67 | </div> |
|
68 | 68 | <div id="preview-container_{1}" class="clearfix" style="display: none;"> |
|
69 | 69 | <div class="comment-help"> |
|
70 | 70 | ${_('Comment preview')} |
|
71 | 71 | </div> |
|
72 | 72 | <div id="preview-box_{1}" class="preview-box"></div> |
|
73 | 73 | </div> |
|
74 | 74 | <div class="comment-footer"> |
|
75 | 75 | <div class="action-buttons"> |
|
76 | 76 | <input type="hidden" name="f_path" value="{0}"> |
|
77 | 77 | <input type="hidden" name="line" value="{1}"> |
|
78 | 78 | <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button> |
|
79 | 79 | <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button> |
|
80 | 80 | ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')} |
|
81 | 81 | </div> |
|
82 | 82 | <div class="comment-button"> |
|
83 | 83 | <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> |
|
84 | 84 | ${_('Cancel')} |
|
85 | 85 | </button> |
|
86 | 86 | </div> |
|
87 | 87 | ${h.end_form()} |
|
88 | 88 | </div> |
|
89 | 89 | %else: |
|
90 | 90 | ${h.form('', class_='inline-form comment-form-login', method='get')} |
|
91 | 91 | <div class="pull-left"> |
|
92 | 92 | <div class="comment-help pull-right"> |
|
93 | 93 | ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a> |
|
94 | 94 | </div> |
|
95 | 95 | </div> |
|
96 | 96 | <div class="comment-button pull-right"> |
|
97 | 97 | <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);"> |
|
98 | 98 | ${_('Cancel')} |
|
99 | 99 | </button> |
|
100 | 100 | </div> |
|
101 | 101 | <div class="clearfix"></div> |
|
102 | 102 | ${h.end_form()} |
|
103 | 103 | %endif |
|
104 | 104 | </div> |
|
105 | 105 | </div> |
|
106 | 106 | |
|
107 | 107 | %endif |
|
108 | 108 | <% |
|
109 | 109 | collapse_all = len(diffset.files) > collapse_when_files_over |
|
110 | 110 | %> |
|
111 | 111 | |
|
112 | 112 | %if c.diffmode == 'sideside': |
|
113 | 113 | <style> |
|
114 | 114 | .wrapper { |
|
115 | 115 | max-width: 1600px !important; |
|
116 | 116 | } |
|
117 | 117 | </style> |
|
118 | 118 | %endif |
|
119 | 119 | %if ruler_at_chars: |
|
120 | 120 | <style> |
|
121 | 121 | .diff table.cb .cb-content:after { |
|
122 | 122 | content: ""; |
|
123 | 123 | border-left: 1px solid blue; |
|
124 | 124 | position: absolute; |
|
125 | 125 | top: 0; |
|
126 | 126 | height: 18px; |
|
127 | 127 | opacity: .2; |
|
128 | 128 | z-index: 10; |
|
129 | 129 | ## +5 to account for diff action (+/-) |
|
130 | 130 | left: ${ruler_at_chars + 5}ch; |
|
131 | 131 | </style> |
|
132 | 132 | %endif |
|
133 | 133 | <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}"> |
|
134 | 134 | <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}"> |
|
135 | 135 | %if commit: |
|
136 | 136 | <div class="pull-right"> |
|
137 | 137 | <a class="btn tooltip" title="${_('Browse Files at revision {}').format(commit.raw_id)}" href="${h.url('files_home',repo_name=diffset.repo_name, revision=commit.raw_id, f_path='')}"> |
|
138 | 138 | ${_('Browse Files')} |
|
139 | 139 | </a> |
|
140 | 140 | </div> |
|
141 | 141 | %endif |
|
142 | 142 | <h2 class="clearinner"> |
|
143 | 143 | %if commit: |
|
144 | 144 | <a class="tooltip revision" title="${h.tooltip(commit.message)}" href="${h.url('changeset_home',repo_name=c.repo_name,revision=commit.raw_id)}">${'r%s:%s' % (commit.revision,h.short_id(commit.raw_id))}</a> - |
|
145 | 145 | ${h.age_component(commit.date)} - |
|
146 | 146 | %endif |
|
147 | 147 | %if diffset.limited_diff: |
|
148 | 148 | ${_('The requested commit is too big and content was truncated.')} |
|
149 | 149 | |
|
150 | 150 | ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}} |
|
151 | 151 | <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> |
|
152 | 152 | %else: |
|
153 | 153 | ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted', |
|
154 | 154 | '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', diffset.changed_files) % {'num': diffset.changed_files, 'linesadd': diffset.lines_added, 'linesdel': diffset.lines_deleted}} |
|
155 | 155 | %endif |
|
156 | 156 | </h2> |
|
157 | 157 | </div> |
|
158 | 158 | |
|
159 | 159 | %if not diffset.files: |
|
160 | 160 | <p class="empty_data">${_('No files')}</p> |
|
161 | 161 | %endif |
|
162 | 162 | |
|
163 | 163 | <div class="filediffs"> |
|
164 | 164 | %for i, filediff in enumerate(diffset.files): |
|
165 | <% | |
|
166 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] | |
|
167 | over_lines_changed_limit = lines_changed > lines_changed_limit | |
|
168 | %> | |
|
165 | ||
|
166 | <% | |
|
167 | lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted'] | |
|
168 | over_lines_changed_limit = lines_changed > lines_changed_limit | |
|
169 | %> | |
|
169 | 170 | <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox"> |
|
170 | 171 | <div |
|
171 | 172 | class="filediff" |
|
172 | 173 | data-f-path="${filediff['patch']['filename']}" |
|
173 | 174 | id="a_${h.FID('', filediff['patch']['filename'])}"> |
|
174 | 175 | <label for="filediff-collapse-${id(filediff)}" class="filediff-heading"> |
|
175 | 176 | <div class="filediff-collapse-indicator"></div> |
|
176 | 177 | ${diff_ops(filediff)} |
|
177 | 178 | </label> |
|
178 | 179 | ${diff_menu(filediff, use_comments=use_comments)} |
|
179 | 180 | <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}"> |
|
180 | 181 | %if not filediff.hunks: |
|
181 | 182 | %for op_id, op_text in filediff['patch']['stats']['ops'].items(): |
|
182 | 183 | <tr> |
|
183 | 184 | <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}> |
|
184 | 185 | %if op_id == DEL_FILENODE: |
|
185 | 186 | ${_('File was deleted')} |
|
186 | 187 | %elif op_id == BIN_FILENODE: |
|
187 | 188 | ${_('Binary file hidden')} |
|
188 | 189 | %else: |
|
189 | 190 | ${op_text} |
|
190 | 191 | %endif |
|
191 | 192 | </td> |
|
192 | 193 | </tr> |
|
193 | 194 | %endfor |
|
194 | 195 | %endif |
|
195 | 196 | %if over_lines_changed_limit: |
|
196 | 197 | <tr class="cb-warning cb-collapser"> |
|
197 | 198 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}> |
|
198 | 199 | ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)} |
|
199 | 200 | <a href="#" class="cb-expand" |
|
200 | 201 | onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')} |
|
201 | 202 | </a> |
|
202 | 203 | <a href="#" class="cb-collapse" |
|
203 | 204 | onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')} |
|
204 | 205 | </a> |
|
205 | 206 | </td> |
|
206 | 207 | </tr> |
|
207 | 208 | %endif |
|
208 | 209 | %if filediff.patch['is_limited_diff']: |
|
209 | 210 | <tr class="cb-warning cb-collapser"> |
|
210 | 211 | <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}> |
|
211 | 212 | ${_('The requested commit is too big and content was truncated.')} <a href="${link_for(fulldiff=1)}" onclick="return confirm('${_("Showing a big diff might take some time and resources, continue?")}')">${_('Show full diff')}</a> |
|
212 | 213 | </td> |
|
213 | 214 | </tr> |
|
214 | 215 | %endif |
|
215 | 216 | %for hunk in filediff.hunks: |
|
216 | 217 | <tr class="cb-hunk"> |
|
217 | 218 | <td ${c.diffmode == 'unified' and 'colspan=3' or ''}> |
|
218 | 219 | ## TODO: dan: add ajax loading of more context here |
|
219 | 220 | ## <a href="#"> |
|
220 | 221 | <i class="icon-more"></i> |
|
221 | 222 | ## </a> |
|
222 | 223 | </td> |
|
223 | 224 | <td ${c.diffmode == 'sideside' and 'colspan=5' or ''}> |
|
224 | 225 | @@ |
|
225 | 226 | -${hunk.source_start},${hunk.source_length} |
|
226 | 227 | +${hunk.target_start},${hunk.target_length} |
|
227 | 228 | ${hunk.section_header} |
|
228 | 229 | </td> |
|
229 | 230 | </tr> |
|
230 | 231 | %if c.diffmode == 'unified': |
|
231 | 232 | ${render_hunk_lines_unified(hunk, use_comments=use_comments)} |
|
232 | 233 | %elif c.diffmode == 'sideside': |
|
233 | 234 | ${render_hunk_lines_sideside(hunk, use_comments=use_comments)} |
|
234 | 235 | %else: |
|
235 | 236 | <tr class="cb-line"> |
|
236 | 237 | <td>unknown diff mode</td> |
|
237 | 238 | </tr> |
|
238 | 239 | %endif |
|
239 | 240 | %endfor |
|
240 | 241 | </table> |
|
241 | 242 | </div> |
|
242 | 243 | %endfor |
|
243 | 244 | </div> |
|
244 | 245 | </div> |
|
245 | 246 | </%def> |
|
246 | 247 | |
|
247 | 248 | <%def name="diff_ops(filediff)"> |
|
248 | 249 | <% |
|
249 | 250 | stats = filediff['patch']['stats'] |
|
250 | 251 | from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \ |
|
251 | 252 | MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE |
|
252 | 253 | %> |
|
253 | 254 | <span class="pill"> |
|
254 | 255 | %if filediff.source_file_path and filediff.target_file_path: |
|
255 | 256 | %if filediff.source_file_path != filediff.target_file_path: # file was renamed |
|
256 | 257 | <strong>${filediff.target_file_path}</strong> ⬅ <del>${filediff.source_file_path}</del> |
|
257 | 258 | %else: |
|
258 | 259 | ## file was modified |
|
259 | 260 | <strong>${filediff.source_file_path}</strong> |
|
260 | 261 | %endif |
|
261 | 262 | %else: |
|
262 | 263 | %if filediff.source_file_path: |
|
263 | 264 | ## file was deleted |
|
264 | 265 | <strong>${filediff.source_file_path}</strong> |
|
265 | 266 | %else: |
|
266 | 267 | ## file was added |
|
267 | 268 | <strong>${filediff.target_file_path}</strong> |
|
268 | 269 | %endif |
|
269 | 270 | %endif |
|
270 | 271 | </span> |
|
271 | 272 | <span class="pill-group" style="float: left"> |
|
272 | 273 | %if filediff.patch['is_limited_diff']: |
|
273 | 274 | <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span> |
|
274 | 275 | %endif |
|
275 | 276 | %if RENAMED_FILENODE in stats['ops']: |
|
276 | 277 | <span class="pill" op="renamed">renamed</span> |
|
277 | 278 | %endif |
|
278 | 279 | |
|
279 | 280 | %if NEW_FILENODE in stats['ops']: |
|
280 | 281 | <span class="pill" op="created">created</span> |
|
281 | 282 | %if filediff['target_mode'].startswith('120'): |
|
282 | 283 | <span class="pill" op="symlink">symlink</span> |
|
283 | 284 | %else: |
|
284 | 285 | <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span> |
|
285 | 286 | %endif |
|
286 | 287 | %endif |
|
287 | 288 | |
|
288 | 289 | %if DEL_FILENODE in stats['ops']: |
|
289 | 290 | <span class="pill" op="removed">removed</span> |
|
290 | 291 | %endif |
|
291 | 292 | |
|
292 | 293 | %if CHMOD_FILENODE in stats['ops']: |
|
293 | 294 | <span class="pill" op="mode"> |
|
294 | 295 | ${nice_mode(filediff['source_mode'])} ➡ ${nice_mode(filediff['target_mode'])} |
|
295 | 296 | </span> |
|
296 | 297 | %endif |
|
297 | 298 | </span> |
|
298 | 299 | |
|
299 | 300 | <a class="pill filediff-anchor" href="#a_${h.FID('', filediff.patch['filename'])}">¶</a> |
|
300 | 301 | |
|
301 | 302 | <span class="pill-group" style="float: right"> |
|
302 | 303 | %if BIN_FILENODE in stats['ops']: |
|
303 | 304 | <span class="pill" op="binary">binary</span> |
|
304 | 305 | %if MOD_FILENODE in stats['ops']: |
|
305 | 306 | <span class="pill" op="modified">modified</span> |
|
306 | 307 | %endif |
|
307 | 308 | %endif |
|
308 | 309 | %if stats['added']: |
|
309 | 310 | <span class="pill" op="added">+${stats['added']}</span> |
|
310 | 311 | %endif |
|
311 | 312 | %if stats['deleted']: |
|
312 | 313 | <span class="pill" op="deleted">-${stats['deleted']}</span> |
|
313 | 314 | %endif |
|
314 | 315 | </span> |
|
315 | 316 | |
|
316 | 317 | </%def> |
|
317 | 318 | |
|
318 | 319 | <%def name="nice_mode(filemode)"> |
|
319 | 320 | ${filemode.startswith('100') and filemode[3:] or filemode} |
|
320 | 321 | </%def> |
|
321 | 322 | |
|
322 | 323 | <%def name="diff_menu(filediff, use_comments=False)"> |
|
323 | 324 | <div class="filediff-menu"> |
|
324 | 325 | %if filediff.diffset.source_ref: |
|
325 | 326 | %if filediff.patch['operation'] in ['D', 'M']: |
|
326 | 327 | <a |
|
327 | 328 | class="tooltip" |
|
328 | 329 | href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}" |
|
329 | 330 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" |
|
330 | 331 | > |
|
331 | 332 | ${_('Show file before')} |
|
332 | 333 | </a> |
|
333 | 334 | %else: |
|
334 | 335 | <span |
|
335 | 336 | class="tooltip" |
|
336 | 337 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}" |
|
337 | 338 | > |
|
338 | 339 | ${_('Show file before')} |
|
339 | 340 | </span> |
|
340 | 341 | %endif |
|
341 | 342 | %if filediff.patch['operation'] in ['A', 'M']: |
|
342 | 343 | <a |
|
343 | 344 | class="tooltip" |
|
344 | 345 | href="${h.url('files_home',repo_name=filediff.diffset.source_repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}" |
|
345 | 346 | title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" |
|
346 | 347 | > |
|
347 | 348 | ${_('Show file after')} |
|
348 | 349 | </a> |
|
349 | 350 | %else: |
|
350 | 351 | <span |
|
351 | 352 | class="tooltip" |
|
352 | 353 | title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}" |
|
353 | 354 | > |
|
354 | 355 | ${_('Show file after')} |
|
355 | 356 | </span> |
|
356 | 357 | %endif |
|
357 | 358 | <a |
|
358 | 359 | class="tooltip" |
|
359 | 360 | title="${h.tooltip(_('Raw diff'))}" |
|
360 | 361 | href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='raw')}" |
|
361 | 362 | > |
|
362 | 363 | ${_('Raw diff')} |
|
363 | 364 | </a> |
|
364 | 365 | <a |
|
365 | 366 | class="tooltip" |
|
366 | 367 | title="${h.tooltip(_('Download diff'))}" |
|
367 | 368 | href="${h.url('files_diff_home',repo_name=filediff.diffset.repo_name,f_path=filediff.target_file_path,diff2=filediff.diffset.target_ref,diff1=filediff.diffset.source_ref,diff='download')}" |
|
368 | 369 | > |
|
369 | 370 | ${_('Download diff')} |
|
370 | 371 | </a> |
|
371 | 372 | |
|
372 | 373 | ## TODO: dan: refactor ignorews_url and context_url into the diff renderer same as diffmode=unified/sideside. Also use ajax to load more context (by clicking hunks) |
|
373 | 374 | %if hasattr(c, 'ignorews_url'): |
|
374 | 375 | ${c.ignorews_url(request.GET, h.FID('', filediff['patch']['filename']))} |
|
375 | 376 | %endif |
|
376 | 377 | %if hasattr(c, 'context_url'): |
|
377 | 378 | ${c.context_url(request.GET, h.FID('', filediff['patch']['filename']))} |
|
378 | 379 | %endif |
|
379 | 380 | |
|
380 | 381 | |
|
381 | 382 | %if use_comments: |
|
382 | 383 | <a href="#" onclick="return Rhodecode.comments.toggleComments(this);"> |
|
383 | 384 | <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span> |
|
384 | 385 | </a> |
|
385 | 386 | %endif |
|
386 | 387 | %endif |
|
387 | 388 | </div> |
|
388 | 389 | </%def> |
|
389 | 390 | |
|
390 | 391 | |
|
391 | 392 | <%namespace name="commentblock" file="/changeset/changeset_file_comment.html"/> |
|
392 | 393 | <%def name="inline_comments_container(comments)"> |
|
393 | 394 | <div class="inline-comments"> |
|
394 | 395 | %for comment in comments: |
|
395 | 396 | ${commentblock.comment_block(comment, inline=True)} |
|
396 | 397 | %endfor |
|
397 | 398 | |
|
398 | 399 | <span onclick="return Rhodecode.comments.createComment(this)" |
|
399 | 400 | class="btn btn-secondary cb-comment-add-button ${'comment-outdated' if comments and comments[-1].outdated else ''}" |
|
400 | 401 | style="${'display: none;' if comments and comments[-1].outdated else ''}"> |
|
401 | 402 | ${_('Add another comment')} |
|
402 | 403 | </span> |
|
403 | 404 | |
|
404 | 405 | </div> |
|
405 | 406 | </%def> |
|
406 | 407 | |
|
407 | 408 | |
|
408 | 409 | <%def name="render_hunk_lines_sideside(hunk, use_comments=False)"> |
|
409 | 410 | %for i, line in enumerate(hunk.sideside): |
|
410 | 411 | <% |
|
411 | 412 | old_line_anchor, new_line_anchor = None, None |
|
412 | 413 | if line.original.lineno: |
|
413 | 414 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o') |
|
414 | 415 | if line.modified.lineno: |
|
415 | 416 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n') |
|
416 | 417 | %> |
|
418 | ||
|
417 | 419 | <tr class="cb-line"> |
|
418 | 420 | <td class="cb-data ${action_class(line.original.action)}" |
|
419 | 421 | data-line-number="${line.original.lineno}" |
|
420 | 422 | > |
|
421 | 423 | <div> |
|
422 | 424 | %if line.original.comments: |
|
423 | 425 | <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> |
|
424 | 426 | %endif |
|
425 | 427 | </div> |
|
426 | 428 | </td> |
|
427 | 429 | <td class="cb-lineno ${action_class(line.original.action)}" |
|
428 | 430 | data-line-number="${line.original.lineno}" |
|
429 | 431 | %if old_line_anchor: |
|
430 | 432 | id="${old_line_anchor}" |
|
431 | 433 | %endif |
|
432 | 434 | > |
|
433 | 435 | %if line.original.lineno: |
|
434 | 436 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a> |
|
435 | 437 | %endif |
|
436 | 438 | </td> |
|
437 | 439 | <td class="cb-content ${action_class(line.original.action)}" |
|
438 | 440 | data-line-number="o${line.original.lineno}" |
|
439 | 441 | > |
|
440 | 442 | %if use_comments and line.original.lineno: |
|
441 | 443 | ${render_add_comment_button()} |
|
442 | 444 | %endif |
|
443 | 445 | <span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span> |
|
444 | 446 | %if use_comments and line.original.lineno and line.original.comments: |
|
445 | 447 | ${inline_comments_container(line.original.comments)} |
|
446 | 448 | %endif |
|
447 | 449 | </td> |
|
448 | 450 | <td class="cb-data ${action_class(line.modified.action)}" |
|
449 | 451 | data-line-number="${line.modified.lineno}" |
|
450 | 452 | > |
|
451 | 453 | <div> |
|
452 | 454 | %if line.modified.comments: |
|
453 | 455 | <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> |
|
454 | 456 | %endif |
|
455 | 457 | </div> |
|
456 | 458 | </td> |
|
457 | 459 | <td class="cb-lineno ${action_class(line.modified.action)}" |
|
458 | 460 | data-line-number="${line.modified.lineno}" |
|
459 | 461 | %if new_line_anchor: |
|
460 | 462 | id="${new_line_anchor}" |
|
461 | 463 | %endif |
|
462 | 464 | > |
|
463 | 465 | %if line.modified.lineno: |
|
464 | 466 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a> |
|
465 | 467 | %endif |
|
466 | 468 | </td> |
|
467 | 469 | <td class="cb-content ${action_class(line.modified.action)}" |
|
468 | 470 | data-line-number="n${line.modified.lineno}" |
|
469 | 471 | > |
|
470 | 472 | %if use_comments and line.modified.lineno: |
|
471 | 473 | ${render_add_comment_button()} |
|
472 | 474 | %endif |
|
473 | 475 | <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span> |
|
474 | 476 | %if use_comments and line.modified.lineno and line.modified.comments: |
|
475 | 477 | ${inline_comments_container(line.modified.comments)} |
|
476 | 478 | %endif |
|
477 | 479 | </td> |
|
478 | 480 | </tr> |
|
479 | 481 | %endfor |
|
480 | 482 | </%def> |
|
481 | 483 | |
|
482 | 484 | |
|
483 | 485 | <%def name="render_hunk_lines_unified(hunk, use_comments=False)"> |
|
484 | 486 | %for old_line_no, new_line_no, action, content, comments in hunk.unified: |
|
485 | 487 | <% |
|
486 | 488 | old_line_anchor, new_line_anchor = None, None |
|
487 | 489 | if old_line_no: |
|
488 | 490 | old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o') |
|
489 | 491 | if new_line_no: |
|
490 | 492 | new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n') |
|
491 | 493 | %> |
|
492 | 494 | <tr class="cb-line"> |
|
493 | 495 | <td class="cb-data ${action_class(action)}"> |
|
494 | 496 | <div> |
|
495 | 497 | %if comments: |
|
496 | 498 | <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i> |
|
497 | 499 | %endif |
|
498 | 500 | </div> |
|
499 | 501 | </td> |
|
500 | 502 | <td class="cb-lineno ${action_class(action)}" |
|
501 | 503 | data-line-number="${old_line_no}" |
|
502 | 504 | %if old_line_anchor: |
|
503 | 505 | id="${old_line_anchor}" |
|
504 | 506 | %endif |
|
505 | 507 | > |
|
506 | 508 | %if old_line_anchor: |
|
507 | 509 | <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a> |
|
508 | 510 | %endif |
|
509 | 511 | </td> |
|
510 | 512 | <td class="cb-lineno ${action_class(action)}" |
|
511 | 513 | data-line-number="${new_line_no}" |
|
512 | 514 | %if new_line_anchor: |
|
513 | 515 | id="${new_line_anchor}" |
|
514 | 516 | %endif |
|
515 | 517 | > |
|
516 | 518 | %if new_line_anchor: |
|
517 | 519 | <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a> |
|
518 | 520 | %endif |
|
519 | 521 | </td> |
|
520 | 522 | <td class="cb-content ${action_class(action)}" |
|
521 | 523 | data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}" |
|
522 | 524 | > |
|
523 | 525 | %if use_comments: |
|
524 | 526 | ${render_add_comment_button()} |
|
525 | 527 | %endif |
|
526 | 528 | <span class="cb-code">${action} ${content or '' | n}</span> |
|
527 | 529 | %if use_comments and comments: |
|
528 | 530 | ${inline_comments_container(comments)} |
|
529 | 531 | %endif |
|
530 | 532 | </td> |
|
531 | 533 | </tr> |
|
532 | 534 | %endfor |
|
533 | 535 | </%def> |
|
534 | 536 | |
|
535 | 537 | <%def name="render_add_comment_button()"> |
|
536 | 538 | <button |
|
537 | 539 | class="btn btn-small btn-primary cb-comment-box-opener" |
|
538 | 540 | onclick="return Rhodecode.comments.createComment(this)" |
|
539 | 541 | ><span>+</span></button> |
|
540 | 542 | </%def> |
|
541 | 543 | |
|
542 | 544 | <%def name="render_diffset_menu()"> |
|
543 | 545 | |
|
544 | 546 | <div class="diffset-menu clearinner"> |
|
545 | 547 | <div class="pull-right"> |
|
546 | 548 | <div class="btn-group"> |
|
549 | ||
|
547 | 550 | <a |
|
548 | 551 | class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip" |
|
549 | 552 | title="${_('View side by side')}" |
|
550 | 553 | href="${h.url_replace(diffmode='sideside')}"> |
|
551 | 554 | <span>${_('Side by Side')}</span> |
|
552 | 555 | </a> |
|
553 | 556 | <a |
|
554 | 557 | class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip" |
|
555 | 558 | title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}"> |
|
556 | 559 | <span>${_('Unified')}</span> |
|
557 | 560 | </a> |
|
558 | 561 | </div> |
|
559 | 562 | </div> |
|
563 | ||
|
560 | 564 | <div class="pull-left"> |
|
561 | 565 | <div class="btn-group"> |
|
562 | 566 | <a |
|
563 | 567 | class="btn" |
|
564 | 568 | href="#" |
|
565 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All')}</a> | |
|
569 | onclick="$('input[class=filediff-collapse-state]').prop('checked', false); return false">${_('Expand All Files')}</a> | |
|
566 | 570 | <a |
|
567 | 571 | class="btn" |
|
568 | 572 | href="#" |
|
569 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All')}</a> | |
|
573 | onclick="$('input[class=filediff-collapse-state]').prop('checked', true); return false">${_('Collapse All Files')}</a> | |
|
570 | 574 | <a |
|
571 | 575 | class="btn" |
|
572 | 576 | href="#" |
|
573 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode')}</a> | |
|
577 | onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode Diff')}</a> | |
|
574 | 578 | </div> |
|
575 | 579 | </div> |
|
576 | 580 | </div> |
|
577 | 581 | </%def> |
@@ -1,104 +1,113 b'' | |||
|
1 | 1 | ## Changesets table ! |
|
2 | 2 | <%namespace name="base" file="/base/base.html"/> |
|
3 | <div class="container"> | |
|
4 | %if not c.commit_ranges: | |
|
5 | <p class="empty_data">${_('No Commits')}</p> | |
|
6 | %else: | |
|
7 | 3 | |
|
8 |
|
|
|
9 |
|
|
|
10 |
|
|
|
11 |
|
|
|
12 |
|
|
|
13 |
|
|
|
14 |
|
|
|
15 | </p> | |
|
16 |
|
|
|
4 | %if c.ancestor: | |
|
5 | <div class="ancestor">${_('Common Ancestor Commit')}: | |
|
6 | <a href="${h.url('changeset_home', | |
|
7 | repo_name=c.repo_name, | |
|
8 | revision=c.ancestor)}"> | |
|
9 | ${h.short_id(c.ancestor)} | |
|
10 | </a> | |
|
11 | </div> | |
|
12 | %endif | |
|
17 | 13 | |
|
14 | <div class="container"> | |
|
18 | 15 | <input type="hidden" name="__start__" value="revisions:sequence"> |
|
19 | 16 | <table class="rctable compare_view_commits"> |
|
20 | 17 | <tr> |
|
21 | 18 | <th>${_('Time')}</th> |
|
22 | 19 | <th>${_('Author')}</th> |
|
23 | 20 | <th>${_('Commit')}</th> |
|
24 | 21 | <th></th> |
|
25 | 22 | <th>${_('Description')}</th> |
|
26 | 23 | </tr> |
|
27 | 24 | %for commit in c.commit_ranges: |
|
28 | 25 | <tr id="row-${commit.raw_id}" |
|
29 | 26 | commit_id="${commit.raw_id}" |
|
30 | 27 | class="compare_select" |
|
31 | 28 | > |
|
32 | 29 | <td class="td-time"> |
|
33 | 30 | ${h.age_component(commit.date)} |
|
34 | 31 | </td> |
|
35 | 32 | <td class="td-user"> |
|
36 | 33 | ${base.gravatar_with_user(commit.author, 16)} |
|
37 | 34 | </td> |
|
38 | 35 | <td class="td-hash"> |
|
39 | 36 | <code> |
|
40 | 37 | <a href="${h.url('changeset_home', |
|
41 | 38 | repo_name=c.target_repo.repo_name, |
|
42 | 39 | revision=commit.raw_id)}"> |
|
43 | 40 | r${commit.revision}:${h.short_id(commit.raw_id)} |
|
44 | 41 | </a> |
|
45 | 42 | ${h.hidden('revisions',commit.raw_id)} |
|
46 | 43 | </code> |
|
47 | 44 | </td> |
|
48 | 45 | <td class="expand_commit" |
|
49 | 46 | data-commit-id="${commit.raw_id}" |
|
50 | 47 | title="${_( 'Expand commit message')}" |
|
51 | 48 | > |
|
52 | 49 | <div class="show_more_col"> |
|
53 | 50 | <i class="show_more"></i> |
|
54 | 51 | </div> |
|
55 | 52 | </td> |
|
56 | 53 | <td class="mid td-description"> |
|
57 | 54 | <div class="log-container truncate-wrap"> |
|
58 | 55 | <div |
|
59 | 56 | id="c-${commit.raw_id}" |
|
60 | 57 | class="message truncate" |
|
61 | 58 | data-message-raw="${commit.message}" |
|
62 | 59 | > |
|
63 | 60 | ${h.urlify_commit_message(commit.message, c.repo_name)} |
|
64 | 61 | </div> |
|
65 | 62 | </div> |
|
66 | 63 | </td> |
|
67 | 64 | </tr> |
|
68 | 65 | %endfor |
|
66 | <tr class="compare_select_hidden" style="display: none"> | |
|
67 | <td colspan="5"> | |
|
68 | ${ungettext('%s commit hidden','%s commits hidden', len(c.commit_ranges)) % len(c.commit_ranges)} | |
|
69 | </td> | |
|
70 | </tr> | |
|
71 | % if not c.commit_ranges: | |
|
72 | <tr class="compare_select"> | |
|
73 | <td colspan="5"> | |
|
74 | ${_('No commits in this compare')} | |
|
75 | </td> | |
|
76 | </tr> | |
|
77 | % endif | |
|
69 | 78 | </table> |
|
70 | 79 | <input type="hidden" name="__end__" value="revisions:sequence"> |
|
71 | %endif | |
|
80 | ||
|
72 | 81 | </div> |
|
73 | 82 | |
|
74 | 83 | <script> |
|
75 | 84 | $('.expand_commit').on('click',function(e){ |
|
76 | 85 | var target_expand = $(this); |
|
77 | 86 | var cid = target_expand.data('commitId'); |
|
78 | 87 | |
|
79 | ## TODO: dan: extract styles into css, and just toggleClass('open') here | |
|
88 | // ## TODO: dan: extract styles into css, and just toggleClass('open') here | |
|
80 | 89 | if (target_expand.hasClass('open')){ |
|
81 | 90 | $('#c-'+cid).css({ |
|
82 | 91 | 'height': '1.5em', |
|
83 | 92 | 'white-space': 'nowrap', |
|
84 | 93 | 'text-overflow': 'ellipsis', |
|
85 | 94 | 'overflow':'hidden' |
|
86 | 95 | }); |
|
87 | 96 | target_expand.removeClass('open'); |
|
88 | 97 | } |
|
89 | 98 | else { |
|
90 | 99 | $('#c-'+cid).css({ |
|
91 | 100 | 'height': 'auto', |
|
92 | 101 | 'white-space': 'pre-line', |
|
93 | 102 | 'text-overflow': 'initial', |
|
94 | 103 | 'overflow':'visible' |
|
95 | 104 | }); |
|
96 | 105 | target_expand.addClass('open'); |
|
97 | 106 | } |
|
98 | 107 | }); |
|
99 | 108 | |
|
100 | 109 | $('.compare_select').on('click',function(e){ |
|
101 | 110 | var cid = $(this).attr('commit_id'); |
|
102 | 111 | $('#row-'+cid).toggleClass('hl', !$('#row-'+cid).hasClass('hl')); |
|
103 | 112 | }); |
|
104 | 113 | </script> |
@@ -1,259 +1,370 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | 2 | <%inherit file="/base/base.html"/> |
|
3 | 3 | <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/> |
|
4 | 4 | |
|
5 | 5 | <%def name="title()"> |
|
6 | 6 | %if c.compare_home: |
|
7 | 7 | ${_('%s Compare') % c.repo_name} |
|
8 | 8 | %else: |
|
9 | 9 | ${_('%s Compare') % c.repo_name} - ${'%s@%s' % (c.source_repo.repo_name, c.source_ref)} > ${'%s@%s' % (c.target_repo.repo_name, c.target_ref)} |
|
10 | 10 | %endif |
|
11 | 11 | %if c.rhodecode_name: |
|
12 | 12 | · ${h.branding(c.rhodecode_name)} |
|
13 | 13 | %endif |
|
14 | 14 | </%def> |
|
15 | 15 | |
|
16 | 16 | <%def name="breadcrumbs_links()"> |
|
17 | 17 | ${ungettext('%s commit','%s commits', len(c.commit_ranges)) % len(c.commit_ranges)} |
|
18 | 18 | </%def> |
|
19 | 19 | |
|
20 | 20 | <%def name="menu_bar_nav()"> |
|
21 | 21 | ${self.menu_items(active='repositories')} |
|
22 | 22 | </%def> |
|
23 | 23 | |
|
24 | 24 | <%def name="menu_bar_subnav()"> |
|
25 | 25 | ${self.repo_menu(active='compare')} |
|
26 | 26 | </%def> |
|
27 | 27 | |
|
28 | 28 | <%def name="main()"> |
|
29 | 29 | <script type="text/javascript"> |
|
30 | 30 | // set fake commitId on this commit-range page |
|
31 | 31 | templateContext.commit_data.commit_id = "${h.EmptyCommit().raw_id}"; |
|
32 | 32 | </script> |
|
33 | 33 | |
|
34 | 34 | <div class="box"> |
|
35 | 35 | <div class="title"> |
|
36 | 36 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
37 | <div class="breadcrumbs"> | |
|
38 | ${_('Compare Commits')} | |
|
39 | </div> | |
|
40 | 37 | </div> |
|
41 | 38 | |
|
39 | <div class="summary changeset"> | |
|
40 | <div class="summary-detail"> | |
|
41 | <div class="summary-detail-header"> | |
|
42 | <span class="breadcrumbs files_location"> | |
|
43 | <h4> | |
|
44 | ${_('Compare Commits')} | |
|
45 | % if c.file_path: | |
|
46 | ${_('for file')} <a href="#${'a_' + h.FID('',c.file_path)}">${c.file_path}</a> | |
|
47 | % endif | |
|
48 | ||
|
49 | % if c.commit_ranges: | |
|
50 | <code> | |
|
51 | r${c.source_commit.revision}:${h.short_id(c.source_commit.raw_id)}...r${c.target_commit.revision}:${h.short_id(c.target_commit.raw_id)} | |
|
52 | </code> | |
|
53 | % endif | |
|
54 | </h4> | |
|
55 | </span> | |
|
56 | </div> | |
|
57 | ||
|
58 | <div class="fieldset"> | |
|
59 | <div class="left-label"> | |
|
60 | ${_('Target')}: | |
|
61 | </div> | |
|
62 | <div class="right-content"> | |
|
63 | <div> | |
|
64 | <div class="code-header" > | |
|
65 | <div class="compare_header"> | |
|
66 | ## The hidden elements are replaced with a select2 widget | |
|
67 | ${h.hidden('compare_source')} | |
|
68 | </div> | |
|
69 | </div> | |
|
70 | </div> | |
|
71 | </div> | |
|
72 | </div> | |
|
73 | ||
|
74 | <div class="fieldset"> | |
|
75 | <div class="left-label"> | |
|
76 | ${_('Source')}: | |
|
77 | </div> | |
|
78 | <div class="right-content"> | |
|
79 | <div> | |
|
80 | <div class="code-header" > | |
|
81 | <div class="compare_header"> | |
|
82 | ## The hidden elements are replaced with a select2 widget | |
|
83 | ${h.hidden('compare_target')} | |
|
84 | </div> | |
|
85 | </div> | |
|
86 | </div> | |
|
87 | </div> | |
|
88 | </div> | |
|
89 | ||
|
90 | <div class="fieldset"> | |
|
91 | <div class="left-label"> | |
|
92 | ${_('Actions')}: | |
|
93 | </div> | |
|
94 | <div class="right-content"> | |
|
95 | <div> | |
|
96 | <div class="code-header" > | |
|
97 | <div class="compare_header"> | |
|
98 | ||
|
99 | <div class="compare-buttons"> | |
|
100 | % if c.compare_home: | |
|
101 | <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a> | |
|
102 | ||
|
103 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a> | |
|
104 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |
|
105 | <div id="changeset_compare_view_content"> | |
|
106 | <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div> | |
|
107 | </div> | |
|
108 | ||
|
109 | % elif c.preview_mode: | |
|
110 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Compare Commits')}</a> | |
|
111 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Swap')}</a> | |
|
112 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |
|
113 | ||
|
114 | % else: | |
|
115 | <a id="compare_revs" class="btn btn-primary"> ${_('Compare Commits')}</a> | |
|
116 | <a id="btn-swap" class="btn btn-primary" href="${c.swap_url}">${_('Swap')}</a> | |
|
117 | ||
|
118 | ## allow comment only if there are commits to comment on | |
|
119 | % if c.diffset and c.diffset.files and c.commit_ranges: | |
|
120 | <a id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</a> | |
|
121 | % else: | |
|
122 | <a class="btn disabled tooltip" disabled="disabled" title="${_('Action unavailable in current view')}">${_('Comment')}</a> | |
|
123 | % endif | |
|
124 | % endif | |
|
125 | </div> | |
|
126 | </div> | |
|
127 | </div> | |
|
128 | </div> | |
|
129 | </div> | |
|
130 | </div> | |
|
131 | ||
|
132 | <%doc> | |
|
133 | ##TODO(marcink): implement this and diff menus | |
|
134 | <div class="fieldset"> | |
|
135 | <div class="left-label"> | |
|
136 | ${_('Diff options')}: | |
|
137 | </div> | |
|
138 | <div class="right-content"> | |
|
139 | <div class="diff-actions"> | |
|
140 | <a href="${h.url('changeset_raw_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Raw diff'))}"> | |
|
141 | ${_('Raw Diff')} | |
|
142 | </a> | |
|
143 | | | |
|
144 | <a href="${h.url('changeset_patch_home',repo_name=c.repo_name,revision='?')}" class="tooltip" title="${h.tooltip(_('Patch diff'))}"> | |
|
145 | ${_('Patch Diff')} | |
|
146 | </a> | |
|
147 | | | |
|
148 | <a href="${h.url('changeset_download_home',repo_name=c.repo_name,revision='?',diff='download')}" class="tooltip" title="${h.tooltip(_('Download diff'))}"> | |
|
149 | ${_('Download Diff')} | |
|
150 | </a> | |
|
151 | </div> | |
|
152 | </div> | |
|
153 | </div> | |
|
154 | </%doc> | |
|
155 | ||
|
156 | </div> <!-- end summary-detail --> | |
|
157 | ||
|
158 | </div> <!-- end summary --> | |
|
159 | ||
|
160 | ||
|
42 | 161 | <div class="table"> |
|
43 | <div id="codeblock" class="diffblock"> | |
|
44 | <div class="code-header" > | |
|
45 | <div class="compare_header"> | |
|
46 | ## The hidden elements are replaced with a select2 widget | |
|
47 | <div class="compare-label">${_('Target')}</div>${h.hidden('compare_source')} | |
|
48 | <div class="compare-label">${_('Source')}</div>${h.hidden('compare_target')} | |
|
49 | 162 | |
|
50 | %if not c.preview_mode: | |
|
51 | <div class="compare-label"></div> | |
|
52 | <div class="compare-buttons"> | |
|
53 | %if not c.compare_home: | |
|
54 | <a id="btn-swap" class="btn btn-primary" href="${c.swap_url}"><i class="icon-refresh"></i> ${_('Swap')}</a> | |
|
55 | %endif | |
|
56 | <div id="compare_revs" class="btn btn-primary"><i class ="icon-loop"></i> ${_('Compare Commits')}</div> | |
|
57 | %if c.diffset and c.diffset.files: | |
|
58 | <div id="compare_changeset_status_toggle" class="btn btn-primary">${_('Comment')}</div> | |
|
59 | %endif | |
|
60 | </div> | |
|
61 | %endif | |
|
62 | </div> | |
|
63 | </div> | |
|
64 | </div> | |
|
65 | 163 | ## use JS script to load it quickly before potentially large diffs render long time |
|
66 | 164 | ## this prevents from situation when large diffs block rendering of select2 fields |
|
67 | 165 | <script type="text/javascript"> |
|
68 | 166 | |
|
69 | 167 | var cache = {}; |
|
70 | 168 | |
|
71 | 169 | var formatSelection = function(repoName){ |
|
72 | 170 | return function(data, container, escapeMarkup) { |
|
73 | 171 | var selection = data ? this.text(data) : ""; |
|
74 | 172 | return escapeMarkup('{0}@{1}'.format(repoName, selection)); |
|
75 | 173 | } |
|
76 | 174 | }; |
|
77 | 175 | |
|
78 | 176 | var feedCompareData = function(query, cachedValue){ |
|
79 | 177 | var data = {results: []}; |
|
80 | 178 | //filter results |
|
81 | 179 | $.each(cachedValue.results, function() { |
|
82 | 180 | var section = this.text; |
|
83 | 181 | var children = []; |
|
84 | 182 | $.each(this.children, function() { |
|
85 | 183 | if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) { |
|
86 | 184 | children.push({ |
|
87 | 185 | 'id': this.id, |
|
88 | 186 | 'text': this.text, |
|
89 | 187 | 'type': this.type |
|
90 | 188 | }) |
|
91 | 189 | } |
|
92 | 190 | }); |
|
93 | 191 | data.results.push({ |
|
94 | 192 | 'text': section, |
|
95 | 193 | 'children': children |
|
96 | 194 | }) |
|
97 | 195 | }); |
|
98 | 196 | //push the typed in changeset |
|
99 | 197 | data.results.push({ |
|
100 | 198 | 'text': _gettext('specify commit'), |
|
101 | 199 | 'children': [{ |
|
102 | 200 | 'id': query.term, |
|
103 | 201 | 'text': query.term, |
|
104 | 202 | 'type': 'rev' |
|
105 | 203 | }] |
|
106 | 204 | }); |
|
107 | 205 | query.callback(data); |
|
108 | 206 | }; |
|
109 | 207 | |
|
110 | 208 | var loadCompareData = function(repoName, query, cache){ |
|
111 | 209 | $.ajax({ |
|
112 | 210 | url: pyroutes.url('repo_refs_data', {'repo_name': repoName}), |
|
113 | 211 | data: {}, |
|
114 | 212 | dataType: 'json', |
|
115 | 213 | type: 'GET', |
|
116 | 214 | success: function(data) { |
|
117 | 215 | cache[repoName] = data; |
|
118 | 216 | query.callback({results: data.results}); |
|
119 | 217 | } |
|
120 | 218 | }) |
|
121 | 219 | }; |
|
122 | 220 | |
|
123 | 221 | var enable_fields = ${"false" if c.preview_mode else "true"}; |
|
124 | 222 | $("#compare_source").select2({ |
|
125 | 223 | placeholder: "${'%s@%s' % (c.source_repo.repo_name, c.source_ref)}", |
|
126 | 224 | containerCssClass: "drop-menu", |
|
127 | 225 | dropdownCssClass: "drop-menu-dropdown", |
|
128 | 226 | formatSelection: formatSelection("${c.source_repo.repo_name}"), |
|
129 | 227 | dropdownAutoWidth: true, |
|
130 | 228 | query: function(query) { |
|
131 | 229 | var repoName = '${c.source_repo.repo_name}'; |
|
132 | 230 | var cachedValue = cache[repoName]; |
|
133 | 231 | |
|
134 | 232 | if (cachedValue){ |
|
135 | 233 | feedCompareData(query, cachedValue); |
|
136 | 234 | } |
|
137 | 235 | else { |
|
138 | 236 | loadCompareData(repoName, query, cache); |
|
139 | 237 | } |
|
140 | 238 | } |
|
141 | 239 | }).select2("enable", enable_fields); |
|
142 | 240 | |
|
143 | 241 | $("#compare_target").select2({ |
|
144 | 242 | placeholder: "${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}", |
|
145 | 243 | dropdownAutoWidth: true, |
|
146 | 244 | containerCssClass: "drop-menu", |
|
147 | 245 | dropdownCssClass: "drop-menu-dropdown", |
|
148 | 246 | formatSelection: formatSelection("${c.target_repo.repo_name}"), |
|
149 | 247 | query: function(query) { |
|
150 | 248 | var repoName = '${c.target_repo.repo_name}'; |
|
151 | 249 | var cachedValue = cache[repoName]; |
|
152 | 250 | |
|
153 | 251 | if (cachedValue){ |
|
154 | 252 | feedCompareData(query, cachedValue); |
|
155 | 253 | } |
|
156 | 254 | else { |
|
157 | 255 | loadCompareData(repoName, query, cache); |
|
158 | 256 | } |
|
159 | 257 | } |
|
160 | 258 | }).select2("enable", enable_fields); |
|
161 | 259 | var initial_compare_source = {id: "${c.source_ref}", type:"${c.source_ref_type}"}; |
|
162 | 260 | var initial_compare_target = {id: "${c.target_ref}", type:"${c.target_ref_type}"}; |
|
163 | 261 | |
|
164 | 262 | $('#compare_revs').on('click', function(e) { |
|
165 | 263 | var source = $('#compare_source').select2('data') || initial_compare_source; |
|
166 | 264 | var target = $('#compare_target').select2('data') || initial_compare_target; |
|
167 | 265 | if (source && target) { |
|
168 | 266 | var url_data = { |
|
169 | 267 | repo_name: "${c.repo_name}", |
|
170 | 268 | source_ref: source.id, |
|
171 | 269 | source_ref_type: source.type, |
|
172 | 270 | target_ref: target.id, |
|
173 | 271 | target_ref_type: target.type |
|
174 | 272 | }; |
|
175 | 273 | window.location = pyroutes.url('compare_url', url_data); |
|
176 | 274 | } |
|
177 | 275 | }); |
|
178 | 276 | $('#compare_changeset_status_toggle').on('click', function(e) { |
|
179 | 277 | $('#compare_changeset_status').toggle(); |
|
180 | 278 | }); |
|
181 | 279 | |
|
182 | 280 | </script> |
|
183 | 281 | |
|
184 | 282 | ## changeset status form |
|
185 | 283 | <%namespace name="comment" file="/changeset/changeset_file_comment.html"/> |
|
186 | 284 | ## main comment form and it status |
|
187 | 285 | <% |
|
188 | 286 | def revs(_revs): |
|
189 | 287 | form_inputs = [] |
|
190 | 288 | for cs in _revs: |
|
191 | 289 | tmpl = '<input type="hidden" data-commit-id="%(cid)s" name="commit_ids" value="%(cid)s">' % {'cid': cs.raw_id} |
|
192 | 290 | form_inputs.append(tmpl) |
|
193 | 291 | return form_inputs |
|
194 | 292 | %> |
|
195 | 293 | <div id="compare_changeset_status" style="display: none;"> |
|
196 | 294 | ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision='0'*16), None, is_compare=True, form_extras=revs(c.commit_ranges))} |
|
197 | 295 | <script type="text/javascript"> |
|
198 | 296 | |
|
199 | 297 | mainCommentForm.setHandleFormSubmit(function(o) { |
|
200 | 298 | var text = mainCommentForm.cm.getValue(); |
|
201 | 299 | var status = mainCommentForm.getCommentStatus(); |
|
202 | 300 | |
|
203 | 301 | if (text === "" && !status) { |
|
204 | 302 | return; |
|
205 | 303 | } |
|
206 | 304 | |
|
207 | 305 | // we can pick which commits we want to make the comment by |
|
208 | 306 | // selecting them via click on preview pane, this will alter the hidden inputs |
|
209 | 307 | var cherryPicked = $('#changeset_compare_view_content .compare_select.hl').length > 0; |
|
210 | 308 | |
|
211 | 309 | var commitIds = []; |
|
212 | 310 | $('#changeset_compare_view_content .compare_select').each(function(el) { |
|
213 | 311 | var commitId = this.id.replace('row-', ''); |
|
214 | 312 | if ($(this).hasClass('hl') || !cherryPicked) { |
|
215 | 313 | $("input[data-commit-id='{0}']".format(commitId)).val(commitId) |
|
216 | 314 | commitIds.push(commitId); |
|
217 | 315 | } else { |
|
218 | 316 | $("input[data-commit-id='{0}']".format(commitId)).val('') |
|
219 | 317 | } |
|
220 | 318 | }); |
|
221 | 319 | |
|
222 | 320 | mainCommentForm.setActionButtonsDisabled(true); |
|
223 | 321 | mainCommentForm.cm.setOption("readOnly", true); |
|
224 | 322 | var postData = { |
|
225 | 323 | 'text': text, |
|
226 | 324 | 'changeset_status': status, |
|
227 | 325 | 'commit_ids': commitIds, |
|
228 | 326 | 'csrf_token': CSRF_TOKEN |
|
229 | 327 | }; |
|
230 | 328 | |
|
231 | 329 | var submitSuccessCallback = function(o) { |
|
232 | 330 | location.reload(true); |
|
233 | 331 | }; |
|
234 | 332 | var submitFailCallback = function(){ |
|
235 | 333 | mainCommentForm.resetCommentFormState(text) |
|
236 | 334 | }; |
|
237 | 335 | mainCommentForm.submitAjaxPOST( |
|
238 | 336 | mainCommentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback); |
|
239 | 337 | }); |
|
240 | 338 | </script> |
|
241 | 339 | |
|
242 | 340 | </div> |
|
243 | 341 | |
|
244 | %if c.compare_home: | |
|
342 | %if not c.compare_home: | |
|
245 | 343 | <div id="changeset_compare_view_content"> |
|
246 | <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div> | |
|
247 |
< |
|
|
248 | %else: | |
|
249 | <div id="changeset_compare_view_content"> | |
|
250 |
|
|
|
344 | <div class="pull-left"> | |
|
345 | <div class="btn-group"> | |
|
346 | <a | |
|
347 | class="btn" | |
|
348 | href="#" | |
|
349 | onclick="$('.compare_select').show();$('.compare_select_hidden').hide(); return false"> | |
|
350 | ${ungettext('Expand %s commit','Expand %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |
|
351 | </a> | |
|
352 | <a | |
|
353 | class="btn" | |
|
354 | href="#" | |
|
355 | onclick="$('.compare_select').hide();$('.compare_select_hidden').show(); return false"> | |
|
356 | ${ungettext('Collapse %s commit','Collapse %s commits', len(c.commit_ranges)) % len(c.commit_ranges)} | |
|
357 | </a> | |
|
358 | </div> | |
|
359 | </div> | |
|
360 | <div style="padding:0 10px 10px 0px" class="pull-left"></div> | |
|
361 | ## commit compare generated below | |
|
251 | 362 | <%include file="compare_commits.html"/> |
|
252 | 363 | ${cbdiffs.render_diffset_menu()} |
|
253 | 364 | ${cbdiffs.render_diffset(c.diffset)} |
|
254 | 365 | </div> |
|
255 | 366 | %endif |
|
256 | 367 | </div> |
|
257 | 368 | </div> |
|
258 | 369 | </div> |
|
259 | 370 | </%def> |
@@ -1,1162 +1,1160 b'' | |||
|
1 | 1 | ## -*- coding: utf-8 -*- |
|
2 | 2 | <%namespace name="base" file="/base/base.html"/> |
|
3 | 3 | <%inherit file="/debug_style/index.html"/> |
|
4 | 4 | |
|
5 | 5 | <%def name="breadcrumbs_links()"> |
|
6 | 6 | ${h.link_to(_('Style'), h.url('debug_style_home'))} |
|
7 | 7 | » |
|
8 | 8 | ${c.active} |
|
9 | 9 | </%def> |
|
10 | 10 | |
|
11 | 11 | <%def name="js_extra()"> |
|
12 | <script type="text/javascript" src="${h.asset('js/mergerly.js', ver=c.rhodecode_version_hash)}"></script> | |
|
13 | 12 | </%def> |
|
14 | 13 | |
|
15 | 14 | <%def name="css_extra()"> |
|
16 | <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css', ver=c.rhodecode_version_hash)}"/> | |
|
17 | 15 | </%def> |
|
18 | 16 | |
|
19 | 17 | |
|
20 | 18 | <%def name="real_main()"> |
|
21 | 19 | <div class="box"> |
|
22 | 20 | <div class="title"> |
|
23 | 21 | ${self.breadcrumbs()} |
|
24 | 22 | </div> |
|
25 | 23 | |
|
26 | 24 | ##main |
|
27 | 25 | <div class='sidebar-col-wrapper'> |
|
28 | 26 | ${self.sidebar()} |
|
29 | 27 | |
|
30 | 28 | <div class="main-content"> |
|
31 | 29 | |
|
32 | 30 | |
|
33 | 31 | |
|
34 | 32 | <h2>Code Blocks</h2> |
|
35 | 33 | |
|
36 | 34 | <dl class="dl-horizontal"> |
|
37 | 35 | <dt><code>.codeblock</code></dt> |
|
38 | 36 | <dd>Used as a wrapping element around <code>.code-header</code> and |
|
39 | 37 | <code>.code-body</code>. Used to show the content of a file or a |
|
40 | 38 | Gist.</dd> |
|
41 | 39 | |
|
42 | 40 | <dt><code>.diffblock</code></dt> |
|
43 | 41 | <dd>Used as a wrapping element to show a diff in a Commit or Pull |
|
44 | 42 | Request page. Contains usually <code>.code-header</code>, |
|
45 | 43 | <code>.code-body</code> and in the edit case a <code>.message</code>. |
|
46 | 44 | </dd> |
|
47 | 45 | </dl> |
|
48 | 46 | |
|
49 | 47 | |
|
50 | 48 | <p>Code Blocks are used in the following areas:</p> |
|
51 | 49 | |
|
52 | 50 | <ul> |
|
53 | 51 | <li>Commit: Showing the Diff (still called Changeset in a few |
|
54 | 52 | places).</li> |
|
55 | 53 | <li>File: Display a file, annotations, and edit a file.</li> |
|
56 | 54 | <li>Gist: Show the Gist and edit it.</li> |
|
57 | 55 | <li>Pull Request: Display the Diff of a Pull Request.</li> |
|
58 | 56 | </ul> |
|
59 | 57 | |
|
60 | 58 | |
|
61 | 59 | |
|
62 | 60 | <!-- |
|
63 | 61 | Compare Commits |
|
64 | 62 | --> |
|
65 | 63 | <h2>Compare Commits</h2> |
|
66 | 64 | |
|
67 | 65 | <div id="c-e589e34d6be8-5ab783e6d81b" class="diffblock margined comm"> |
|
68 | 66 | <div class="code-header"> |
|
69 | 67 | <div title="Go back to changed files overview"> |
|
70 | 68 | <a href="#changes_box"> |
|
71 | 69 | <i class="icon-circle-arrow-up"></i> |
|
72 | 70 | </a> |
|
73 | 71 | </div> |
|
74 | 72 | <div class="changeset_header"> |
|
75 | 73 | <div class="changeset_file"> |
|
76 | 74 | <i class="icon-file"></i> |
|
77 | 75 | <a href="/example/files/e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d/rhodecode/public/css/code-block.less">rhodecode/public/css/code-block.less</a> |
|
78 | 76 | </div> |
|
79 | 77 | <div class="diff-actions"> |
|
80 | 78 | <a href="/example/diff/rhodecode/public/css/code-block.less?fulldiff=1&diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&diff=diff&diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full diff for this file"> |
|
81 | 79 | <img class="icon" src="/images/icons/page_white_go.png"> |
|
82 | 80 | </a> |
|
83 | 81 | <a href="/example/diff-2way/rhodecode/public/css/code-block.less?fulldiff=1&diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&diff=diff&diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full side-by-side diff for this file"> |
|
84 | 82 | <img class="icon" src="/images/icons/application_double.png"> |
|
85 | 83 | </a> |
|
86 | 84 | <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&diff=raw&diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Raw diff" tt_title="Raw diff"> |
|
87 | 85 | <img class="icon" src="/images/icons/page_white.png"> |
|
88 | 86 | </a> |
|
89 | 87 | <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&diff=download&diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Download diff"> |
|
90 | 88 | <img class="icon" src="/images/icons/page_save.png"> |
|
91 | 89 | </a> |
|
92 | 90 | <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=WS%3A1&c-e589e34d6be8-5ab783e6d81b=C%3A3#c-e589e34d6be8-5ab783e6d81b" title="Ignore white space"><img alt="Ignore white space" class="icon" src="/images/icons/text_strikethrough.png"></a> |
|
93 | 91 | <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=C%3A6#c-e589e34d6be8-5ab783e6d81b" title="increase diff context to 6 lines"><img alt="increase diff context to 6 lines" class="icon" src="/images/icons/table_add.png"></a> |
|
94 | 92 | </div> |
|
95 | 93 | <span> |
|
96 | 94 | <label> |
|
97 | 95 | Show inline comments |
|
98 | 96 | <input checked="checked" class="show-inline-comments" id="" id_for="c-e589e34d6be8-5ab783e6d81b" name="" type="checkbox" value="1"> |
|
99 | 97 | </label> |
|
100 | 98 | </span> |
|
101 | 99 | </div> |
|
102 | 100 | </div> |
|
103 | 101 | <div class="code-body"> |
|
104 | 102 | <div class="full_f_path" path="rhodecode/public/css/code-block.less"></div> |
|
105 | 103 | <table class="code-difftable"> |
|
106 | 104 | <tbody><tr class="line context"> |
|
107 | 105 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td> |
|
108 | 106 | <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td> |
|
109 | 107 | <td class="code no-comment"> |
|
110 | 108 | <pre>@@ -391,7 +391,7 @@ |
|
111 | 109 | </pre> |
|
112 | 110 | </td> |
|
113 | 111 | </tr> |
|
114 | 112 | <tr class="line unmod"> |
|
115 | 113 | <td id="rhodecodepubliccsscode-blockless_o391" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o391">391</a></td> |
|
116 | 114 | <td id="rhodecodepubliccsscode-blockless_n391" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n391">391</a></td> |
|
117 | 115 | <td class="code no-comment"> |
|
118 | 116 | <pre>} /* Existing line, it might have a quite long content actually and in this case we might need some horizontal scrolling. The remaining text here is just used to make this line very long. |
|
119 | 117 | </pre> |
|
120 | 118 | </td> |
|
121 | 119 | </tr> |
|
122 | 120 | <tr class="line unmod"> |
|
123 | 121 | <td id="rhodecodepubliccsscode-blockless_o392" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o392">392</a></td> |
|
124 | 122 | <td id="rhodecodepubliccsscode-blockless_n392" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n392">392</a></td> |
|
125 | 123 | <td class="code no-comment"> |
|
126 | 124 | <pre></pre> |
|
127 | 125 | </td> |
|
128 | 126 | </tr> |
|
129 | 127 | <tr class="line unmod"> |
|
130 | 128 | <td id="rhodecodepubliccsscode-blockless_o393" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o393">393</a></td> |
|
131 | 129 | <td id="rhodecodepubliccsscode-blockless_n393" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n393">393</a></td> |
|
132 | 130 | <td class="code no-comment"> |
|
133 | 131 | <pre>.code-body.textarea.editor, |
|
134 | 132 | </pre> |
|
135 | 133 | </td> |
|
136 | 134 | </tr> |
|
137 | 135 | <tr class="line del"> |
|
138 | 136 | <td id="rhodecodepubliccsscode-blockless_o394" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o394">394</a></td> |
|
139 | 137 | <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n"></a></td> |
|
140 | 138 | <td class="code no-comment"> |
|
141 | 139 | <pre>div.code-body{ |
|
142 | 140 | </pre> |
|
143 | 141 | </td> |
|
144 | 142 | </tr> |
|
145 | 143 | <tr class="line add"> |
|
146 | 144 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td> |
|
147 | 145 | <td id="rhodecodepubliccsscode-blockless_n394" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n394">394</a></td> |
|
148 | 146 | <td class="code no-comment"> |
|
149 | 147 | <pre>div.code-body<ins> </ins>{ |
|
150 | 148 | </pre> |
|
151 | 149 | </td> |
|
152 | 150 | </tr> |
|
153 | 151 | <tr class="line unmod"> |
|
154 | 152 | <td id="rhodecodepubliccsscode-blockless_o395" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o395">395</a></td> |
|
155 | 153 | <td id="rhodecodepubliccsscode-blockless_n395" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n395">395</a></td> |
|
156 | 154 | <td class="code no-comment"> |
|
157 | 155 | <pre> float: left; |
|
158 | 156 | </pre> |
|
159 | 157 | </td> |
|
160 | 158 | </tr> |
|
161 | 159 | <tr class="line unmod"> |
|
162 | 160 | <td id="rhodecodepubliccsscode-blockless_o396" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o396">396</a></td> |
|
163 | 161 | <td id="rhodecodepubliccsscode-blockless_n396" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n396">396</a></td> |
|
164 | 162 | <td class="code no-comment"> |
|
165 | 163 | <pre> position: relative; |
|
166 | 164 | </pre> |
|
167 | 165 | </td> |
|
168 | 166 | </tr> |
|
169 | 167 | <tr class="line unmod"> |
|
170 | 168 | <td id="rhodecodepubliccsscode-blockless_o397" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o397">397</a></td> |
|
171 | 169 | <td id="rhodecodepubliccsscode-blockless_n397" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n397">397</a></td> |
|
172 | 170 | <td class="code no-comment"> |
|
173 | 171 | <pre> max-width: none; |
|
174 | 172 | </pre> |
|
175 | 173 | </td> |
|
176 | 174 | </tr> |
|
177 | 175 | <tr class="line context"> |
|
178 | 176 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td> |
|
179 | 177 | <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td> |
|
180 | 178 | <td class="code no-comment"> |
|
181 | 179 | <pre>@@ -399,3 +399,6 @@ |
|
182 | 180 | </pre> |
|
183 | 181 | </td> |
|
184 | 182 | </tr> |
|
185 | 183 | <tr class="line unmod"> |
|
186 | 184 | <td id="rhodecodepubliccsscode-blockless_o399" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o399">399</a></td> |
|
187 | 185 | <td id="rhodecodepubliccsscode-blockless_n399" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n399">399</a></td> |
|
188 | 186 | <td class="code no-comment"> |
|
189 | 187 | <pre> box-sizing: border-box; |
|
190 | 188 | </pre> |
|
191 | 189 | </td> |
|
192 | 190 | </tr> |
|
193 | 191 | <tr class="line unmod"> |
|
194 | 192 | <td id="rhodecodepubliccsscode-blockless_o400" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o400">400</a></td> |
|
195 | 193 | <td id="rhodecodepubliccsscode-blockless_n400" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n400">400</a></td> |
|
196 | 194 | <td class="code no-comment"> |
|
197 | 195 | <pre>} |
|
198 | 196 | </pre> |
|
199 | 197 | </td> |
|
200 | 198 | </tr> |
|
201 | 199 | <tr class="line unmod"> |
|
202 | 200 | <td id="rhodecodepubliccsscode-blockless_o401" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o401">401</a></td> |
|
203 | 201 | <td id="rhodecodepubliccsscode-blockless_n401" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n401">401</a></td> |
|
204 | 202 | <td class="code no-comment"> |
|
205 | 203 | <pre></pre> |
|
206 | 204 | </td> |
|
207 | 205 | </tr> |
|
208 | 206 | <tr class="line add"> |
|
209 | 207 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td> |
|
210 | 208 | <td id="rhodecodepubliccsscode-blockless_n402" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n402">402</a></td> |
|
211 | 209 | <td class="code no-comment"> |
|
212 | 210 | <pre>.code-body td{ |
|
213 | 211 | </pre> |
|
214 | 212 | </td> |
|
215 | 213 | </tr> |
|
216 | 214 | <tr class="line add"> |
|
217 | 215 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td> |
|
218 | 216 | <td id="rhodecodepubliccsscode-blockless_n403" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n403">403</a></td> |
|
219 | 217 | <td class="code no-comment"> |
|
220 | 218 | <pre> line-height: 1.2em; |
|
221 | 219 | </pre> |
|
222 | 220 | </td> |
|
223 | 221 | </tr> |
|
224 | 222 | <tr class="line add"> |
|
225 | 223 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td> |
|
226 | 224 | <td id="rhodecodepubliccsscode-blockless_n404" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n404">404</a></td> |
|
227 | 225 | <td class="code no-comment"> |
|
228 | 226 | <pre>} |
|
229 | 227 | </pre> |
|
230 | 228 | </td> |
|
231 | 229 | </tr> |
|
232 | 230 | <tr class="line context"> |
|
233 | 231 | <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td> |
|
234 | 232 | <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td> |
|
235 | 233 | <td class="code no-comment"> |
|
236 | 234 | <pre> No newline at end of file |
|
237 | 235 | </pre> |
|
238 | 236 | </td> |
|
239 | 237 | </tr> |
|
240 | 238 | </tbody></table> |
|
241 | 239 | </div> |
|
242 | 240 | </div> |
|
243 | 241 | |
|
244 | 242 | |
|
245 | 243 | |
|
246 | 244 | |
|
247 | 245 | |
|
248 | 246 | |
|
249 | 247 | <!-- |
|
250 | 248 | Pull Request |
|
251 | 249 | --> |
|
252 | 250 | |
|
253 | 251 | <h2>Pull Request</h2> |
|
254 | 252 | |
|
255 | 253 | <div class="cs_files"> |
|
256 | 254 | <table class="compare_view_files"> |
|
257 | 255 | |
|
258 | 256 | <tbody><tr class="cs_M collapse_file" fid="c--5f1d017cf13b"> |
|
259 | 257 | <td class="cs_icon_td"> |
|
260 | 258 | <span class="collapse_file_icon" fid="c--5f1d017cf13b"></span> |
|
261 | 259 | </td> |
|
262 | 260 | <td class="cs_icon_td"> |
|
263 | 261 | <div class="flag_status not_reviewed hidden"></div> |
|
264 | 262 | </td> |
|
265 | 263 | <td id="a_c--5f1d017cf13b"> |
|
266 | 264 | <a class="compare_view_filepath" href="#a_c--5f1d017cf13b"> |
|
267 | 265 | rhodecode/public/css/main.less |
|
268 | 266 | </a> |
|
269 | 267 | <span id="diff_c--5f1d017cf13b" class="diff_links" style=""> |
|
270 | 268 | <a href="/example/diff/rhodecode/public/css/main.less?fulldiff=1&diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&diff=diff&diff2=27eb56cf467ca849112536d62decb2ed020b3ebc"> |
|
271 | 269 | Unified Diff |
|
272 | 270 | </a> |
|
273 | 271 | | |
|
274 | 272 | <a href="/example/diff-2way/rhodecode/public/css/main.less?fulldiff=1&diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&diff=diff&diff2=27eb56cf467ca849112536d62decb2ed020b3ebc"> |
|
275 | 273 | Side-by-side Diff |
|
276 | 274 | </a> |
|
277 | 275 | </span> |
|
278 | 276 | </td> |
|
279 | 277 | <td> |
|
280 | 278 | <div class="changes pull-right"><div style="width:100px"><div class="added top-left-rounded-corner-mid bottom-left-rounded-corner-mid" style="width:33.3333333333%">1</div><div class="deleted top-right-rounded-corner-mid bottom-right-rounded-corner-mid" style="width:66.6666666667%">2</div></div></div> |
|
281 | 279 | <div class="comment-bubble pull-right" data-path="rhodecode/public/css/main.less"> |
|
282 | 280 | <i class="icon-comment"></i> |
|
283 | 281 | </div> |
|
284 | 282 | </td> |
|
285 | 283 | </tr> |
|
286 | 284 | <tr id="tr_c--5f1d017cf13b"> |
|
287 | 285 | <td></td> |
|
288 | 286 | <td></td> |
|
289 | 287 | <td class="injected_diff" colspan="2"> |
|
290 | 288 | |
|
291 | 289 | <div class="diff-container" id="diff-container-140360026534904"> |
|
292 | 290 | <div id="c--5f1d017cf13b_target"></div> |
|
293 | 291 | <div id="c--5f1d017cf13b" class="diffblock margined comm"> |
|
294 | 292 | <div class="code-body"> |
|
295 | 293 | <div class="full_f_path" path="rhodecode/public/css/main.less" style="display: none;"></div> |
|
296 | 294 | <table class="code-difftable"> |
|
297 | 295 | <tbody><tr class="line context"> |
|
298 | 296 | <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td> |
|
299 | 297 | <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td> |
|
300 | 298 | <td class="code "> |
|
301 | 299 | <pre>@@ -2110,7 +2110,6 @@ |
|
302 | 300 | </pre> |
|
303 | 301 | </td> |
|
304 | 302 | </tr> |
|
305 | 303 | <tr class="line unmod"> |
|
306 | 304 | <td id="rhodecodepubliccssmainless_o2110" class="lineno old"><a href="#rhodecodepubliccssmainless_o2110">2110</a></td> |
|
307 | 305 | <td id="rhodecodepubliccssmainless_n2110" class="lineno new"><a href="#rhodecodepubliccssmainless_n2110">2110</a></td> |
|
308 | 306 | <td class="code "> |
|
309 | 307 | <pre><span class="tab-escape"> </span>width: auto !important; |
|
310 | 308 | </pre> |
|
311 | 309 | </td> |
|
312 | 310 | </tr> |
|
313 | 311 | <tr class="line unmod"> |
|
314 | 312 | <td id="rhodecodepubliccssmainless_o2111" class="lineno old"><a href="#rhodecodepubliccssmainless_o2111">2111</a></td> |
|
315 | 313 | <td id="rhodecodepubliccssmainless_n2111" class="lineno new"><a href="#rhodecodepubliccssmainless_n2111">2111</a></td> |
|
316 | 314 | <td class="code "> |
|
317 | 315 | <pre><span class="tab-escape"> </span>min-width: 160px; |
|
318 | 316 | </pre> |
|
319 | 317 | </td> |
|
320 | 318 | </tr> |
|
321 | 319 | <tr class="line unmod"> |
|
322 | 320 | <td id="rhodecodepubliccssmainless_o2112" class="lineno old"><a href="#rhodecodepubliccssmainless_o2112">2112</a></td> |
|
323 | 321 | <td id="rhodecodepubliccssmainless_n2112" class="lineno new"><a href="#rhodecodepubliccssmainless_n2112">2112</a></td> |
|
324 | 322 | <td class="code "> |
|
325 | 323 | <pre><span class="tab-escape"> </span>margin: @padding @padding @padding 0; |
|
326 | 324 | </pre> |
|
327 | 325 | </td> |
|
328 | 326 | </tr> |
|
329 | 327 | <tr class="line del"> |
|
330 | 328 | <td id="rhodecodepubliccssmainless_o2113" class="lineno old"><a href="#rhodecodepubliccssmainless_o2113">2113</a></td> |
|
331 | 329 | <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td> |
|
332 | 330 | <td class="code "> |
|
333 | 331 | <pre><span class="tab-escape"> </span>padding: .9em; /* Old comment which was making this line a very long line so that we might have to deal with it by either adding horizontal scrolling or some smart way of breaking this line. */ |
|
334 | 332 | </pre> |
|
335 | 333 | </td> |
|
336 | 334 | </tr> |
|
337 | 335 | <tr class="line unmod"> |
|
338 | 336 | <td id="rhodecodepubliccssmainless_o2114" class="lineno old"><a href="#rhodecodepubliccssmainless_o2114">2114</a></td> |
|
339 | 337 | <td id="rhodecodepubliccssmainless_n2113" class="lineno new"><a href="#rhodecodepubliccssmainless_n2113">2113</a></td> |
|
340 | 338 | <td class="code "> |
|
341 | 339 | <pre> line-height: 1em; |
|
342 | 340 | </pre> |
|
343 | 341 | </td> |
|
344 | 342 | </tr> |
|
345 | 343 | <tr class="line unmod"> |
|
346 | 344 | <td id="rhodecodepubliccssmainless_o2115" class="lineno old"><a href="#rhodecodepubliccssmainless_o2115">2115</a></td> |
|
347 | 345 | <td id="rhodecodepubliccssmainless_n2114" class="lineno new"><a href="#rhodecodepubliccssmainless_n2114">2114</a></td> |
|
348 | 346 | <td class="code "> |
|
349 | 347 | <pre><span class="tab-escape"> </span>z-index: 100;//js sets the menu below it to 9999 |
|
350 | 348 | </pre> |
|
351 | 349 | </td> |
|
352 | 350 | </tr> |
|
353 | 351 | <tr class="line unmod"> |
|
354 | 352 | <td id="rhodecodepubliccssmainless_o2116" class="lineno old"><a href="#rhodecodepubliccssmainless_o2116">2116</a></td> |
|
355 | 353 | <td id="rhodecodepubliccssmainless_n2115" class="lineno new"><a href="#rhodecodepubliccssmainless_n2115">2115</a></td> |
|
356 | 354 | <td class="code "> |
|
357 | 355 | <pre><span class="tab-escape"> </span>background-color: white; |
|
358 | 356 | </pre> |
|
359 | 357 | </td> |
|
360 | 358 | </tr> |
|
361 | 359 | <tr class="line context"> |
|
362 | 360 | <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td> |
|
363 | 361 | <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td> |
|
364 | 362 | <td class="code "> |
|
365 | 363 | <pre>@@ -2118,7 +2117,7 @@ |
|
366 | 364 | </pre> |
|
367 | 365 | </td> |
|
368 | 366 | </tr> |
|
369 | 367 | <tr class="line unmod"> |
|
370 | 368 | <td id="rhodecodepubliccssmainless_o2118" class="lineno old"><a href="#rhodecodepubliccssmainless_o2118">2118</a></td> |
|
371 | 369 | <td id="rhodecodepubliccssmainless_n2117" class="lineno new"><a href="#rhodecodepubliccssmainless_n2117">2117</a></td> |
|
372 | 370 | <td class="code "> |
|
373 | 371 | <pre></pre> |
|
374 | 372 | </td> |
|
375 | 373 | </tr> |
|
376 | 374 | <tr class="line unmod"> |
|
377 | 375 | <td id="rhodecodepubliccssmainless_o2119" class="lineno old"><a href="#rhodecodepubliccssmainless_o2119">2119</a></td> |
|
378 | 376 | <td id="rhodecodepubliccssmainless_n2118" class="lineno new"><a href="#rhodecodepubliccssmainless_n2118">2118</a></td> |
|
379 | 377 | <td class="code "> |
|
380 | 378 | <pre><span class="tab-escape"> </span>a { |
|
381 | 379 | </pre> |
|
382 | 380 | </td> |
|
383 | 381 | </tr> |
|
384 | 382 | <tr class="line unmod"> |
|
385 | 383 | <td id="rhodecodepubliccssmainless_o2120" class="lineno old"><a href="#rhodecodepubliccssmainless_o2120">2120</a></td> |
|
386 | 384 | <td id="rhodecodepubliccssmainless_n2119" class="lineno new"><a href="#rhodecodepubliccssmainless_n2119">2119</a></td> |
|
387 | 385 | <td class="code "> |
|
388 | 386 | <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>display:block; |
|
389 | 387 | </pre> |
|
390 | 388 | </td> |
|
391 | 389 | </tr> |
|
392 | 390 | <tr class="line del"> |
|
393 | 391 | <td id="rhodecodepubliccssmainless_o2121" class="lineno old"><a href="#rhodecodepubliccssmainless_o2121">2121</a></td> |
|
394 | 392 | <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td> |
|
395 | 393 | <td class="code "> |
|
396 | 394 | <pre><span class="tab-escape"> </span><del><span< del=""> <del>class=</del><del>"tab-escape"</del><del>> </del>padding: <del>0</del>; |
|
397 | 395 | </span<></del></pre> |
|
398 | 396 | </td> |
|
399 | 397 | </tr> |
|
400 | 398 | <tr class="line add"> |
|
401 | 399 | <td class="lineno old"><a href="#rhodecodepubliccssmainless_o"></a></td> |
|
402 | 400 | <td id="rhodecodepubliccssmainless_n2120" class="lineno new"><a href="#rhodecodepubliccssmainless_n2120">2120</a></td> |
|
403 | 401 | <td class="code "> |
|
404 | 402 | <pre><span class="tab-escape"> </span><ins> </ins> <ins> </ins><ins> </ins>padding: <ins>.9em</ins>; |
|
405 | 403 | </pre> |
|
406 | 404 | </td> |
|
407 | 405 | </tr> |
|
408 | 406 | <tr class="line unmod"> |
|
409 | 407 | <td id="rhodecodepubliccssmainless_o2122" class="lineno old"><a href="#rhodecodepubliccssmainless_o2122">2122</a></td> |
|
410 | 408 | <td id="rhodecodepubliccssmainless_n2121" class="lineno new"><a href="#rhodecodepubliccssmainless_n2121">2121</a></td> |
|
411 | 409 | <td class="code "> |
|
412 | 410 | <pre></pre> |
|
413 | 411 | </td> |
|
414 | 412 | </tr> |
|
415 | 413 | <tr class="line unmod"> |
|
416 | 414 | <td id="rhodecodepubliccssmainless_o2123" class="lineno old"><a href="#rhodecodepubliccssmainless_o2123">2123</a></td> |
|
417 | 415 | <td id="rhodecodepubliccssmainless_n2122" class="lineno new"><a href="#rhodecodepubliccssmainless_n2122">2122</a></td> |
|
418 | 416 | <td class="code "> |
|
419 | 417 | <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>&:after { |
|
420 | 418 | </pre> |
|
421 | 419 | </td> |
|
422 | 420 | </tr> |
|
423 | 421 | <tr class="line unmod"> |
|
424 | 422 | <td id="rhodecodepubliccssmainless_o2124" class="lineno old"><a href="#rhodecodepubliccssmainless_o2124">2124</a></td> |
|
425 | 423 | <td id="rhodecodepubliccssmainless_n2123" class="lineno new"><a href="#rhodecodepubliccssmainless_n2123">2123</a></td> |
|
426 | 424 | <td class="code "> |
|
427 | 425 | <pre><span class="tab-escape"> </span><span class="tab-escape"> </span><span class="tab-escape"> </span>content: "\00A0\25BE"; |
|
428 | 426 | </pre> |
|
429 | 427 | </td> |
|
430 | 428 | </tr> |
|
431 | 429 | </tbody></table> |
|
432 | 430 | </div> |
|
433 | 431 | </div> |
|
434 | 432 | </div> |
|
435 | 433 | |
|
436 | 434 | </td> |
|
437 | 435 | </tr> |
|
438 | 436 | </tbody></table> |
|
439 | 437 | </div> |
|
440 | 438 | |
|
441 | 439 | |
|
442 | 440 | |
|
443 | 441 | |
|
444 | 442 | |
|
445 | 443 | |
|
446 | 444 | |
|
447 | 445 | |
|
448 | 446 | |
|
449 | 447 | <!-- |
|
450 | 448 | File View |
|
451 | 449 | --> |
|
452 | 450 | |
|
453 | 451 | ##TODO: lisa: I believe this needs to be updated as the layout has changed. |
|
454 | 452 | <h2>File View</h2> |
|
455 | 453 | |
|
456 | 454 | <div class="codeblock"> |
|
457 | 455 | <div class="code-header"> |
|
458 | 456 | <div class="stats"> |
|
459 | 457 | <div class="img"> |
|
460 | 458 | <i class="icon-file"></i> |
|
461 | 459 | <span class="revision_id item"><a href="/example/changeset/fc252256eb0fcb4f2613e66f0126ea27967ae28c">r5487:fc252256eb0f</a></span> |
|
462 | 460 | <span>1.2 KiB</span> |
|
463 | 461 | <span class="item last">text/x-python</span> |
|
464 | 462 | <div class="buttons"> |
|
465 | 463 | |
|
466 | 464 | <a id="file_history_overview" class="btn btn-mini" href="#"> |
|
467 | 465 | <i class="icon-time"></i> history |
|
468 | 466 | </a> |
|
469 | 467 | <a id="file_history_overview_full" class="btn btn-mini" style="display: none" href="/example/changelog/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py"> |
|
470 | 468 | <i class="icon-time"></i> show full history |
|
471 | 469 | </a> |
|
472 | 470 | <a class="btn btn-mini" href="/example/annotate/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">annotation</a> |
|
473 | 471 | <a class="btn btn-mini" href="/example/raw/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">raw</a> |
|
474 | 472 | <a class="btn btn-mini" href="/example/rawfile/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py"> |
|
475 | 473 | <i class="icon-archive"></i> download |
|
476 | 474 | </a> |
|
477 | 475 | |
|
478 | 476 | <a class="btn btn-mini disabled tooltip" href="#" title="Editing files allowed only when on branch head commit">edit</a> |
|
479 | 477 | <a class="btn btn-mini btn-danger disabled tooltip" href="#" title="Deleting files allowed only when on branch head commit">delete</a> |
|
480 | 478 | </div> |
|
481 | 479 | </div> |
|
482 | 480 | </div> |
|
483 | 481 | <div id="file_history_container"></div> |
|
484 | 482 | <div class="author"> |
|
485 | 483 | <div class="gravatar"> |
|
486 | 484 | <img alt="gravatar" src="https://secure.gravatar.com/avatar/99e27b99c64003ca8c9875c9e3843495?d=identicon&s=32" height="16" width="16"> |
|
487 | 485 | </div> |
|
488 | 486 | <div title="Marcin Kuzminski <marcin@python-works.com>" class="user">Marcin Kuzminski - <span class="tooltip" title="Wed, 02 Jul 2014 08:48:15">6m and 12d ago</span></div> |
|
489 | 487 | </div> |
|
490 | 488 | <div id="trimmed_message_box" class="commit">License changes</div> |
|
491 | 489 | <div id="message_expand" style="display: none;"> |
|
492 | 490 | <i class="icon-resize-vertical"></i> |
|
493 | 491 | expand |
|
494 | 492 | <i class="icon-resize-vertical"></i> |
|
495 | 493 | </div> |
|
496 | 494 | </div> |
|
497 | 495 | <div class="code-body"> |
|
498 | 496 | <table class="code-highlighttable"><tbody><tr><td class="linenos"><div class="linenodiv"><pre><a href="#L1"> 1</a> |
|
499 | 497 | <a href="#L2"> 2</a> |
|
500 | 498 | <a href="#L3"> 3</a> |
|
501 | 499 | <a href="#L4"> 4</a> |
|
502 | 500 | <a href="#L5"> 5</a> |
|
503 | 501 | <a href="#L6"> 6</a> |
|
504 | 502 | <a href="#L7"> 7</a> |
|
505 | 503 | <a href="#L8"> 8</a> |
|
506 | 504 | <a href="#L9"> 9</a> |
|
507 | 505 | <a href="#L10">10</a> |
|
508 | 506 | <a href="#L11">11</a> |
|
509 | 507 | <a href="#L12">12</a> |
|
510 | 508 | <a href="#L13">13</a> |
|
511 | 509 | <a href="#L14">14</a> |
|
512 | 510 | <a href="#L15">15</a> |
|
513 | 511 | <a href="#L16">16</a> |
|
514 | 512 | <a href="#L17">17</a> |
|
515 | 513 | <a href="#L18">18</a> |
|
516 | 514 | <a href="#L19">19</a> |
|
517 | 515 | <a href="#L20">20</a> |
|
518 | 516 | <a href="#L21">21</a> |
|
519 | 517 | <a href="#L22">22</a> |
|
520 | 518 | <a href="#L23">23</a> |
|
521 | 519 | <a href="#L24">24</a> |
|
522 | 520 | <a href="#L25">25</a> |
|
523 | 521 | <a href="#L26">26</a> |
|
524 | 522 | <a href="#L27">27</a> |
|
525 | 523 | <a href="#L28">28</a> |
|
526 | 524 | <a href="#L29">29</a> |
|
527 | 525 | <a href="#L30">30</a> |
|
528 | 526 | <a href="#L31">31</a> |
|
529 | 527 | <a href="#L32">32</a> |
|
530 | 528 | <a href="#L33">33</a> |
|
531 | 529 | <a href="#L34">34</a> |
|
532 | 530 | <a href="#L35">35</a> |
|
533 | 531 | <a href="#L36">36</a> |
|
534 | 532 | <a href="#L37">37</a> |
|
535 | 533 | <a href="#L38">38</a> |
|
536 | 534 | <a href="#L39">39</a> |
|
537 | 535 | <a href="#L40">40</a> |
|
538 | 536 | <a href="#L41">41</a> |
|
539 | 537 | <a href="#L42">42</a></pre></div></td><td id="hlcode" class="code"><div class="code-highlight"><pre><div id="L1"><a name="L-1"></a><span class="c"># -*- coding: utf-8 -*-</span> |
|
540 | 538 | </div><div id="L2"><a name="L-2"></a> |
|
541 | 539 | </div><div id="L3"><a name="L-3"></a><span class="c"># Published under Business Source License.</span> |
|
542 | 540 | </div><div id="L4"><a name="L-4"></a><span class="c"># Read the full license text at https://rhodecode.com/licenses.</span> |
|
543 | 541 | </div><div id="L5"><a name="L-5"></a><span class="sd">"""</span> |
|
544 | 542 | </div><div id="L6"><a name="L-6"></a><span class="sd">rhodecode.websetup</span> |
|
545 | 543 | </div><div id="L7"><a name="L-7"></a><span class="sd">~~~~~~~~~~~~~~~~~~</span> |
|
546 | 544 | </div><div id="L8"><a name="L-8"></a> |
|
547 | 545 | </div><div id="L9"><a name="L-9"></a><span class="sd">Weboperations and setup for rhodecode. Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</span> |
|
548 | 546 | </div><div id="L10"><a name="L-10"></a> |
|
549 | 547 | </div><div id="L11"><a name="L-11"></a><span class="sd">:created_on: Dec 11, 2010</span> |
|
550 | 548 | </div><div id="L12"><a name="L-12"></a><span class="sd">:author: marcink</span> |
|
551 | 549 | </div><div id="L13"><a name="L-13"></a><span class="sd">:copyright: (c) 2013-2015 RhodeCode GmbH.</span> |
|
552 | 550 | </div><div id="L14"><a name="L-14"></a><span class="sd">:license: Business Source License, see LICENSE for more details.</span> |
|
553 | 551 | </div><div id="L15"><a name="L-15"></a><span class="sd">"""</span> |
|
554 | 552 | </div><div id="L16"><a name="L-16"></a> |
|
555 | 553 | </div><div id="L17"><a name="L-17"></a><span class="kn">import</span> <span class="nn">logging</span> |
|
556 | 554 | </div><div id="L18"><a name="L-18"></a> |
|
557 | 555 | </div><div id="L19"><a name="L-19"></a><span class="kn">from</span> <span class="nn">rhodecode.config.environment</span> <span class="kn">import</span> <span class="n">load_environment</span> |
|
558 | 556 | </div><div id="L20"><a name="L-20"></a><span class="kn">from</span> <span class="nn">rhodecode.lib.db_manage</span> <span class="kn">import</span> <span class="n">DbManage</span> |
|
559 | 557 | </div><div id="L21"><a name="L-21"></a><span class="kn">from</span> <span class="nn">rhodecode.model.meta</span> <span class="kn">import</span> <span class="n">Session</span> |
|
560 | 558 | </div><div id="L22"><a name="L-22"></a> |
|
561 | 559 | </div><div id="L23"><a name="L-23"></a> |
|
562 | 560 | </div><div id="L24"><a name="L-24"></a><span class="n">log</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="n">__name__</span><span class="p">)</span> |
|
563 | 561 | </div><div id="L25"><a name="L-25"></a> |
|
564 | 562 | </div><div id="L26"><a name="L-26"></a> |
|
565 | 563 | </div><div id="L27"><a name="L-27"></a><span class="k">def</span> <span class="nf">setup_app</span><span class="p">(</span><span class="n">command</span><span class="p">,</span> <span class="n">conf</span><span class="p">,</span> <span class="nb">vars</span><span class="p">):</span> |
|
566 | 564 | </div><div id="L28"><a name="L-28"></a> <span class="sd">"""Place any commands to setup rhodecode here"""</span> |
|
567 | 565 | </div><div id="L29"><a name="L-29"></a> <span class="n">dbconf</span> <span class="o">=</span> <span class="n">conf</span><span class="p">[</span><span class="s">'sqlalchemy.db1.url'</span><span class="p">]</span> |
|
568 | 566 | </div><div id="L30"><a name="L-30"></a> <span class="n">dbmanage</span> <span class="o">=</span> <span class="n">DbManage</span><span class="p">(</span><span class="n">log_sql</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">dbconf</span><span class="o">=</span><span class="n">dbconf</span><span class="p">,</span> <span class="n">root</span><span class="o">=</span><span class="n">conf</span><span class="p">[</span><span class="s">'here'</span><span class="p">],</span> |
|
569 | 567 | </div><div id="L31"><a name="L-31"></a> <span class="n">tests</span><span class="o">=</span><span class="bp">False</span><span class="p">,</span> <span class="n">cli_args</span><span class="o">=</span><span class="n">command</span><span class="o">.</span><span class="n">options</span><span class="o">.</span><span class="n">__dict__</span><span class="p">)</span> |
|
570 | 568 | </div><div id="L32"><a name="L-32"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_tables</span><span class="p">(</span><span class="n">override</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> |
|
571 | 569 | </div><div id="L33"><a name="L-33"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">set_db_version</span><span class="p">()</span> |
|
572 | 570 | </div><div id="L34"><a name="L-34"></a> <span class="n">opts</span> <span class="o">=</span> <span class="n">dbmanage</span><span class="o">.</span><span class="n">config_prompt</span><span class="p">(</span><span class="bp">None</span><span class="p">)</span> |
|
573 | 571 | </div><div id="L35"><a name="L-35"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_settings</span><span class="p">(</span><span class="n">opts</span><span class="p">)</span> |
|
574 | 572 | </div><div id="L36"><a name="L-36"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_default_user</span><span class="p">()</span> |
|
575 | 573 | </div><div id="L37"><a name="L-37"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">admin_prompt</span><span class="p">()</span> |
|
576 | 574 | </div><div id="L38"><a name="L-38"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">create_permissions</span><span class="p">()</span> |
|
577 | 575 | </div><div id="L39"><a name="L-39"></a> <span class="n">dbmanage</span><span class="o">.</span><span class="n">populate_default_permissions</span><span class="p">()</span> |
|
578 | 576 | </div><div id="L40"><a name="L-40"></a> <span class="n">Session</span><span class="p">()</span><span class="o">.</span><span class="n">commit</span><span class="p">()</span> |
|
579 | 577 | </div><div id="L41"><a name="L-41"></a> <span class="n">load_environment</span><span class="p">(</span><span class="n">conf</span><span class="o">.</span><span class="n">global_conf</span><span class="p">,</span> <span class="n">conf</span><span class="o">.</span><span class="n">local_conf</span><span class="p">,</span> <span class="n">initial</span><span class="o">=</span><span class="bp">True</span><span class="p">)</span> |
|
580 | 578 | </div><div id="L42"><a name="L-42"></a> <span class="n">DbManage</span><span class="o">.</span><span class="n">check_waitress</span><span class="p">()</span> |
|
581 | 579 | </div></pre></div> |
|
582 | 580 | </td></tr></tbody></table> |
|
583 | 581 | </div> |
|
584 | 582 | </div> |
|
585 | 583 | |
|
586 | 584 | |
|
587 | 585 | |
|
588 | 586 | |
|
589 | 587 | |
|
590 | 588 | |
|
591 | 589 | |
|
592 | 590 | |
|
593 | 591 | |
|
594 | 592 | <!-- |
|
595 | 593 | Gist Edit |
|
596 | 594 | --> |
|
597 | 595 | |
|
598 | 596 | |
|
599 | 597 | <h2>Gist Edit</h2> |
|
600 | 598 | |
|
601 | 599 | <div class="codeblock"> |
|
602 | 600 | <div class="code-header"> |
|
603 | 601 | <div class="form"> |
|
604 | 602 | <div class="fields"> |
|
605 | 603 | <input id="filename" name="filename" placeholder="name this file..." size="30" type="text"> |
|
606 | 604 | <div class="select2-container drop-menu" id="s2id_mimetype"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-3">Python</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen3" class="select2-offscreen"></label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-3" id="s2id_autogen3"><div class="select2-drop select2-display-none drop-menu-dropdown select2-with-searchbox"> <div class="select2-search"> <label for="s2id_autogen3_search" class="select2-offscreen"></label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-3" id="s2id_autogen3_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-3"> </ul></div></div><select id="mimetype" name="mimetype" tabindex="-1" title="" style="display: none;"> |
|
607 | 605 | <option selected="selected" value="plain">plain</option> |
|
608 | 606 | <option value="text/apl" mode="apl">APL</option><option value="text/x-asterisk" mode="asterisk">Asterisk</option><option value="text/x-csrc" mode="clike">C</option><option value="text/x-c++src" mode="clike">C++</option><option value="text/x-cobol" mode="cobol">Cobol</option><option value="text/x-java" mode="clike">Java</option><option value="text/x-csharp" mode="clike">C#</option><option value="text/x-scala" mode="clike">Scala</option><option value="text/x-clojure" mode="clojure">Clojure</option><option value="text/x-coffeescript" mode="coffeescript">CoffeeScript</option><option value="text/x-common-lisp" mode="commonlisp">Common Lisp</option><option value="text/css" mode="css">CSS</option><option value="text/x-d" mode="d">D</option><option value="text/x-diff" mode="diff">diff</option><option value="application/xml-dtd" mode="dtd">DTD</option><option value="text/x-dylan" mode="dylan">Dylan</option><option value="text/x-ecl" mode="ecl">ECL</option><option value="text/x-eiffel" mode="eiffel">Eiffel</option><option value="text/x-erlang" mode="erlang">Erlang</option><option value="text/x-fortran" mode="fortran">Fortran</option><option value="text/x-fsharp" mode="mllike">F#</option><option value="text/x-gas" mode="gas">Gas</option><option value="text/x-go" mode="go">GO</option><option value="text/x-feature" mode="gherkin">Gherkin</option><option value="text/x-go" mode="go">Go</option><option value="text/x-groovy" mode="groovy">Groovy</option><option value="text/x-haml" mode="haml">HAML</option><option value="text/x-haskell" mode="haskell">Haskell</option><option value="text/x-haxe" mode="haxe">Haxe</option><option value="application/x-aspx" mode="htmlembedded">ASP.NET</option><option value="application/x-ejs" mode="htmlembedded">Embedded Javascript</option><option value="application/x-jsp" mode="htmlembedded">JavaServer Pages</option><option value="text/html" mode="htmlmixed">HTML</option><option value="message/http" mode="http">HTTP</option><option value="text/x-jade" mode="jade">Jade</option><option value="text/javascript" mode="javascript">JavaScript</option><option value="application/json" mode="javascript">JSON</option><option value="application/typescript" mode="javascript">TypeScript</option><option value="jinja2" mode="jinja2">Jinja2</option><option value="text/x-julia" mode="julia">Julia</option><option value="text/x-less" mode="less">LESS</option><option value="text/x-livescript" mode="livescript">LiveScript</option><option value="text/x-lua" mode="lua">Lua</option><option value="text/x-markdown" mode="markdown">Markdown (GitHub-flavour)</option><option value="text/mirc" mode="mirc">mIRC</option><option value="text/x-nginx-conf" mode="nginx">Nginx</option><option value="text/n-triples" mode="ntriples">NTriples</option><option value="text/x-ocaml" mode="ocaml">OCaml</option><option value="text/x-ocaml" mode="mllike">OCaml</option><option value="text/x-octave" mode="octave">Octave</option><option value="text/x-pascal" mode="pascal">Pascal</option><option value="null" mode="pegjs">PEG.js</option><option value="text/x-perl" mode="perl">Perl</option><option value="text/x-php" mode="php">PHP</option><option value="text/x-pig" mode="pig">Pig</option><option value="text/plain" mode="null">Plain Text</option><option value="text/x-properties" mode="properties">Properties files</option><option value="text/x-python" mode="python">Python</option><option value="text/x-puppet" mode="puppet">Puppet</option><option value="text/x-rsrc" mode="r">R</option><option value="text/x-rst" mode="rst">reStructuredText</option><option value="text/x-ruby" mode="ruby">Ruby</option><option value="text/x-rustsrc" mode="rust">Rust</option><option value="text/x-sass" mode="sass">Sass</option><option value="text/x-scheme" mode="scheme">Scheme</option><option value="text/x-scss" mode="css">SCSS</option><option value="text/x-sh" mode="shell">Shell</option><option value="application/sieve" mode="sieve">Sieve</option><option value="text/x-stsrc" mode="smalltalk">Smalltalk</option><option value="text/x-smarty" mode="smarty">Smarty</option><option value="text/x-smarty" mode="smartymixed">SmartyMixed</option><option value="text/x-solr" mode="solr">Solr</option><option value="application/x-sparql-query" mode="sparql">SPARQL</option><option value="text/x-sql" mode="sql">SQL</option><option value="text/x-mariadb" mode="sql">MariaDB</option><option value="text/x-stex" mode="stex">sTeX</option><option value="text/x-latex" mode="stex">LaTeX</option><option value="text/x-systemverilog" mode="verilog">SystemVerilog</option><option value="text/x-tcl" mode="tcl">Tcl</option><option value="text/x-tiddlywiki" mode="tiddlywiki">TiddlyWiki </option><option value="text/tiki" mode="tiki">Tiki wiki</option><option value="text/x-toml" mode="toml">TOML</option><option value="text/turtle" mode="turtle">Turtle</option><option value="text/x-vb" mode="vb">VB.NET</option><option value="text/vbscript" mode="vbscript">VBScript</option><option value="text/velocity" mode="velocity">Velocity</option><option value="text/x-verilog" mode="verilog">Verilog</option><option value="application/xml" mode="xml">XML</option><option value="text/html" mode="xml">HTML</option><option value="application/xquery" mode="xquery">XQuery</option><option value="text/x-yaml" mode="yaml">YAML</option><option value="text/x-z80" mode="z80">Z80</option></select> |
|
609 | 607 | <script> |
|
610 | 608 | $(document).ready(function() { |
|
611 | 609 | $('#mimetype').select2({ |
|
612 | 610 | containerCssClass: 'drop-menu', |
|
613 | 611 | dropdownCssClass: 'drop-menu-dropdown', |
|
614 | 612 | dropdownAutoWidth: true |
|
615 | 613 | }); |
|
616 | 614 | }); |
|
617 | 615 | </script> |
|
618 | 616 | |
|
619 | 617 | </div> |
|
620 | 618 | </div> |
|
621 | 619 | </div> |
|
622 | 620 | <div id="editor_container"> |
|
623 | 621 | <div id="editor_pre"></div> |
|
624 | 622 | <textarea id="editor" name="content" style="display: none;"></textarea><div class="CodeMirror cm-s-default"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 484px; left: 219.4091796875px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea></div><div class="CodeMirror-hscrollbar" style="left: 29px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="min-width: 18px; display: block; bottom: 0px;"><div style="min-width: 1px; height: 619px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="min-width: 700.269653320313px; margin-left: 29px; min-height: 619px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"><div class="CodeMirror-linenumber CodeMirror-gutter-elt"><div>47</div></div></div><div style="position: relative; z-index: 1; display: none;"></div><div class="CodeMirror-code"><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">1</div></div><pre><span class="cm-keyword">import</span> <span class="cm-variable">re</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">2</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">3</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">django</span>.<span class="cm-variable">utils</span>.<span class="cm-variable">text</span> <span class="cm-keyword">import</span> <span class="cm-variable">compress_sequence</span>, <span class="cm-variable">compress_string</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">4</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">django</span>.<span class="cm-variable">utils</span>.<span class="cm-variable">cache</span> <span class="cm-keyword">import</span> <span class="cm-variable">patch_vary_headers</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">5</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">6</div></div><pre><span class="cm-variable">re_accepts_gzip</span> = <span class="cm-variable">re</span>.<span class="cm-builtin">compile</span>(<span class="cm-string">r'\bgzip\b'</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">7</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">8</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">9</div></div><pre><span class="cm-keyword">class</span> <span class="cm-def">GZipMiddleware</span>(<span class="cm-builtin">object</span>): # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">10</div></div><pre> <span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">11</div></div><pre><span class="cm-string"> This middleware compresses content if the browser allows gzip compression.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">12</div></div><pre><span class="cm-string"> It sets the Vary header accordingly, so that caches will base their storage</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">13</div></div><pre><span class="cm-string"> on the Accept-Encoding header.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">14</div></div><pre><span class="cm-string"> """</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">15</div></div><pre> <span class="cm-keyword">def</span> <span class="cm-def">process_response</span>(<span class="cm-variable-2">self</span>, <span class="cm-variable">request</span>, <span class="cm-variable">response</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">16</div></div><pre> <span class="cm-comment"># It's not worth attempting to compress really short responses.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">17</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-operator">not</span> <span class="cm-variable">response</span>.<span class="cm-variable">streaming</span> <span class="cm-operator">and</span> <span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>) <span class="cm-operator"><</span> <span class="cm-number">200</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">18</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">19</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">20</div></div><pre> <span class="cm-comment"># Avoid gzipping if we've already got a content-encoding.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">21</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">has_header</span>(<span class="cm-string">'Content-Encoding'</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">22</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">23</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">24</div></div><pre> <span class="cm-variable">patch_vary_headers</span>(<span class="cm-variable">response</span>, (<span class="cm-string">'Accept-Encoding'</span>,))</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">25</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">26</div></div><pre> <span class="cm-variable">ae</span> = <span class="cm-variable">request</span>.<span class="cm-variable">META</span>.<span class="cm-variable">get</span>(<span class="cm-string">'HTTP_ACCEPT_ENCODING'</span>, <span class="cm-string">''</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">27</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-operator">not</span> <span class="cm-variable">re_accepts_gzip</span>.<span class="cm-variable">search</span>(<span class="cm-variable">ae</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">28</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">29</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">30</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">streaming</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">31</div></div><pre> <span class="cm-comment"># Delete the `Content-Length` header for streaming content, because</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">32</div></div><pre> <span class="cm-comment"># we won't know the compressed size until we stream it.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">33</div></div><pre> <span class="cm-variable">response</span>.<span class="cm-variable">streaming_content</span> = <span class="cm-variable">compress_sequence</span>(<span class="cm-variable">response</span>.<span class="cm-variable">streaming_content</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">34</div></div><pre> <span class="cm-keyword">del</span> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Length'</span>]</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">35</div></div><pre> <span class="cm-keyword">else</span>:</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">36</div></div><pre> <span class="cm-comment"># Return the compressed content only if it's actually shorter.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">37</div></div><pre> <span class="cm-variable">compressed_content</span> = <span class="cm-variable">compress_string</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">38</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-builtin">len</span>(<span class="cm-variable">compressed_content</span>) <span class="cm-operator">>=</span> <span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">39</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">40</div></div><pre> <span class="cm-variable">response</span>.<span class="cm-variable">content</span> = <span class="cm-variable">compressed_content</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">41</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Length'</span>] = <span class="cm-builtin">str</span>(<span class="cm-builtin">len</span>(<span class="cm-variable">response</span>.<span class="cm-variable">content</span>))</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">42</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">43</div></div><pre> <span class="cm-keyword">if</span> <span class="cm-variable">response</span>.<span class="cm-variable">has_header</span>(<span class="cm-string">'ETag'</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">44</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'ETag'</span>] = <span class="cm-variable">re</span>.<span class="cm-variable">sub</span>(<span class="cm-string">'"$'</span>, <span class="cm-string">';gzip"'</span>, <span class="cm-variable">response</span>[<span class="cm-string">'ETag'</span>])</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">45</div></div><pre> <span class="cm-variable">response</span>[<span class="cm-string">'Content-Encoding'</span>] = <span class="cm-string">'gzip'</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">46</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">47</div></div><pre> <span class="cm-keyword">return</span> <span class="cm-variable">response</span></pre></div></div><div class="CodeMirror-cursor" style="left: 189.4091796875px; top: 598px; height: 13px;"> </div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;"> </div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 619px;"></div><div class="CodeMirror-gutters" style="height: 619px;"><div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 28px;"></div></div></div></div> |
|
625 | 623 | </div> |
|
626 | 624 | </div> |
|
627 | 625 | |
|
628 | 626 | |
|
629 | 627 | |
|
630 | 628 | |
|
631 | 629 | |
|
632 | 630 | <!-- |
|
633 | 631 | File Edit |
|
634 | 632 | --> |
|
635 | 633 | |
|
636 | 634 | <h2>File Edit</h2> |
|
637 | 635 | |
|
638 | 636 | <div class="codeblock"> |
|
639 | 637 | <div class="code-header"> |
|
640 | 638 | <div class="stats"> |
|
641 | 639 | <i class="icon-file"></i> |
|
642 | 640 | <span class="item"><a href="/example/changeset/80ead1899f50a894889e19ffeb49c9cebf5bf045">r8248:80ead1899f50</a></span> |
|
643 | 641 | <span class="item">1.2 KiB</span> |
|
644 | 642 | <span class="item last">text/x-python</span> |
|
645 | 643 | <div class="buttons"> |
|
646 | 644 | <a class="btn btn-mini" href="/example/changelog/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py"> |
|
647 | 645 | <i class="icon-time"></i> history |
|
648 | 646 | </a> |
|
649 | 647 | |
|
650 | 648 | <a class="btn btn-mini" href="/example/files/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">source</a> |
|
651 | 649 | <a class="btn btn-mini" href="/example/raw/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">raw</a> |
|
652 | 650 | <a class="btn btn-mini" href="/example/rawfile/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py"> |
|
653 | 651 | <i class="icon-archive"></i> download |
|
654 | 652 | </a> |
|
655 | 653 | </div> |
|
656 | 654 | </div> |
|
657 | 655 | <div class="form"> |
|
658 | 656 | <label for="set_mode">Editing file:</label> |
|
659 | 657 | rhodecode / |
|
660 | 658 | <input type="text" name="filename" value="websetup.py"> |
|
661 | 659 | |
|
662 | 660 | <div class="select2-container drop-menu" id="s2id_set_mode"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-2">plain</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen2" class="select2-offscreen">Editing file:</label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-2" id="s2id_autogen2"><div class="select2-drop select2-display-none drop-menu-dropdown select2-with-searchbox"> <div class="select2-search"> <label for="s2id_autogen2_search" class="select2-offscreen">Editing file:</label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-2" id="s2id_autogen2_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-2"> </ul></div></div><select id="set_mode" name="set_mode" tabindex="-1" title="Editing file:" style="display: none;"> |
|
663 | 661 | <option selected="selected" value="plain">plain</option> |
|
664 | 662 | <option value="apl">APL</option><option value="asterisk">Asterisk</option><option value="clike">C</option><option value="clike">C++</option><option value="cobol">Cobol</option><option value="clike">Java</option><option value="clike">C#</option><option value="clike">Scala</option><option value="clojure">Clojure</option><option value="coffeescript">CoffeeScript</option><option value="commonlisp">Common Lisp</option><option value="css">CSS</option><option value="d">D</option><option value="diff">diff</option><option value="dtd">DTD</option><option value="dylan">Dylan</option><option value="ecl">ECL</option><option value="eiffel">Eiffel</option><option value="erlang">Erlang</option><option value="fortran">Fortran</option><option value="mllike">F#</option><option value="gas">Gas</option><option value="go">GO</option><option value="gherkin">Gherkin</option><option value="go">Go</option><option value="groovy">Groovy</option><option value="haml">HAML</option><option value="haskell">Haskell</option><option value="haxe">Haxe</option><option value="htmlembedded">ASP.NET</option><option value="htmlembedded">Embedded Javascript</option><option value="htmlembedded">JavaServer Pages</option><option value="htmlmixed">HTML</option><option value="http">HTTP</option><option value="jade">Jade</option><option value="javascript">JavaScript</option><option value="javascript">JSON</option><option value="javascript">TypeScript</option><option value="jinja2">Jinja2</option><option value="julia">Julia</option><option value="less">LESS</option><option value="livescript">LiveScript</option><option value="lua">Lua</option><option value="markdown">Markdown (GitHub-flavour)</option><option value="mirc">mIRC</option><option value="nginx">Nginx</option><option value="ntriples">NTriples</option><option value="ocaml">OCaml</option><option value="mllike">OCaml</option><option value="octave">Octave</option><option value="pascal">Pascal</option><option value="pegjs">PEG.js</option><option value="perl">Perl</option><option value="php">PHP</option><option value="pig">Pig</option><option value="null">Plain Text</option><option value="properties">Properties files</option><option value="python" selected="selected">Python</option><option value="puppet">Puppet</option><option value="r">R</option><option value="rst">reStructuredText</option><option value="ruby">Ruby</option><option value="rust">Rust</option><option value="sass">Sass</option><option value="scheme">Scheme</option><option value="css">SCSS</option><option value="shell">Shell</option><option value="sieve">Sieve</option><option value="smalltalk">Smalltalk</option><option value="smarty">Smarty</option><option value="smartymixed">SmartyMixed</option><option value="solr">Solr</option><option value="sparql">SPARQL</option><option value="sql">SQL</option><option value="sql">MariaDB</option><option value="stex">sTeX</option><option value="stex">LaTeX</option><option value="verilog">SystemVerilog</option><option value="tcl">Tcl</option><option value="tiddlywiki">TiddlyWiki </option><option value="tiki">Tiki wiki</option><option value="toml">TOML</option><option value="turtle">Turtle</option><option value="vb">VB.NET</option><option value="vbscript">VBScript</option><option value="velocity">Velocity</option><option value="verilog">Verilog</option><option value="xml">XML</option><option value="xml">HTML</option><option value="xquery">XQuery</option><option value="yaml">YAML</option><option value="z80">Z80</option></select> |
|
665 | 663 | <script> |
|
666 | 664 | $(document).ready(function() { |
|
667 | 665 | $('#set_mode').select2({ |
|
668 | 666 | containerCssClass: 'drop-menu', |
|
669 | 667 | dropdownCssClass: 'drop-menu-dropdown', |
|
670 | 668 | dropdownAutoWidth: true |
|
671 | 669 | }); |
|
672 | 670 | }); |
|
673 | 671 | </script> |
|
674 | 672 | |
|
675 | 673 | <label for="line_wrap">line wraps</label> |
|
676 | 674 | <div class="select2-container drop-menu" id="s2id_line_wrap"><a href="javascript:void(0)" class="select2-choice" tabindex="-1"> <span class="select2-chosen" id="select2-chosen-3">off</span><abbr class="select2-search-choice-close"></abbr> <span class="select2-arrow" role="presentation"><b role="presentation"></b></span></a><label for="s2id_autogen3" class="select2-offscreen">line wraps</label><input class="select2-focusser select2-offscreen" type="text" aria-haspopup="true" role="button" aria-labelledby="select2-chosen-3" id="s2id_autogen3"><div class="select2-drop select2-display-none drop-menu-dropdown"> <div class="select2-search select2-search-hidden select2-offscreen"> <label for="s2id_autogen3_search" class="select2-offscreen">line wraps</label> <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" role="combobox" aria-expanded="true" aria-autocomplete="list" aria-owns="select2-results-3" id="s2id_autogen3_search" placeholder=""> </div> <ul class="select2-results" role="listbox" id="select2-results-3"> </ul></div></div><select id="line_wrap" name="line_wrap" tabindex="-1" title="line wraps" style="display: none;"> |
|
677 | 675 | <option value="on">on</option> |
|
678 | 676 | <option selected="selected" value="off">off</option> |
|
679 | 677 | </select> |
|
680 | 678 | <script> |
|
681 | 679 | $(document).ready(function() { |
|
682 | 680 | $('#line_wrap').select2({ |
|
683 | 681 | containerCssClass: 'drop-menu', |
|
684 | 682 | dropdownCssClass: 'drop-menu-dropdown', |
|
685 | 683 | dropdownAutoWidth: true, |
|
686 | 684 | minimumResultsForSearch: -1 |
|
687 | 685 | |
|
688 | 686 | }); |
|
689 | 687 | }); |
|
690 | 688 | </script> |
|
691 | 689 | |
|
692 | 690 | <div id="render_preview" class="btn btn-mini hidden disabled">Preview</div> |
|
693 | 691 | </div> |
|
694 | 692 | </div> |
|
695 | 693 | <div id="editor_container"> |
|
696 | 694 | <pre id="editor_pre"></pre> |
|
697 | 695 | <textarea id="editor" name="content" style="display: none;"># -*- coding: utf-8 -*- |
|
698 | 696 | |
|
699 | 697 | # Published under Commercial License. |
|
700 | 698 | # Read the full license text at https://rhodecode.com/licenses. |
|
701 | 699 | """ |
|
702 | 700 | rhodecode.websetup |
|
703 | 701 | ~~~~~~~~~~~~~~~~~~ |
|
704 | 702 | |
|
705 | 703 | Weboperations and setup for rhodecode |
|
706 | 704 | |
|
707 | 705 | :created_on: Dec 11, 2010 |
|
708 | 706 | :author: marcink |
|
709 | 707 | :copyright: (c) 2013-2015 RhodeCode GmbH. |
|
710 | 708 | :license: Commercial License, see LICENSE for more details. |
|
711 | 709 | """ |
|
712 | 710 | |
|
713 | 711 | import logging |
|
714 | 712 | |
|
715 | 713 | from rhodecode.config.environment import load_environment |
|
716 | 714 | from rhodecode.lib.db_manage import DbManage |
|
717 | 715 | from rhodecode.model.meta import Session |
|
718 | 716 | |
|
719 | 717 | |
|
720 | 718 | log = logging.getLogger(__name__) |
|
721 | 719 | |
|
722 | 720 | |
|
723 | 721 | def setup_app(command, conf, vars): |
|
724 | 722 | """Place any commands to setup rhodecode here""" |
|
725 | 723 | dbconf = conf['sqlalchemy.db1.url'] |
|
726 | 724 | dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'], |
|
727 | 725 | tests=False, cli_args=command.options.__dict__) |
|
728 | 726 | dbmanage.create_tables(override=True) |
|
729 | 727 | dbmanage.set_db_version() |
|
730 | 728 | opts = dbmanage.config_prompt(None) |
|
731 | 729 | dbmanage.create_settings(opts) |
|
732 | 730 | dbmanage.create_default_user() |
|
733 | 731 | dbmanage.admin_prompt() |
|
734 | 732 | dbmanage.create_permissions() |
|
735 | 733 | dbmanage.populate_default_permissions() |
|
736 | 734 | Session().commit() |
|
737 | 735 | load_environment(conf.global_conf, conf.local_conf, initial=True) |
|
738 | 736 | </textarea><div class="CodeMirror cm-s-default CodeMirror-focused"><div style="overflow: hidden; position: relative; width: 3px; height: 0px; top: 5px; left: 34px;"><textarea autocorrect="off" autocapitalize="off" spellcheck="false" style="position: absolute; padding: 0px; width: 1000px; height: 1em; outline: none;" tabindex="0"></textarea></div><div class="CodeMirror-hscrollbar" style="left: 29px; min-height: 18px;"><div style="height: 100%; min-height: 1px; width: 0px;"></div></div><div class="CodeMirror-vscrollbar" style="display: block; bottom: 0px; min-width: 18px;"><div style="min-width: 1px; height: 554px;"></div></div><div class="CodeMirror-scrollbar-filler"></div><div class="CodeMirror-gutter-filler"></div><div class="CodeMirror-scroll" tabindex="-1"><div class="CodeMirror-sizer" style="min-width: 579.350463867188px; margin-left: 29px; min-height: 554px;"><div style="position: relative; top: 0px;"><div class="CodeMirror-lines"><div style="position: relative; outline: none;"><div class="CodeMirror-measure"><div style="width: 50px; height: 50px; overflow-x: scroll;"></div></div><div style="position: relative; z-index: 1; display: none;"></div><div class="CodeMirror-code"><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">1</div></div><pre><span class="cm-comment"># -*- coding: utf-8 -*-</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">2</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">3</div></div><pre><span class="cm-comment"># Published under Commercial License.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">4</div></div><pre><span class="cm-comment"># Read the full license text at https://rhodecode.com/licenses.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">5</div></div><pre><span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">6</div></div><pre><span class="cm-string">rhodecode.websetup</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">7</div></div><pre><span class="cm-string">~~~~~~~~~~~~~~~~~~</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">8</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">9</div></div><pre><span class="cm-string">Weboperations and setup for rhodecode</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">10</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">11</div></div><pre><span class="cm-string">:created_on: Dec 11, 2010</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">12</div></div><pre><span class="cm-string">:author: marcink</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">13</div></div><pre><span class="cm-string">:copyright: (c) 2013-2015 RhodeCode GmbH.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">14</div></div><pre><span class="cm-string">:license: Commercial License, see LICENSE for more details.</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">15</div></div><pre><span class="cm-string">"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">16</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">17</div></div><pre><span class="cm-keyword">import</span> <span class="cm-variable">logging</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">18</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">19</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">config</span>.<span class="cm-variable">environment</span> <span class="cm-keyword">import</span> <span class="cm-variable">load_environment</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">20</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">lib</span>.<span class="cm-variable">db_manage</span> <span class="cm-keyword">import</span> <span class="cm-variable">DbManage</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">21</div></div><pre><span class="cm-keyword">from</span> <span class="cm-variable">rhodecode</span>.<span class="cm-variable">model</span>.<span class="cm-variable">meta</span> <span class="cm-keyword">import</span> <span class="cm-variable">Session</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">22</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">23</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">24</div></div><pre><span class="cm-variable">log</span> = <span class="cm-variable">logging</span>.<span class="cm-variable">getLogger</span>(<span class="cm-variable">__name__</span>) # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it.</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">25</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">26</div></div><pre> </pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">27</div></div><pre><span class="cm-keyword">def</span> <span class="cm-def">setup_app</span>(<span class="cm-variable">command</span>, <span class="cm-variable">conf</span>, <span class="cm-builtin">vars</span>):</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">28</div></div><pre> <span class="cm-string">"""Place any commands to setup rhodecode here"""</span></pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">29</div></div><pre> <span class="cm-variable">dbconf</span> = <span class="cm-variable">conf</span>[<span class="cm-string">'sqlalchemy.db1.url'</span>]</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">30</div></div><pre> <span class="cm-variable">dbmanage</span> = <span class="cm-variable">DbManage</span>(<span class="cm-variable">log_sql</span>=<span class="cm-builtin">True</span>, <span class="cm-variable">dbconf</span>=<span class="cm-variable">dbconf</span>, <span class="cm-variable">root</span>=<span class="cm-variable">conf</span>[<span class="cm-string">'here'</span>],</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">31</div></div><pre> <span class="cm-variable">tests</span>=<span class="cm-builtin">False</span>, <span class="cm-variable">cli_args</span>=<span class="cm-variable">command</span>.<span class="cm-variable">options</span>.<span class="cm-variable">__dict__</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">32</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_tables</span>(<span class="cm-variable">override</span>=<span class="cm-builtin">True</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">33</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">set_db_version</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">34</div></div><pre> <span class="cm-variable">opts</span> = <span class="cm-variable">dbmanage</span>.<span class="cm-variable">config_prompt</span>(<span class="cm-builtin">None</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">35</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_settings</span>(<span class="cm-variable">opts</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">36</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_default_user</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">37</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">admin_prompt</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">38</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">create_permissions</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">39</div></div><pre> <span class="cm-variable">dbmanage</span>.<span class="cm-variable">populate_default_permissions</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">40</div></div><pre> <span class="cm-variable">Session</span>().<span class="cm-variable">commit</span>()</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">41</div></div><pre> <span class="cm-variable">load_environment</span>(<span class="cm-variable">conf</span>.<span class="cm-variable">global_conf</span>, <span class="cm-variable">conf</span>.<span class="cm-variable">local_conf</span>, <span class="cm-variable">initial</span>=<span class="cm-builtin">True</span>)</pre></div><div style="position: relative;"><div class="CodeMirror-gutter-wrapper" style="position: absolute; left: -29px;"><div class="CodeMirror-linenumber CodeMirror-gutter-elt" style="left: 0px; width: 20px;">42</div></div><pre> </pre></div></div><div class="CodeMirror-cursor" style="left: 4px; top: 0px; height: 13px;"> </div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;"> </div></div></div></div></div><div style="position: absolute; height: 30px; width: 1px; top: 554px;"></div><div class="CodeMirror-gutters" style="height: 554px;"><div class="CodeMirror-gutter CodeMirror-linenumbers" style="width: 28px;"></div></div></div></div> |
|
739 | 737 | <div id="editor_preview"></div> |
|
740 | 738 | </div> |
|
741 | 739 | <div class="message"> |
|
742 | 740 | <label class="codeblock-label">Commit Message</label> |
|
743 | 741 | <textarea id="commit" name="message" placeholder="Edited file rhodecode/websetup.py via RhodeCode"></textarea> |
|
744 | 742 | </div> |
|
745 | 743 | </div> |
|
746 | 744 | |
|
747 | 745 | |
|
748 | 746 | |
|
749 | 747 | |
|
750 | 748 | |
|
751 | 749 | |
|
752 | 750 | <!-- |
|
753 | 751 | Commit with comments |
|
754 | 752 | --> |
|
755 | 753 | |
|
756 | 754 | <h2>Commit with comments</h2> |
|
757 | 755 | |
|
758 | 756 | <div class="diff-container" id="diff-container-140360037209920"> |
|
759 | 757 | <div id="c-4e5ee86997c6-7046e4320b26_target"></div> |
|
760 | 758 | <div id="c-4e5ee86997c6-7046e4320b26" class="diffblock margined comm"> |
|
761 | 759 | <div class="code-header"> |
|
762 | 760 | <div title="Go back to changed files overview"> |
|
763 | 761 | <a href="#changes_box"> |
|
764 | 762 | <i class="icon-circle-arrow-up"></i> |
|
765 | 763 | </a> |
|
766 | 764 | </div> |
|
767 | 765 | <div class="changeset_header"> |
|
768 | 766 | <div class="changeset_file"> |
|
769 | 767 | <i class="icon-file"></i> |
|
770 | 768 | <a href="/andersonsantos/rhodecode-dev-fork/files/4e5ee86997c64981d85cf62283af448624e26929/rhodecode/tests/functional/test_compare_local.py">rhodecode/tests/functional/test_compare_local.py</a> |
|
771 | 769 | </div> |
|
772 | 770 | <div class="diff-actions"> |
|
773 | 771 | <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&diff=diff&diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full diff for this file"> |
|
774 | 772 | <img class="icon" src="/images/icons/page_white_go.png"> |
|
775 | 773 | </a> |
|
776 | 774 | <a href="/andersonsantos/rhodecode-dev-fork/diff-2way/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&diff=diff&diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full side-by-side diff for this file"> |
|
777 | 775 | <img class="icon" src="/images/icons/application_double.png"> |
|
778 | 776 | </a> |
|
779 | 777 | <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&diff=raw&diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Raw diff"> |
|
780 | 778 | <img class="icon" src="/images/icons/page_white.png"> |
|
781 | 779 | </a> |
|
782 | 780 | <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&diff=download&diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Download diff"> |
|
783 | 781 | <img class="icon" src="/images/icons/page_save.png"> |
|
784 | 782 | </a> |
|
785 | 783 | <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=WS%3A1&c-4e5ee86997c6-7046e4320b26=C%3A3#c-4e5ee86997c6-7046e4320b26" title="Ignore white space"><img alt="Ignore white space" class="icon" src="/images/icons/text_strikethrough.png"></a> |
|
786 | 784 | <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=C%3A6#c-4e5ee86997c6-7046e4320b26" title="increase diff context to 6 lines"><img alt="increase diff context to 6 lines" class="icon" src="/images/icons/table_add.png"></a> |
|
787 | 785 | </div> |
|
788 | 786 | <span> |
|
789 | 787 | <label> |
|
790 | 788 | Show inline comments |
|
791 | 789 | <input checked="checked" class="show-inline-comments" id="" id_for="c-4e5ee86997c6-7046e4320b26" name="" type="checkbox" value="1"> |
|
792 | 790 | </label> |
|
793 | 791 | </span> |
|
794 | 792 | </div> |
|
795 | 793 | </div> |
|
796 | 794 | <div class="code-body"> |
|
797 | 795 | <div class="full_f_path" path="rhodecode/tests/functional/test_compare_local.py"></div> |
|
798 | 796 | <table class="code-difftable"> |
|
799 | 797 | <tbody><tr class="line context"> |
|
800 | 798 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td> |
|
801 | 799 | <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td> |
|
802 | 800 | <td class="code "> |
|
803 | 801 | <pre>@@ -59,7 +59,7 @@ |
|
804 | 802 | </pre> |
|
805 | 803 | </td> |
|
806 | 804 | </tr> |
|
807 | 805 | <tr class="line unmod"> |
|
808 | 806 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o59" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o59">59</a></td> |
|
809 | 807 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n59" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n59">59</a></td> |
|
810 | 808 | <td class="code "> |
|
811 | 809 | <pre> 'tag': 'v0.2.0', |
|
812 | 810 | </pre> |
|
813 | 811 | </td> |
|
814 | 812 | </tr> |
|
815 | 813 | <tr class="line unmod"> |
|
816 | 814 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o60" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o60">60</a></td> |
|
817 | 815 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n60" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n60">60</a></td> |
|
818 | 816 | <td class="code "> |
|
819 | 817 | <pre> 'branch': 'default', |
|
820 | 818 | </pre> |
|
821 | 819 | </td> |
|
822 | 820 | </tr> |
|
823 | 821 | <tr class="line unmod"> |
|
824 | 822 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o61" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o61">61</a></td> |
|
825 | 823 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n61" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n61">61</a></td> |
|
826 | 824 | <td class="code "> |
|
827 | 825 | <pre> 'response': # Intentionally long line to show what will happen if this line does not fit onto the screen. It might have some horizontal scrolling applied or some other fancy mechanism to deal with it. |
|
828 | 826 | </pre> |
|
829 | 827 | </td> |
|
830 | 828 | </tr> |
|
831 | 829 | <tr class="line del"> |
|
832 | 830 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o62" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o62">62</a></td> |
|
833 | 831 | <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td> |
|
834 | 832 | <td class="code "> |
|
835 | 833 | <pre> '147 files changed: 5700 inserted, 10176 deleted' |
|
836 | 834 | </pre> |
|
837 | 835 | </td> |
|
838 | 836 | </tr> |
|
839 | 837 | <tr class="line add"> |
|
840 | 838 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td> |
|
841 | 839 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n62" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n62">62</a></td> |
|
842 | 840 | <td class="code "> |
|
843 | 841 | <pre><ins> </ins> '147 files changed: 5700 inserted, 10176 deleted' |
|
844 | 842 | </pre> |
|
845 | 843 | </td> |
|
846 | 844 | </tr> |
|
847 | 845 | <tr class="line unmod"> |
|
848 | 846 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o63" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o63">63</a></td> |
|
849 | 847 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n63" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n63">63</a></td> |
|
850 | 848 | <td class="code "> |
|
851 | 849 | <pre> }, |
|
852 | 850 | </pre> |
|
853 | 851 | </td> |
|
854 | 852 | </tr> |
|
855 | 853 | <tr class="line unmod"> |
|
856 | 854 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o64" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o64">64</a></td> |
|
857 | 855 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n64" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n64">64</a></td> |
|
858 | 856 | <td class="code "> |
|
859 | 857 | <pre> 'git': { |
|
860 | 858 | </pre> |
|
861 | 859 | </td> |
|
862 | 860 | </tr> |
|
863 | 861 | <tr class="line unmod"> |
|
864 | 862 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o65" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o65">65</a></td> |
|
865 | 863 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n65" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n65">65</a></td> |
|
866 | 864 | <td class="code "> |
|
867 | 865 | <pre> 'tag': 'v0.2.2', |
|
868 | 866 | </pre> |
|
869 | 867 | </td> |
|
870 | 868 | </tr> |
|
871 | 869 | <tr class="line context"> |
|
872 | 870 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td> |
|
873 | 871 | <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td> |
|
874 | 872 | <td class="code "> |
|
875 | 873 | <pre>@@ -77,9 +77,11 @@ |
|
876 | 874 | </pre> |
|
877 | 875 | </td> |
|
878 | 876 | </tr> |
|
879 | 877 | <tr class="line unmod"> |
|
880 | 878 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o77" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o77">77</a></td> |
|
881 | 879 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n77" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n77">77</a></td> |
|
882 | 880 | <td class="code "> |
|
883 | 881 | <pre> target_ref=revisions[backend.alias]['tag'], |
|
884 | 882 | </pre> |
|
885 | 883 | </td> |
|
886 | 884 | </tr> |
|
887 | 885 | <tr class="line unmod"> |
|
888 | 886 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o78" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o78">78</a></td> |
|
889 | 887 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n78" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n78">78</a></td> |
|
890 | 888 | <td class="code "> |
|
891 | 889 | <pre> )) |
|
892 | 890 | </pre> |
|
893 | 891 | </td> |
|
894 | 892 | </tr><tr id="comment-tr-3754" class="inline-comments"><td></td><td></td><td> |
|
895 | 893 | |
|
896 | 894 | <div class="comment" id="comment-3754" line="n78"> |
|
897 | 895 | <div class="comment-wrapp"> |
|
898 | 896 | <div class="meta"> |
|
899 | 897 | <span class="gravatar"> |
|
900 | 898 | <img src="https://secure.gravatar.com/avatar/72706ebd30734451af9ff3fb59f05ff1?d=identicon&s=40" height="20" width="20"> |
|
901 | 899 | </span> |
|
902 | 900 | <span class="user"> |
|
903 | 901 | anderson |
|
904 | 902 | </span> |
|
905 | 903 | <span class="date"> |
|
906 | 904 | just now | |
|
907 | 905 | </span> |
|
908 | 906 | <span class="status-change"> |
|
909 | 907 | Comment on commit |
|
910 | 908 | </span> |
|
911 | 909 | <a class="permalink" href="#comment-3754">¶</a> |
|
912 | 910 | </div> |
|
913 | 911 | <div class="text"> |
|
914 | 912 | <div class="rst-block"><p>commented line |
|
915 | 913 | with multiple lines</p> |
|
916 | 914 | </div> |
|
917 | 915 | </div> |
|
918 | 916 | </div> |
|
919 | 917 | </div><div class="add-comment"><span class="btn btn-default">Add another comment</span></div> |
|
920 | 918 | |
|
921 | 919 | </td></tr> |
|
922 | 920 | <tr class="line unmod"> |
|
923 | 921 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o79" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o79">79</a></td> |
|
924 | 922 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n79" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n79">79</a></td> |
|
925 | 923 | <td class="code "> |
|
926 | 924 | <pre></pre> |
|
927 | 925 | </td> |
|
928 | 926 | </tr> |
|
929 | 927 | <tr class="line del form-open hl-comment"> |
|
930 | 928 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o80" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o80">80</a></td> |
|
931 | 929 | <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td> |
|
932 | 930 | <td class="code "> |
|
933 | 931 | <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del> |
|
934 | 932 | </pre> |
|
935 | 933 | </td> |
|
936 | 934 | </tr><tr id="comment-tr-undefined" class="comment-form-inline"><td></td><td></td><td> |
|
937 | 935 | <div class="comment-inline-form ac"> |
|
938 | 936 | <div class="overlay"><div class="overlay-text">Submitting...</div></div> |
|
939 | 937 | <form action="#" class="inline-form" method="get"> |
|
940 | 938 | <div id="edit-container_o80" class="clearfix"> |
|
941 | 939 | <div class="comment-title pull-left"> |
|
942 | 940 | Commenting on line o80. |
|
943 | 941 | </div> |
|
944 | 942 | <div class="comment-help pull-right"> |
|
945 | 943 | Comments parsed using <a href="http://docutils.sourceforge.net/docs/user/rst/quickref.html">RST</a> syntax with <span class="tooltip" title="Use @username inside this text to send notification to this RhodeCode user">@mention</span> support. |
|
946 | 944 | </div> |
|
947 | 945 | <div style="clear: both"></div> |
|
948 | 946 | <textarea id="text_o80" name="text" class="comment-block-ta ac-input" autocomplete="off"></textarea> |
|
949 | 947 | </div> |
|
950 | 948 | <div id="preview-container_o80" class="clearfix" style="display: none;"> |
|
951 | 949 | <div class="comment-help"> |
|
952 | 950 | Comment preview |
|
953 | 951 | </div> |
|
954 | 952 | <div id="preview-box_o80" class="preview-box"></div> |
|
955 | 953 | </div> |
|
956 | 954 | <div class="comment-button pull-right"> |
|
957 | 955 | <input type="hidden" name="f_path" value="rhodecode/tests/functional/test_compare_local.py"> |
|
958 | 956 | <input type="hidden" name="line" value="o80"> |
|
959 | 957 | <div id="preview-btn_o80" class="btn btn-default">Preview</div> |
|
960 | 958 | <div id="edit-btn_o80" class="btn" style="display: none;">Edit</div> |
|
961 | 959 | <input class="btn btn-success save-inline-form" id="save" name="save" type="submit" value="Comment"> |
|
962 | 960 | </div> |
|
963 | 961 | <div class="comment-button hide-inline-form-button"> |
|
964 | 962 | <input class="btn hide-inline-form" id="hide-inline-form" name="hide-inline-form" type="reset" value="Cancel"> |
|
965 | 963 | </div> |
|
966 | 964 | </form> |
|
967 | 965 | </div> |
|
968 | 966 | </td></tr> |
|
969 | 967 | <tr class="line add"> |
|
970 | 968 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td> |
|
971 | 969 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n80" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n80">80</a></td> |
|
972 | 970 | <td class="code "> |
|
973 | 971 | <pre> response.mustcontain('%s@%s' % ( |
|
974 | 972 | </pre> |
|
975 | 973 | </td> |
|
976 | 974 | </tr> |
|
977 | 975 | <tr class="line add"> |
|
978 | 976 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td> |
|
979 | 977 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n81" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n81">81</a></td> |
|
980 | 978 | <td class="code "> |
|
981 | 979 | <pre> backend.repo_name, |
|
982 | 980 | </pre> |
|
983 | 981 | </td> |
|
984 | 982 | </tr> |
|
985 | 983 | <tr class="line unmod"> |
|
986 | 984 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o81" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o81">81</a></td> |
|
987 | 985 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n82" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n82">82</a></td> |
|
988 | 986 | <td class="code "> |
|
989 | 987 | <pre> revisions[backend.alias]['branch'])) |
|
990 | 988 | </pre> |
|
991 | 989 | </td> |
|
992 | 990 | </tr> |
|
993 | 991 | <tr class="line del"> |
|
994 | 992 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o82" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o82">82</a></td> |
|
995 | 993 | <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td> |
|
996 | 994 | <td class="code "> |
|
997 | 995 | <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del> |
|
998 | 996 | </pre> |
|
999 | 997 | </td> |
|
1000 | 998 | </tr> |
|
1001 | 999 | <tr class="line add"> |
|
1002 | 1000 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td> |
|
1003 | 1001 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n83" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n83">83</a></td> |
|
1004 | 1002 | <td class="code "> |
|
1005 | 1003 | <pre> response.mustcontain('%s@%s' % ( |
|
1006 | 1004 | </pre> |
|
1007 | 1005 | </td> |
|
1008 | 1006 | </tr> |
|
1009 | 1007 | <tr class="line add"> |
|
1010 | 1008 | <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td> |
|
1011 | 1009 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n84" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n84">84</a></td> |
|
1012 | 1010 | <td class="code "> |
|
1013 | 1011 | <pre> backend.repo_name, |
|
1014 | 1012 | </pre> |
|
1015 | 1013 | </td> |
|
1016 | 1014 | </tr> |
|
1017 | 1015 | <tr class="line unmod"> |
|
1018 | 1016 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o83" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o83">83</a></td> |
|
1019 | 1017 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n85" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n85">85</a></td> |
|
1020 | 1018 | <td class="code "> |
|
1021 | 1019 | <pre> revisions[backend.alias]['tag'])) |
|
1022 | 1020 | </pre> |
|
1023 | 1021 | </td> |
|
1024 | 1022 | </tr> |
|
1025 | 1023 | <tr class="line unmod"> |
|
1026 | 1024 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o84" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o84">84</a></td> |
|
1027 | 1025 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n86" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n86">86</a></td> |
|
1028 | 1026 | <td class="code "> |
|
1029 | 1027 | <pre> response.mustcontain(revisions[backend.alias]['response']) |
|
1030 | 1028 | </pre> |
|
1031 | 1029 | </td> |
|
1032 | 1030 | </tr> |
|
1033 | 1031 | <tr class="line unmod"> |
|
1034 | 1032 | <td id="rhodecodetestsfunctionaltest_compare_localpy_o85" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o85">85</a></td> |
|
1035 | 1033 | <td id="rhodecodetestsfunctionaltest_compare_localpy_n87" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n87">87</a></td> |
|
1036 | 1034 | <td class="code "> |
|
1037 | 1035 | <pre></pre> |
|
1038 | 1036 | </td> |
|
1039 | 1037 | </tr> |
|
1040 | 1038 | </tbody></table> |
|
1041 | 1039 | </div> |
|
1042 | 1040 | </div> |
|
1043 | 1041 | </div> |
|
1044 | 1042 | |
|
1045 | 1043 | |
|
1046 | 1044 | |
|
1047 | 1045 | <!-- |
|
1048 | 1046 | Side-by-side diff |
|
1049 | 1047 | --> |
|
1050 | 1048 | |
|
1051 | 1049 | <h2>Side-by-side diff</h2> |
|
1052 | 1050 | |
|
1053 | 1051 | <div class="box"> |
|
1054 | 1052 | <div class="diff-container" style="overflow-x: hidden"> |
|
1055 | 1053 | <div class="diffblock comm" style="margin:3px; padding:1px"> |
|
1056 | 1054 | <div class="code-header"> |
|
1057 | 1055 | <div class="changeset_header"> |
|
1058 | 1056 | <div class="changeset_file"> |
|
1059 | 1057 | <i class="icon-file"></i> |
|
1060 | 1058 | <a href="/pygments/files/ea295cfb622620f5ba13e226ec531e3fe5296399/tests/test_basic_api.py">tests/test_basic_api.py</a> |
|
1061 | 1059 | [mode: <span id="selected_mode">python</span>] |
|
1062 | 1060 | </div> |
|
1063 | 1061 | <div class="diff-actions"> |
|
1064 | 1062 | <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&diff=diff&diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&fulldiff=1" class="tooltip" title="Show full diff for this file"> |
|
1065 | 1063 | <img class="icon" src="/images/icons/page_white_go.png"> |
|
1066 | 1064 | </a> |
|
1067 | 1065 | <a href="/pygments/diff-2way/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&diff=diff&diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&fulldiff=1" class="tooltip" title="Show full side-by-side diff for this file" tt_title="Show full side-by-side diff for this file"> |
|
1068 | 1066 | <img class="icon" src="/images/icons/application_double.png"> |
|
1069 | 1067 | </a> |
|
1070 | 1068 | <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&diff=raw" class="tooltip" title="Raw diff"> |
|
1071 | 1069 | <img class="icon" src="/images/icons/page_white.png"> |
|
1072 | 1070 | </a> |
|
1073 | 1071 | <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&diff=download" class="tooltip" title="Download diff"> |
|
1074 | 1072 | <img class="icon" src="/images/icons/page_save.png"> |
|
1075 | 1073 | </a> |
|
1076 | 1074 | <label><input id="ignorews" name="ignorews" type="checkbox" value="1">ignore white space</label> |
|
1077 | 1075 | <label><input id="edit_mode" name="edit_mode" type="checkbox" value="1">turn on edit mode</label> |
|
1078 | 1076 | |
|
1079 | 1077 | </div> |
|
1080 | 1078 | <div style="float: right; padding: 0px 10px 0px 0px"> |
|
1081 | 1079 | r1538:de45f950b669 ... r1539:ea295cfb6226 |
|
1082 | 1080 | </div> |
|
1083 | 1081 | </div> |
|
1084 | 1082 | </div> |
|
1085 | 1083 | <div id="compare"></div> |
|
1086 | 1084 | </div> |
|
1087 | 1085 | </div> |
|
1088 | 1086 | |
|
1089 | 1087 | <script> |
|
1090 | 1088 | $(document).ready(function () { |
|
1091 | 1089 | var example_lines = '1\n2\n3\n4\n5\n6\n7\n8\n9\n \n'; |
|
1092 | 1090 | |
|
1093 | 1091 | $('#compare').mergely({ |
|
1094 | 1092 | width: 'auto', |
|
1095 | 1093 | height: '600', |
|
1096 | 1094 | fgcolor: {a:'#ddffdd',c:'#cccccc',d:'#ffdddd'}, |
|
1097 | 1095 | bgcolor: '#fff', |
|
1098 | 1096 | viewport: true, |
|
1099 | 1097 | cmsettings: {mode: 'text/plain', readOnly: true, lineWrapping: false, lineNumbers: true}, |
|
1100 | 1098 | lhs: function(setValue) { |
|
1101 | 1099 | if("False" == "True"){ |
|
1102 | 1100 | setValue('Binary file') |
|
1103 | 1101 | } |
|
1104 | 1102 | else if("MercurialCommit" == "EmptyCommit"){ |
|
1105 | 1103 | setValue(''); |
|
1106 | 1104 | } |
|
1107 | 1105 | else{ |
|
1108 | 1106 | var left_value = example_lines.slice(0, 10) + |
|
1109 | 1107 | '123456789 '.repeat(10) + |
|
1110 | 1108 | '\n'+ |
|
1111 | 1109 | example_lines.slice(10, 20); |
|
1112 | 1110 | setValue(left_value + example_lines.repeat(9)); |
|
1113 | 1111 | } |
|
1114 | 1112 | |
|
1115 | 1113 | }, |
|
1116 | 1114 | rhs: function(setValue) { |
|
1117 | 1115 | if("False" == "True"){ |
|
1118 | 1116 | setValue('Binary file') |
|
1119 | 1117 | } |
|
1120 | 1118 | else if("MercurialCommit" == "EmptyCommit"){ |
|
1121 | 1119 | setValue(''); |
|
1122 | 1120 | } |
|
1123 | 1121 | else{ |
|
1124 | 1122 | var right_value = example_lines + |
|
1125 | 1123 | example_lines.slice(0, 8) + |
|
1126 | 1124 | 'abcdefghi '.repeat(10) + |
|
1127 | 1125 | '\n'+ |
|
1128 | 1126 | example_lines.slice(8, 20); |
|
1129 | 1127 | setValue(right_value + example_lines.repeat(9)); |
|
1130 | 1128 | } |
|
1131 | 1129 | }, |
|
1132 | 1130 | }); |
|
1133 | 1131 | |
|
1134 | 1132 | var detected_mode = detectCodeMirrorModeFromExt('test_basic_api.py', true); |
|
1135 | 1133 | if(detected_mode){ |
|
1136 | 1134 | setCodeMirrorMode($('#compare').mergely('cm', 'lhs'), detected_mode); |
|
1137 | 1135 | setCodeMirrorMode($('#compare').mergely('cm', 'rhs'), detected_mode); |
|
1138 | 1136 | $('#selected_mode').html(detected_mode); |
|
1139 | 1137 | } |
|
1140 | 1138 | |
|
1141 | 1139 | $('#ignorews').change(function(e){ |
|
1142 | 1140 | var val = e.currentTarget.checked; |
|
1143 | 1141 | $('#compare').mergely('options', {ignorews: val}); |
|
1144 | 1142 | $('#compare').mergely('update'); |
|
1145 | 1143 | }) |
|
1146 | 1144 | $('#edit_mode').change(function(e){ |
|
1147 | 1145 | var val = !e.currentTarget.checked; |
|
1148 | 1146 | $('#compare').mergely('cm', 'lhs').setOption('readOnly', val); |
|
1149 | 1147 | $('#compare').mergely('cm', 'rhs').setOption('readOnly', val); |
|
1150 | 1148 | $('#compare').mergely('update'); |
|
1151 | 1149 | }) |
|
1152 | 1150 | }); |
|
1153 | 1151 | </script> |
|
1154 | 1152 | |
|
1155 | 1153 | </div> |
|
1156 | 1154 | |
|
1157 | 1155 | <!-- end examples --> |
|
1158 | 1156 | |
|
1159 | 1157 | </div> |
|
1160 | 1158 | </div> |
|
1161 | 1159 | </div> |
|
1162 | 1160 | </%def> |
@@ -1,286 +1,324 b'' | |||
|
1 | 1 | <%inherit file="/base/base.html"/> |
|
2 | 2 | |
|
3 | 3 | <%def name="title(*args)"> |
|
4 | 4 | ${_('%s Files') % c.repo_name} |
|
5 | 5 | %if hasattr(c,'file'): |
|
6 | 6 | · ${h.safe_unicode(c.file.path) or '\\'} |
|
7 | 7 | %endif |
|
8 | 8 | |
|
9 | 9 | %if c.rhodecode_name: |
|
10 | 10 | · ${h.branding(c.rhodecode_name)} |
|
11 | 11 | %endif |
|
12 | 12 | </%def> |
|
13 | 13 | |
|
14 | 14 | <%def name="breadcrumbs_links()"> |
|
15 | 15 | ${_('Files')} |
|
16 | 16 | %if c.file: |
|
17 | 17 | @ ${h.show_id(c.commit)} |
|
18 | 18 | %endif |
|
19 | 19 | </%def> |
|
20 | 20 | |
|
21 | 21 | <%def name="menu_bar_nav()"> |
|
22 | 22 | ${self.menu_items(active='repositories')} |
|
23 | 23 | </%def> |
|
24 | 24 | |
|
25 | 25 | <%def name="menu_bar_subnav()"> |
|
26 | 26 | ${self.repo_menu(active='files')} |
|
27 | 27 | </%def> |
|
28 | 28 | |
|
29 | 29 | <%def name="main()"> |
|
30 | 30 | <div class="title"> |
|
31 | 31 | ${self.repo_page_title(c.rhodecode_db_repo)} |
|
32 | 32 | </div> |
|
33 | 33 | |
|
34 | 34 | <div id="pjax-container" class="summary"> |
|
35 | 35 | <div id="files_data"> |
|
36 | 36 | <%include file='files_pjax.html'/> |
|
37 | 37 | </div> |
|
38 | 38 | </div> |
|
39 | 39 | <script> |
|
40 | 40 | var curState = { |
|
41 | 41 | commit_id: "${c.commit.raw_id}" |
|
42 | 42 | }; |
|
43 | 43 | |
|
44 | 44 | var getState = function(context) { |
|
45 | 45 | var url = $(location).attr('href'); |
|
46 | 46 | var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}'; |
|
47 | 47 | var _annotate_url = '${h.url("files_annotate_home",repo_name=c.repo_name,revision='',f_path='')}'; |
|
48 | 48 | _base_url = _base_url.replace('//', '/'); |
|
49 | 49 | _annotate_url = _annotate_url.replace('//', '/'); |
|
50 | 50 | |
|
51 | 51 | //extract f_path from url. |
|
52 | 52 | var parts = url.split(_base_url); |
|
53 | 53 | if (parts.length != 2) { |
|
54 | 54 | parts = url.split(_annotate_url); |
|
55 | 55 | if (parts.length != 2) { |
|
56 | 56 | var rev = "tip"; |
|
57 | 57 | var f_path = ""; |
|
58 | 58 | } else { |
|
59 | 59 | var parts2 = parts[1].split('/'); |
|
60 | 60 | var rev = parts2.shift(); // pop the first element which is the revision |
|
61 | 61 | var f_path = parts2.join('/'); |
|
62 | 62 | } |
|
63 | 63 | |
|
64 | 64 | } else { |
|
65 | 65 | var parts2 = parts[1].split('/'); |
|
66 | 66 | var rev = parts2.shift(); // pop the first element which is the revision |
|
67 | 67 | var f_path = parts2.join('/'); |
|
68 | 68 | } |
|
69 | 69 | |
|
70 | 70 | var _node_list_url = pyroutes.url('files_nodelist_home', |
|
71 | 71 | {repo_name: templateContext.repo_name, |
|
72 | 72 | revision: rev, f_path: f_path}); |
|
73 | 73 | var _url_base = pyroutes.url('files_home', |
|
74 | 74 | {repo_name: templateContext.repo_name, |
|
75 | 75 | revision: rev, f_path:'__FPATH__'}); |
|
76 | 76 | return { |
|
77 | 77 | url: url, |
|
78 | 78 | f_path: f_path, |
|
79 | 79 | rev: rev, |
|
80 | 80 | commit_id: curState.commit_id, |
|
81 | 81 | node_list_url: _node_list_url, |
|
82 | 82 | url_base: _url_base |
|
83 | 83 | }; |
|
84 | 84 | }; |
|
85 | 85 | |
|
86 | 86 | var metadataRequest = null; |
|
87 | 87 | var getFilesMetadata = function() { |
|
88 | 88 | if (metadataRequest && metadataRequest.readyState != 4) { |
|
89 | 89 | metadataRequest.abort(); |
|
90 | 90 | } |
|
91 | 91 | if (fileSourcePage) { |
|
92 | 92 | return false; |
|
93 | 93 | } |
|
94 | 94 | |
|
95 | 95 | if ($('#file-tree-wrapper').hasClass('full-load')) { |
|
96 | 96 | // in case our HTML wrapper has full-load class we don't |
|
97 | 97 | // trigger the async load of metadata |
|
98 | 98 | return false; |
|
99 | 99 | } |
|
100 | 100 | |
|
101 | 101 | var state = getState('metadata'); |
|
102 | 102 | var url_data = { |
|
103 | 103 | 'repo_name': templateContext.repo_name, |
|
104 | 104 | 'commit_id': state.commit_id, |
|
105 | 105 | 'f_path': state.f_path |
|
106 | 106 | }; |
|
107 | 107 | |
|
108 | 108 | var url = pyroutes.url('files_nodetree_full', url_data); |
|
109 | 109 | |
|
110 | 110 | metadataRequest = $.ajax({url: url}); |
|
111 | 111 | |
|
112 | 112 | metadataRequest.done(function(data) { |
|
113 | 113 | $('#file-tree').html(data); |
|
114 | 114 | timeagoActivate(); |
|
115 | 115 | }); |
|
116 | 116 | metadataRequest.fail(function (data, textStatus, errorThrown) { |
|
117 | 117 | console.log(data); |
|
118 | 118 | if (data.status != 0) { |
|
119 | 119 | alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText)); |
|
120 | 120 | } |
|
121 | 121 | }); |
|
122 | 122 | }; |
|
123 | 123 | |
|
124 | 124 | var callbacks = function() { |
|
125 | 125 | var state = getState('callbacks'); |
|
126 | 126 | timeagoActivate(); |
|
127 | 127 | |
|
128 | 128 | // used for history, and switch to |
|
129 | 129 | var initialCommitData = { |
|
130 | 130 | id: null, |
|
131 |
text: '${_(" |
|
|
131 | text: '${_("Pick Commit")}', | |
|
132 | 132 | type: 'sha', |
|
133 | 133 | raw_id: null, |
|
134 | 134 | files_url: null |
|
135 | 135 | }; |
|
136 | 136 | |
|
137 | 137 | if ($('#trimmed_message_box').height() < 50) { |
|
138 | 138 | $('#message_expand').hide(); |
|
139 | 139 | } |
|
140 | 140 | |
|
141 | 141 | $('#message_expand').on('click', function(e) { |
|
142 | 142 | $('#trimmed_message_box').css('max-height', 'none'); |
|
143 | 143 | $(this).hide(); |
|
144 | 144 | }); |
|
145 | 145 | |
|
146 | 146 | if (fileSourcePage) { |
|
147 | 147 | // variants for with source code, not tree view |
|
148 | 148 | |
|
149 | 149 | // select code link event |
|
150 | 150 | $("#hlcode").mouseup(getSelectionLink); |
|
151 | 151 | |
|
152 | 152 | // file history select2 |
|
153 | 153 | select2FileHistorySwitcher('#diff1', initialCommitData, state); |
|
154 | ||
|
155 | // show at, diff to actions handlers | |
|
154 | 156 | $('#diff1').on('change', function(e) { |
|
155 | $('#diff').removeClass('disabled').removeAttr("disabled"); | |
|
156 | $('#show_rev').removeClass('disabled').removeAttr("disabled"); | |
|
157 | $('#diff_to_commit').removeClass('disabled').removeAttr("disabled"); | |
|
158 | $('#diff_to_commit').val(_gettext('Diff to Commit ') + e.val.truncateAfter(8, '...')); | |
|
159 | ||
|
160 | $('#show_at_commit').removeClass('disabled').removeAttr("disabled"); | |
|
161 | $('#show_at_commit').val(_gettext('Show at Commit ') + e.val.truncateAfter(8, '...')); | |
|
162 | }); | |
|
163 | ||
|
164 | $('#diff_to_commit').on('click', function(e) { | |
|
165 | var diff1 = $('#diff1').val(); | |
|
166 | var diff2 = $('#diff2').val(); | |
|
167 | ||
|
168 | var url_data = { | |
|
169 | repo_name: templateContext.repo_name, | |
|
170 | source_ref: diff1, | |
|
171 | source_ref_type: 'rev', | |
|
172 | target_ref: diff2, | |
|
173 | target_ref_type: 'rev', | |
|
174 | merge: 1, | |
|
175 | f_path: state.f_path | |
|
176 | }; | |
|
177 | window.location = pyroutes.url('compare_url', url_data); | |
|
178 | }); | |
|
179 | ||
|
180 | $('#show_at_commit').on('click', function(e) { | |
|
181 | var diff1 = $('#diff1').val(); | |
|
182 | ||
|
183 | var annotate = $('#annotate').val(); | |
|
184 | if (annotate === "True") { | |
|
185 | var url = pyroutes.url('files_annotate_home', | |
|
186 | {'repo_name': templateContext.repo_name, | |
|
187 | 'revision': diff1, 'f_path': state.f_path}); | |
|
188 | } else { | |
|
189 | var url = pyroutes.url('files_home', | |
|
190 | {'repo_name': templateContext.repo_name, | |
|
191 | 'revision': diff1, 'f_path': state.f_path}); | |
|
192 | } | |
|
193 | window.location = url; | |
|
194 | ||
|
157 | 195 | }); |
|
158 | 196 | |
|
159 | 197 | // show more authors |
|
160 | 198 | $('#show_authors').on('click', function(e) { |
|
161 | 199 | e.preventDefault(); |
|
162 | 200 | var url = pyroutes.url('files_authors_home', |
|
163 | 201 | {'repo_name': templateContext.repo_name, |
|
164 | 202 | 'revision': state.rev, 'f_path': state.f_path}); |
|
165 | 203 | |
|
166 | 204 | $.pjax({ |
|
167 | 205 | url: url, |
|
168 | 206 | data: 'annotate=${"1" if c.annotate else "0"}', |
|
169 | 207 | container: '#file_authors', |
|
170 | 208 | push: false, |
|
171 | 209 | timeout: pjaxTimeout |
|
172 | 210 | }).complete(function(){ |
|
173 | 211 | $('#show_authors').hide(); |
|
174 | 212 | }) |
|
175 | 213 | }); |
|
176 | 214 | |
|
177 | 215 | // load file short history |
|
178 | 216 | $('#file_history_overview').on('click', function(e) { |
|
179 | 217 | e.preventDefault(); |
|
180 | 218 | path = state.f_path; |
|
181 | 219 | if (path.indexOf("#") >= 0) { |
|
182 | 220 | path = path.slice(0, path.indexOf("#")); |
|
183 | 221 | } |
|
184 | 222 | var url = pyroutes.url('changelog_file_home', |
|
185 | 223 | {'repo_name': templateContext.repo_name, |
|
186 | 224 | 'revision': state.rev, 'f_path': path, 'limit': 6}); |
|
187 | 225 | $('#file_history_container').show(); |
|
188 | 226 | $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...'))); |
|
189 | 227 | |
|
190 | 228 | $.pjax({ |
|
191 | 229 | url: url, |
|
192 | 230 | container: '#file_history_container', |
|
193 | 231 | push: false, |
|
194 | 232 | timeout: pjaxTimeout |
|
195 | 233 | }) |
|
196 | 234 | }); |
|
197 | 235 | |
|
198 | 236 | } |
|
199 | 237 | else { |
|
200 | 238 | getFilesMetadata(); |
|
201 | 239 | |
|
202 | 240 | // fuzzy file filter |
|
203 | 241 | fileBrowserListeners(state.node_list_url, state.url_base); |
|
204 | 242 | |
|
205 | 243 | // switch to widget |
|
206 | 244 | select2RefSwitcher('#refs_filter', initialCommitData); |
|
207 | 245 | $('#refs_filter').on('change', function(e) { |
|
208 | 246 | var data = $('#refs_filter').select2('data'); |
|
209 | 247 | curState.commit_id = data.raw_id; |
|
210 | 248 | $.pjax({url: data.files_url, container: '#pjax-container', timeout: pjaxTimeout}); |
|
211 | 249 | }); |
|
212 | 250 | |
|
213 | 251 | $("#prev_commit_link").on('click', function(e) { |
|
214 | 252 | var data = $(this).data(); |
|
215 | 253 | curState.commit_id = data.commitId; |
|
216 | 254 | }); |
|
217 | 255 | |
|
218 | 256 | $("#next_commit_link").on('click', function(e) { |
|
219 | 257 | var data = $(this).data(); |
|
220 | 258 | curState.commit_id = data.commitId; |
|
221 | 259 | }); |
|
222 | 260 | |
|
223 | 261 | $('#at_rev').on("keypress", function(e) { |
|
224 | 262 | /* ENTER PRESSED */ |
|
225 | 263 | if (e.keyCode === 13) { |
|
226 | 264 | var rev = $('#at_rev').val(); |
|
227 | 265 | // explicit reload page here. with pjax entering bad input |
|
228 | 266 | // produces not so nice results |
|
229 | 267 | window.location = pyroutes.url('files_home', |
|
230 | 268 | {'repo_name': templateContext.repo_name, |
|
231 | 269 | 'revision': rev, 'f_path': state.f_path}); |
|
232 | 270 | } |
|
233 | 271 | }); |
|
234 | 272 | } |
|
235 | 273 | }; |
|
236 | 274 | |
|
237 | 275 | var pjaxTimeout = 5000; |
|
238 | 276 | |
|
239 | 277 | $(document).pjax(".pjax-link", "#pjax-container", { |
|
240 | 278 | "fragment": "#pjax-content", |
|
241 | 279 | "maxCacheLength": 1000, |
|
242 | 280 | "timeout": pjaxTimeout |
|
243 | 281 | }); |
|
244 | 282 | |
|
245 | 283 | // define global back/forward states |
|
246 | 284 | var isPjaxPopState = false; |
|
247 | 285 | $(document).on('pjax:popstate', function() { |
|
248 | 286 | isPjaxPopState = true; |
|
249 | 287 | }); |
|
250 | 288 | |
|
251 | 289 | $(document).on('pjax:end', function(xhr, options) { |
|
252 | 290 | if (isPjaxPopState) { |
|
253 | 291 | isPjaxPopState = false; |
|
254 | 292 | callbacks(); |
|
255 | 293 | _NODEFILTER.resetFilter(); |
|
256 | 294 | } |
|
257 | 295 | |
|
258 | 296 | // run callback for tracking if defined for google analytics etc. |
|
259 | 297 | // this is used to trigger tracking on pjax |
|
260 | 298 | if (typeof window.rhodecode_statechange_callback !== 'undefined') { |
|
261 | 299 | var state = getState('statechange'); |
|
262 | 300 | rhodecode_statechange_callback(state.url, null) |
|
263 | 301 | } |
|
264 | 302 | }); |
|
265 | 303 | |
|
266 | 304 | $(document).on('pjax:success', function(event, xhr, options) { |
|
267 | 305 | if (event.target.id == "file_history_container") { |
|
268 | 306 | $('#file_history_overview').hide(); |
|
269 | 307 | $('#file_history_overview_full').show(); |
|
270 | 308 | timeagoActivate(); |
|
271 | 309 | } else { |
|
272 | 310 | callbacks(); |
|
273 | 311 | } |
|
274 | 312 | }); |
|
275 | 313 | |
|
276 | 314 | $(document).ready(function() { |
|
277 | 315 | callbacks(); |
|
278 | 316 | var search_GET = "${request.GET.get('search','')}"; |
|
279 | 317 | if (search_GET == "1") { |
|
280 | 318 | _NODEFILTER.initFilter(); |
|
281 | 319 | } |
|
282 | 320 | }); |
|
283 | 321 | |
|
284 | 322 | </script> |
|
285 | 323 | |
|
286 | 324 | </%def> |
@@ -1,62 +1,74 b'' | |||
|
1 | 1 | <%namespace name="file_base" file="/files/base.html"/> |
|
2 | 2 | |
|
3 | 3 | <div class="fieldset collapsable-content no-hide" data-toggle="summary-details"> |
|
4 | 4 | <div class="left-label"> |
|
5 | 5 | ${_('Commit Description')}: |
|
6 | 6 | </div> |
|
7 | 7 | <div class="commit right-content truncate-wrap">${h.urlify_commit_message(h.chop_at_smart(c.commit.message, '\n', suffix_if_chopped='...'), c.repo_name)}</div> |
|
8 | 8 | </div> |
|
9 | 9 | |
|
10 | 10 | <div class="fieldset collapsable-content" data-toggle="summary-details"> |
|
11 | 11 | <div class="left-label"> |
|
12 | 12 | ${_('Commit Description')}: |
|
13 | 13 | </div> |
|
14 | 14 | <div class="commit right-content">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div> |
|
15 | 15 | </div> |
|
16 | 16 | |
|
17 | 17 | |
|
18 | 18 | <div class="fieldset " data-toggle="summary-details"> |
|
19 | 19 | <div class="left-label"> |
|
20 | 20 | ${_('References')}: |
|
21 | 21 | </div> |
|
22 | 22 | <div class="right-content"> |
|
23 | 23 | <div class="tags tags-main"> |
|
24 | 24 | <code> |
|
25 | 25 | <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.commit.raw_id)}">${h.show_id(c.commit)}</a> |
|
26 | 26 | </code> |
|
27 | 27 | |
|
28 | 28 | ${file_base.refs(c.commit)} |
|
29 | 29 | </div> |
|
30 | 30 | </div> |
|
31 | 31 | </div> |
|
32 | 32 | |
|
33 | 33 | <div class="fieldset collapsable-content" data-toggle="summary-details"> |
|
34 | 34 | <div class="left-label"> |
|
35 | 35 | ${_('File last commit')}: |
|
36 | 36 | </div> |
|
37 | 37 | <div class="right-content"> |
|
38 | 38 | <div class="tags"> |
|
39 | 39 | <code> |
|
40 | 40 | <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.file_last_commit.raw_id)}">${h.show_id(c.file_last_commit)}</a> |
|
41 | 41 | </code> |
|
42 | 42 | |
|
43 | 43 | ${file_base.refs(c.file_last_commit)} |
|
44 | 44 | </div> |
|
45 | 45 | </div> |
|
46 | 46 | </div> |
|
47 | 47 | |
|
48 | 48 | |
|
49 |
<div |
|
|
50 | ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')} | |
|
49 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
|
50 | <div class="left-label"> | |
|
51 | ${_('Show/Diff file')}: | |
|
52 | </div> | |
|
53 | <div class="right-content"> | |
|
51 | 54 | ${h.hidden('diff1')} |
|
52 |
${h.hidden('diff2',c. |
|
|
55 | ${h.hidden('diff2',c.commit.raw_id)} | |
|
56 | ${h.hidden('annotate', c.annotate)} | |
|
57 | </div> | |
|
58 | </div> | |
|
53 | 59 | |
|
54 | ${h.submit('diff',_('Diff to Commit'),class_="btn disabled",disabled="true")} | |
|
55 | ${h.submit('show_rev',_('Show at Commit'),class_="btn disabled",disabled="true")} | |
|
56 | ${h.hidden('annotate', c.annotate)} | |
|
57 | ${h.end_form()} | |
|
60 | ||
|
61 | <div class="fieldset collapsable-content" data-toggle="summary-details"> | |
|
62 | <div class="left-label"> | |
|
63 | ${_('Action')}: | |
|
64 | </div> | |
|
65 | <div class="right-content"> | |
|
66 | ${h.submit('diff_to_commit',_('Diff to Commit'),class_="btn disabled",disabled="true")} | |
|
67 | ${h.submit('show_at_commit',_('Show at Commit'),class_="btn disabled",disabled="true")} | |
|
68 | </div> | |
|
58 | 69 | </div> |
|
59 | 70 | |
|
71 | ||
|
60 | 72 | <script> |
|
61 | 73 | collapsableContent(); |
|
62 | 74 | </script> No newline at end of file |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: modified file | |
The requested commit or file is too big and content was truncated. Show full diff |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed | |
This diff has been collapsed as it changes many lines, (1669 lines changed) Show them Hide them |
|
1 | NO CONTENT: file was removed |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now