##// END OF EJS Templates
diffs: compare overhaul....
marcink -
r1259:8e9f93ec default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

1 NO CONTENT: new file 100644
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
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
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 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Routes configuration
22 Routes configuration
23
23
24 The more specific and detailed routes should be defined first so they
24 The more specific and detailed routes should be defined first so they
25 may take precedent over the more generic routes. For more information
25 may take precedent over the more generic routes. For more information
26 refer to the routes manual at http://routes.groovie.org/docs/
26 refer to the routes manual at http://routes.groovie.org/docs/
27
27
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
28 IMPORTANT: if you change any routing here, make sure to take a look at lib/base.py
29 and _route_name variable which uses some of stored naming here to do redirects.
29 and _route_name variable which uses some of stored naming here to do redirects.
30 """
30 """
31 import os
31 import os
32 import re
32 import re
33 from routes import Mapper
33 from routes import Mapper
34
34
35 from rhodecode.config import routing_links
35 from rhodecode.config import routing_links
36
36
37 # prefix for non repository related links needs to be prefixed with `/`
37 # prefix for non repository related links needs to be prefixed with `/`
38 ADMIN_PREFIX = '/_admin'
38 ADMIN_PREFIX = '/_admin'
39 STATIC_FILE_PREFIX = '/_static'
39 STATIC_FILE_PREFIX = '/_static'
40
40
41 # Default requirements for URL parts
41 # Default requirements for URL parts
42 URL_NAME_REQUIREMENTS = {
42 URL_NAME_REQUIREMENTS = {
43 # group name can have a slash in them, but they must not end with a slash
43 # group name can have a slash in them, but they must not end with a slash
44 'group_name': r'.*?[^/]',
44 'group_name': r'.*?[^/]',
45 'repo_group_name': r'.*?[^/]',
45 'repo_group_name': r'.*?[^/]',
46 # repo names can have a slash in them, but they must not end with a slash
46 # repo names can have a slash in them, but they must not end with a slash
47 'repo_name': r'.*?[^/]',
47 'repo_name': r'.*?[^/]',
48 # file path eats up everything at the end
48 # file path eats up everything at the end
49 'f_path': r'.*',
49 'f_path': r'.*',
50 # reference types
50 # reference types
51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
51 'source_ref_type': '(branch|book|tag|rev|\%\(source_ref_type\)s)',
52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
52 'target_ref_type': '(branch|book|tag|rev|\%\(target_ref_type\)s)',
53 }
53 }
54
54
55
55
56 def add_route_requirements(route_path, requirements):
56 def add_route_requirements(route_path, requirements):
57 """
57 """
58 Adds regex requirements to pyramid routes using a mapping dict
58 Adds regex requirements to pyramid routes using a mapping dict
59
59
60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
60 >>> add_route_requirements('/{action}/{id}', {'id': r'\d+'})
61 '/{action}/{id:\d+}'
61 '/{action}/{id:\d+}'
62
62
63 """
63 """
64 for key, regex in requirements.items():
64 for key, regex in requirements.items():
65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
65 route_path = route_path.replace('{%s}' % key, '{%s:%s}' % (key, regex))
66 return route_path
66 return route_path
67
67
68
68
69 class JSRoutesMapper(Mapper):
69 class JSRoutesMapper(Mapper):
70 """
70 """
71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
71 Wrapper for routes.Mapper to make pyroutes compatible url definitions
72 """
72 """
73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
73 _named_route_regex = re.compile(r'^[a-z-_0-9A-Z]+$')
74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
74 _argument_prog = re.compile('\{(.*?)\}|:\((.*)\)')
75 def __init__(self, *args, **kw):
75 def __init__(self, *args, **kw):
76 super(JSRoutesMapper, self).__init__(*args, **kw)
76 super(JSRoutesMapper, self).__init__(*args, **kw)
77 self._jsroutes = []
77 self._jsroutes = []
78
78
79 def connect(self, *args, **kw):
79 def connect(self, *args, **kw):
80 """
80 """
81 Wrapper for connect to take an extra argument jsroute=True
81 Wrapper for connect to take an extra argument jsroute=True
82
82
83 :param jsroute: boolean, if True will add the route to the pyroutes list
83 :param jsroute: boolean, if True will add the route to the pyroutes list
84 """
84 """
85 if kw.pop('jsroute', False):
85 if kw.pop('jsroute', False):
86 if not self._named_route_regex.match(args[0]):
86 if not self._named_route_regex.match(args[0]):
87 raise Exception('only named routes can be added to pyroutes')
87 raise Exception('only named routes can be added to pyroutes')
88 self._jsroutes.append(args[0])
88 self._jsroutes.append(args[0])
89
89
90 super(JSRoutesMapper, self).connect(*args, **kw)
90 super(JSRoutesMapper, self).connect(*args, **kw)
91
91
92 def _extract_route_information(self, route):
92 def _extract_route_information(self, route):
93 """
93 """
94 Convert a route into tuple(name, path, args), eg:
94 Convert a route into tuple(name, path, args), eg:
95 ('user_profile', '/profile/%(username)s', ['username'])
95 ('user_profile', '/profile/%(username)s', ['username'])
96 """
96 """
97 routepath = route.routepath
97 routepath = route.routepath
98 def replace(matchobj):
98 def replace(matchobj):
99 if matchobj.group(1):
99 if matchobj.group(1):
100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
100 return "%%(%s)s" % matchobj.group(1).split(':')[0]
101 else:
101 else:
102 return "%%(%s)s" % matchobj.group(2)
102 return "%%(%s)s" % matchobj.group(2)
103
103
104 routepath = self._argument_prog.sub(replace, routepath)
104 routepath = self._argument_prog.sub(replace, routepath)
105 return (
105 return (
106 route.name,
106 route.name,
107 routepath,
107 routepath,
108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
108 [(arg[0].split(':')[0] if arg[0] != '' else arg[1])
109 for arg in self._argument_prog.findall(route.routepath)]
109 for arg in self._argument_prog.findall(route.routepath)]
110 )
110 )
111
111
112 def jsroutes(self):
112 def jsroutes(self):
113 """
113 """
114 Return a list of pyroutes.js compatible routes
114 Return a list of pyroutes.js compatible routes
115 """
115 """
116 for route_name in self._jsroutes:
116 for route_name in self._jsroutes:
117 yield self._extract_route_information(self._routenames[route_name])
117 yield self._extract_route_information(self._routenames[route_name])
118
118
119
119
120 def make_map(config):
120 def make_map(config):
121 """Create, configure and return the routes Mapper"""
121 """Create, configure and return the routes Mapper"""
122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
122 rmap = JSRoutesMapper(directory=config['pylons.paths']['controllers'],
123 always_scan=config['debug'])
123 always_scan=config['debug'])
124 rmap.minimization = False
124 rmap.minimization = False
125 rmap.explicit = False
125 rmap.explicit = False
126
126
127 from rhodecode.lib.utils2 import str2bool
127 from rhodecode.lib.utils2 import str2bool
128 from rhodecode.model import repo, repo_group
128 from rhodecode.model import repo, repo_group
129
129
130 def check_repo(environ, match_dict):
130 def check_repo(environ, match_dict):
131 """
131 """
132 check for valid repository for proper 404 handling
132 check for valid repository for proper 404 handling
133
133
134 :param environ:
134 :param environ:
135 :param match_dict:
135 :param match_dict:
136 """
136 """
137 repo_name = match_dict.get('repo_name')
137 repo_name = match_dict.get('repo_name')
138
138
139 if match_dict.get('f_path'):
139 if match_dict.get('f_path'):
140 # fix for multiple initial slashes that causes errors
140 # fix for multiple initial slashes that causes errors
141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
141 match_dict['f_path'] = match_dict['f_path'].lstrip('/')
142 repo_model = repo.RepoModel()
142 repo_model = repo.RepoModel()
143 by_name_match = repo_model.get_by_repo_name(repo_name)
143 by_name_match = repo_model.get_by_repo_name(repo_name)
144 # if we match quickly from database, short circuit the operation,
144 # if we match quickly from database, short circuit the operation,
145 # and validate repo based on the type.
145 # and validate repo based on the type.
146 if by_name_match:
146 if by_name_match:
147 return True
147 return True
148
148
149 by_id_match = repo_model.get_repo_by_id(repo_name)
149 by_id_match = repo_model.get_repo_by_id(repo_name)
150 if by_id_match:
150 if by_id_match:
151 repo_name = by_id_match.repo_name
151 repo_name = by_id_match.repo_name
152 match_dict['repo_name'] = repo_name
152 match_dict['repo_name'] = repo_name
153 return True
153 return True
154
154
155 return False
155 return False
156
156
157 def check_group(environ, match_dict):
157 def check_group(environ, match_dict):
158 """
158 """
159 check for valid repository group path for proper 404 handling
159 check for valid repository group path for proper 404 handling
160
160
161 :param environ:
161 :param environ:
162 :param match_dict:
162 :param match_dict:
163 """
163 """
164 repo_group_name = match_dict.get('group_name')
164 repo_group_name = match_dict.get('group_name')
165 repo_group_model = repo_group.RepoGroupModel()
165 repo_group_model = repo_group.RepoGroupModel()
166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
166 by_name_match = repo_group_model.get_by_group_name(repo_group_name)
167 if by_name_match:
167 if by_name_match:
168 return True
168 return True
169
169
170 return False
170 return False
171
171
172 def check_user_group(environ, match_dict):
172 def check_user_group(environ, match_dict):
173 """
173 """
174 check for valid user group for proper 404 handling
174 check for valid user group for proper 404 handling
175
175
176 :param environ:
176 :param environ:
177 :param match_dict:
177 :param match_dict:
178 """
178 """
179 return True
179 return True
180
180
181 def check_int(environ, match_dict):
181 def check_int(environ, match_dict):
182 return match_dict.get('id').isdigit()
182 return match_dict.get('id').isdigit()
183
183
184
184
185 #==========================================================================
185 #==========================================================================
186 # CUSTOM ROUTES HERE
186 # CUSTOM ROUTES HERE
187 #==========================================================================
187 #==========================================================================
188
188
189 # MAIN PAGE
189 # MAIN PAGE
190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
190 rmap.connect('home', '/', controller='home', action='index', jsroute=True)
191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
191 rmap.connect('goto_switcher_data', '/_goto_data', controller='home',
192 action='goto_switcher_data')
192 action='goto_switcher_data')
193 rmap.connect('repo_list_data', '/_repos', controller='home',
193 rmap.connect('repo_list_data', '/_repos', controller='home',
194 action='repo_list_data')
194 action='repo_list_data')
195
195
196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
196 rmap.connect('user_autocomplete_data', '/_users', controller='home',
197 action='user_autocomplete_data', jsroute=True)
197 action='user_autocomplete_data', jsroute=True)
198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
198 rmap.connect('user_group_autocomplete_data', '/_user_groups', controller='home',
199 action='user_group_autocomplete_data', jsroute=True)
199 action='user_group_autocomplete_data', jsroute=True)
200
200
201 rmap.connect(
201 rmap.connect(
202 'user_profile', '/_profiles/{username}', controller='users',
202 'user_profile', '/_profiles/{username}', controller='users',
203 action='user_profile')
203 action='user_profile')
204
204
205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
205 # TODO: johbo: Static links, to be replaced by our redirection mechanism
206 rmap.connect('rst_help',
206 rmap.connect('rst_help',
207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
207 'http://docutils.sourceforge.net/docs/user/rst/quickref.html',
208 _static=True)
208 _static=True)
209 rmap.connect('markdown_help',
209 rmap.connect('markdown_help',
210 'http://daringfireball.net/projects/markdown/syntax',
210 'http://daringfireball.net/projects/markdown/syntax',
211 _static=True)
211 _static=True)
212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
212 rmap.connect('rhodecode_official', 'https://rhodecode.com', _static=True)
213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
213 rmap.connect('rhodecode_support', 'https://rhodecode.com/help/', _static=True)
214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
214 rmap.connect('rhodecode_translations', 'https://rhodecode.com/translate/enterprise', _static=True)
215 # TODO: anderson - making this a static link since redirect won't play
215 # TODO: anderson - making this a static link since redirect won't play
216 # nice with POST requests
216 # nice with POST requests
217 rmap.connect('enterprise_license_convert_from_old',
217 rmap.connect('enterprise_license_convert_from_old',
218 'https://rhodecode.com/u/license-upgrade',
218 'https://rhodecode.com/u/license-upgrade',
219 _static=True)
219 _static=True)
220
220
221 routing_links.connect_redirection_links(rmap)
221 routing_links.connect_redirection_links(rmap)
222
222
223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
223 rmap.connect('ping', '%s/ping' % (ADMIN_PREFIX,), controller='home', action='ping')
224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
224 rmap.connect('error_test', '%s/error_test' % (ADMIN_PREFIX,), controller='home', action='error_test')
225
225
226 # ADMIN REPOSITORY ROUTES
226 # ADMIN REPOSITORY ROUTES
227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
227 with rmap.submapper(path_prefix=ADMIN_PREFIX,
228 controller='admin/repos') as m:
228 controller='admin/repos') as m:
229 m.connect('repos', '/repos',
229 m.connect('repos', '/repos',
230 action='create', conditions={'method': ['POST']})
230 action='create', conditions={'method': ['POST']})
231 m.connect('repos', '/repos',
231 m.connect('repos', '/repos',
232 action='index', conditions={'method': ['GET']})
232 action='index', conditions={'method': ['GET']})
233 m.connect('new_repo', '/create_repository', jsroute=True,
233 m.connect('new_repo', '/create_repository', jsroute=True,
234 action='create_repository', conditions={'method': ['GET']})
234 action='create_repository', conditions={'method': ['GET']})
235 m.connect('/repos/{repo_name}',
235 m.connect('/repos/{repo_name}',
236 action='update', conditions={'method': ['PUT'],
236 action='update', conditions={'method': ['PUT'],
237 'function': check_repo},
237 'function': check_repo},
238 requirements=URL_NAME_REQUIREMENTS)
238 requirements=URL_NAME_REQUIREMENTS)
239 m.connect('delete_repo', '/repos/{repo_name}',
239 m.connect('delete_repo', '/repos/{repo_name}',
240 action='delete', conditions={'method': ['DELETE']},
240 action='delete', conditions={'method': ['DELETE']},
241 requirements=URL_NAME_REQUIREMENTS)
241 requirements=URL_NAME_REQUIREMENTS)
242 m.connect('repo', '/repos/{repo_name}',
242 m.connect('repo', '/repos/{repo_name}',
243 action='show', conditions={'method': ['GET'],
243 action='show', conditions={'method': ['GET'],
244 'function': check_repo},
244 'function': check_repo},
245 requirements=URL_NAME_REQUIREMENTS)
245 requirements=URL_NAME_REQUIREMENTS)
246
246
247 # ADMIN REPOSITORY GROUPS ROUTES
247 # ADMIN REPOSITORY GROUPS ROUTES
248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
248 with rmap.submapper(path_prefix=ADMIN_PREFIX,
249 controller='admin/repo_groups') as m:
249 controller='admin/repo_groups') as m:
250 m.connect('repo_groups', '/repo_groups',
250 m.connect('repo_groups', '/repo_groups',
251 action='create', conditions={'method': ['POST']})
251 action='create', conditions={'method': ['POST']})
252 m.connect('repo_groups', '/repo_groups',
252 m.connect('repo_groups', '/repo_groups',
253 action='index', conditions={'method': ['GET']})
253 action='index', conditions={'method': ['GET']})
254 m.connect('new_repo_group', '/repo_groups/new',
254 m.connect('new_repo_group', '/repo_groups/new',
255 action='new', conditions={'method': ['GET']})
255 action='new', conditions={'method': ['GET']})
256 m.connect('update_repo_group', '/repo_groups/{group_name}',
256 m.connect('update_repo_group', '/repo_groups/{group_name}',
257 action='update', conditions={'method': ['PUT'],
257 action='update', conditions={'method': ['PUT'],
258 'function': check_group},
258 'function': check_group},
259 requirements=URL_NAME_REQUIREMENTS)
259 requirements=URL_NAME_REQUIREMENTS)
260
260
261 # EXTRAS REPO GROUP ROUTES
261 # EXTRAS REPO GROUP ROUTES
262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
262 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
263 action='edit',
263 action='edit',
264 conditions={'method': ['GET'], 'function': check_group},
264 conditions={'method': ['GET'], 'function': check_group},
265 requirements=URL_NAME_REQUIREMENTS)
265 requirements=URL_NAME_REQUIREMENTS)
266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
266 m.connect('edit_repo_group', '/repo_groups/{group_name}/edit',
267 action='edit',
267 action='edit',
268 conditions={'method': ['PUT'], 'function': check_group},
268 conditions={'method': ['PUT'], 'function': check_group},
269 requirements=URL_NAME_REQUIREMENTS)
269 requirements=URL_NAME_REQUIREMENTS)
270
270
271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
271 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
272 action='edit_repo_group_advanced',
272 action='edit_repo_group_advanced',
273 conditions={'method': ['GET'], 'function': check_group},
273 conditions={'method': ['GET'], 'function': check_group},
274 requirements=URL_NAME_REQUIREMENTS)
274 requirements=URL_NAME_REQUIREMENTS)
275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
275 m.connect('edit_repo_group_advanced', '/repo_groups/{group_name}/edit/advanced',
276 action='edit_repo_group_advanced',
276 action='edit_repo_group_advanced',
277 conditions={'method': ['PUT'], 'function': check_group},
277 conditions={'method': ['PUT'], 'function': check_group},
278 requirements=URL_NAME_REQUIREMENTS)
278 requirements=URL_NAME_REQUIREMENTS)
279
279
280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
280 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
281 action='edit_repo_group_perms',
281 action='edit_repo_group_perms',
282 conditions={'method': ['GET'], 'function': check_group},
282 conditions={'method': ['GET'], 'function': check_group},
283 requirements=URL_NAME_REQUIREMENTS)
283 requirements=URL_NAME_REQUIREMENTS)
284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
284 m.connect('edit_repo_group_perms', '/repo_groups/{group_name}/edit/permissions',
285 action='update_perms',
285 action='update_perms',
286 conditions={'method': ['PUT'], 'function': check_group},
286 conditions={'method': ['PUT'], 'function': check_group},
287 requirements=URL_NAME_REQUIREMENTS)
287 requirements=URL_NAME_REQUIREMENTS)
288
288
289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
289 m.connect('delete_repo_group', '/repo_groups/{group_name}',
290 action='delete', conditions={'method': ['DELETE'],
290 action='delete', conditions={'method': ['DELETE'],
291 'function': check_group},
291 'function': check_group},
292 requirements=URL_NAME_REQUIREMENTS)
292 requirements=URL_NAME_REQUIREMENTS)
293
293
294 # ADMIN USER ROUTES
294 # ADMIN USER ROUTES
295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
295 with rmap.submapper(path_prefix=ADMIN_PREFIX,
296 controller='admin/users') as m:
296 controller='admin/users') as m:
297 m.connect('users', '/users',
297 m.connect('users', '/users',
298 action='create', conditions={'method': ['POST']})
298 action='create', conditions={'method': ['POST']})
299 m.connect('users', '/users',
299 m.connect('users', '/users',
300 action='index', conditions={'method': ['GET']})
300 action='index', conditions={'method': ['GET']})
301 m.connect('new_user', '/users/new',
301 m.connect('new_user', '/users/new',
302 action='new', conditions={'method': ['GET']})
302 action='new', conditions={'method': ['GET']})
303 m.connect('update_user', '/users/{user_id}',
303 m.connect('update_user', '/users/{user_id}',
304 action='update', conditions={'method': ['PUT']})
304 action='update', conditions={'method': ['PUT']})
305 m.connect('delete_user', '/users/{user_id}',
305 m.connect('delete_user', '/users/{user_id}',
306 action='delete', conditions={'method': ['DELETE']})
306 action='delete', conditions={'method': ['DELETE']})
307 m.connect('edit_user', '/users/{user_id}/edit',
307 m.connect('edit_user', '/users/{user_id}/edit',
308 action='edit', conditions={'method': ['GET']}, jsroute=True)
308 action='edit', conditions={'method': ['GET']}, jsroute=True)
309 m.connect('user', '/users/{user_id}',
309 m.connect('user', '/users/{user_id}',
310 action='show', conditions={'method': ['GET']})
310 action='show', conditions={'method': ['GET']})
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
311 m.connect('force_password_reset_user', '/users/{user_id}/password_reset',
312 action='reset_password', conditions={'method': ['POST']})
312 action='reset_password', conditions={'method': ['POST']})
313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
313 m.connect('create_personal_repo_group', '/users/{user_id}/create_repo_group',
314 action='create_personal_repo_group', conditions={'method': ['POST']})
314 action='create_personal_repo_group', conditions={'method': ['POST']})
315
315
316 # EXTRAS USER ROUTES
316 # EXTRAS USER ROUTES
317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
317 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
318 action='edit_advanced', conditions={'method': ['GET']})
318 action='edit_advanced', conditions={'method': ['GET']})
319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
319 m.connect('edit_user_advanced', '/users/{user_id}/edit/advanced',
320 action='update_advanced', conditions={'method': ['PUT']})
320 action='update_advanced', conditions={'method': ['PUT']})
321
321
322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
322 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
323 action='edit_auth_tokens', conditions={'method': ['GET']})
323 action='edit_auth_tokens', conditions={'method': ['GET']})
324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
324 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
325 action='add_auth_token', conditions={'method': ['PUT']})
325 action='add_auth_token', conditions={'method': ['PUT']})
326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
326 m.connect('edit_user_auth_tokens', '/users/{user_id}/edit/auth_tokens',
327 action='delete_auth_token', conditions={'method': ['DELETE']})
327 action='delete_auth_token', conditions={'method': ['DELETE']})
328
328
329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
329 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
330 action='edit_global_perms', conditions={'method': ['GET']})
330 action='edit_global_perms', conditions={'method': ['GET']})
331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
331 m.connect('edit_user_global_perms', '/users/{user_id}/edit/global_permissions',
332 action='update_global_perms', conditions={'method': ['PUT']})
332 action='update_global_perms', conditions={'method': ['PUT']})
333
333
334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
334 m.connect('edit_user_perms_summary', '/users/{user_id}/edit/permissions_summary',
335 action='edit_perms_summary', conditions={'method': ['GET']})
335 action='edit_perms_summary', conditions={'method': ['GET']})
336
336
337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
337 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
338 action='edit_emails', conditions={'method': ['GET']})
338 action='edit_emails', conditions={'method': ['GET']})
339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
339 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
340 action='add_email', conditions={'method': ['PUT']})
340 action='add_email', conditions={'method': ['PUT']})
341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
341 m.connect('edit_user_emails', '/users/{user_id}/edit/emails',
342 action='delete_email', conditions={'method': ['DELETE']})
342 action='delete_email', conditions={'method': ['DELETE']})
343
343
344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
344 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
345 action='edit_ips', conditions={'method': ['GET']})
345 action='edit_ips', conditions={'method': ['GET']})
346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
346 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
347 action='add_ip', conditions={'method': ['PUT']})
347 action='add_ip', conditions={'method': ['PUT']})
348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
348 m.connect('edit_user_ips', '/users/{user_id}/edit/ips',
349 action='delete_ip', conditions={'method': ['DELETE']})
349 action='delete_ip', conditions={'method': ['DELETE']})
350
350
351 # ADMIN USER GROUPS REST ROUTES
351 # ADMIN USER GROUPS REST ROUTES
352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
352 with rmap.submapper(path_prefix=ADMIN_PREFIX,
353 controller='admin/user_groups') as m:
353 controller='admin/user_groups') as m:
354 m.connect('users_groups', '/user_groups',
354 m.connect('users_groups', '/user_groups',
355 action='create', conditions={'method': ['POST']})
355 action='create', conditions={'method': ['POST']})
356 m.connect('users_groups', '/user_groups',
356 m.connect('users_groups', '/user_groups',
357 action='index', conditions={'method': ['GET']})
357 action='index', conditions={'method': ['GET']})
358 m.connect('new_users_group', '/user_groups/new',
358 m.connect('new_users_group', '/user_groups/new',
359 action='new', conditions={'method': ['GET']})
359 action='new', conditions={'method': ['GET']})
360 m.connect('update_users_group', '/user_groups/{user_group_id}',
360 m.connect('update_users_group', '/user_groups/{user_group_id}',
361 action='update', conditions={'method': ['PUT']})
361 action='update', conditions={'method': ['PUT']})
362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
362 m.connect('delete_users_group', '/user_groups/{user_group_id}',
363 action='delete', conditions={'method': ['DELETE']})
363 action='delete', conditions={'method': ['DELETE']})
364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
364 m.connect('edit_users_group', '/user_groups/{user_group_id}/edit',
365 action='edit', conditions={'method': ['GET']},
365 action='edit', conditions={'method': ['GET']},
366 function=check_user_group)
366 function=check_user_group)
367
367
368 # EXTRAS USER GROUP ROUTES
368 # EXTRAS USER GROUP ROUTES
369 m.connect('edit_user_group_global_perms',
369 m.connect('edit_user_group_global_perms',
370 '/user_groups/{user_group_id}/edit/global_permissions',
370 '/user_groups/{user_group_id}/edit/global_permissions',
371 action='edit_global_perms', conditions={'method': ['GET']})
371 action='edit_global_perms', conditions={'method': ['GET']})
372 m.connect('edit_user_group_global_perms',
372 m.connect('edit_user_group_global_perms',
373 '/user_groups/{user_group_id}/edit/global_permissions',
373 '/user_groups/{user_group_id}/edit/global_permissions',
374 action='update_global_perms', conditions={'method': ['PUT']})
374 action='update_global_perms', conditions={'method': ['PUT']})
375 m.connect('edit_user_group_perms_summary',
375 m.connect('edit_user_group_perms_summary',
376 '/user_groups/{user_group_id}/edit/permissions_summary',
376 '/user_groups/{user_group_id}/edit/permissions_summary',
377 action='edit_perms_summary', conditions={'method': ['GET']})
377 action='edit_perms_summary', conditions={'method': ['GET']})
378
378
379 m.connect('edit_user_group_perms',
379 m.connect('edit_user_group_perms',
380 '/user_groups/{user_group_id}/edit/permissions',
380 '/user_groups/{user_group_id}/edit/permissions',
381 action='edit_perms', conditions={'method': ['GET']})
381 action='edit_perms', conditions={'method': ['GET']})
382 m.connect('edit_user_group_perms',
382 m.connect('edit_user_group_perms',
383 '/user_groups/{user_group_id}/edit/permissions',
383 '/user_groups/{user_group_id}/edit/permissions',
384 action='update_perms', conditions={'method': ['PUT']})
384 action='update_perms', conditions={'method': ['PUT']})
385
385
386 m.connect('edit_user_group_advanced',
386 m.connect('edit_user_group_advanced',
387 '/user_groups/{user_group_id}/edit/advanced',
387 '/user_groups/{user_group_id}/edit/advanced',
388 action='edit_advanced', conditions={'method': ['GET']})
388 action='edit_advanced', conditions={'method': ['GET']})
389
389
390 m.connect('edit_user_group_members',
390 m.connect('edit_user_group_members',
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
391 '/user_groups/{user_group_id}/edit/members', jsroute=True,
392 action='user_group_members', conditions={'method': ['GET']})
392 action='user_group_members', conditions={'method': ['GET']})
393
393
394 # ADMIN PERMISSIONS ROUTES
394 # ADMIN PERMISSIONS ROUTES
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
395 with rmap.submapper(path_prefix=ADMIN_PREFIX,
396 controller='admin/permissions') as m:
396 controller='admin/permissions') as m:
397 m.connect('admin_permissions_application', '/permissions/application',
397 m.connect('admin_permissions_application', '/permissions/application',
398 action='permission_application_update', conditions={'method': ['POST']})
398 action='permission_application_update', conditions={'method': ['POST']})
399 m.connect('admin_permissions_application', '/permissions/application',
399 m.connect('admin_permissions_application', '/permissions/application',
400 action='permission_application', conditions={'method': ['GET']})
400 action='permission_application', conditions={'method': ['GET']})
401
401
402 m.connect('admin_permissions_global', '/permissions/global',
402 m.connect('admin_permissions_global', '/permissions/global',
403 action='permission_global_update', conditions={'method': ['POST']})
403 action='permission_global_update', conditions={'method': ['POST']})
404 m.connect('admin_permissions_global', '/permissions/global',
404 m.connect('admin_permissions_global', '/permissions/global',
405 action='permission_global', conditions={'method': ['GET']})
405 action='permission_global', conditions={'method': ['GET']})
406
406
407 m.connect('admin_permissions_object', '/permissions/object',
407 m.connect('admin_permissions_object', '/permissions/object',
408 action='permission_objects_update', conditions={'method': ['POST']})
408 action='permission_objects_update', conditions={'method': ['POST']})
409 m.connect('admin_permissions_object', '/permissions/object',
409 m.connect('admin_permissions_object', '/permissions/object',
410 action='permission_objects', conditions={'method': ['GET']})
410 action='permission_objects', conditions={'method': ['GET']})
411
411
412 m.connect('admin_permissions_ips', '/permissions/ips',
412 m.connect('admin_permissions_ips', '/permissions/ips',
413 action='permission_ips', conditions={'method': ['POST']})
413 action='permission_ips', conditions={'method': ['POST']})
414 m.connect('admin_permissions_ips', '/permissions/ips',
414 m.connect('admin_permissions_ips', '/permissions/ips',
415 action='permission_ips', conditions={'method': ['GET']})
415 action='permission_ips', conditions={'method': ['GET']})
416
416
417 m.connect('admin_permissions_overview', '/permissions/overview',
417 m.connect('admin_permissions_overview', '/permissions/overview',
418 action='permission_perms', conditions={'method': ['GET']})
418 action='permission_perms', conditions={'method': ['GET']})
419
419
420 # ADMIN DEFAULTS REST ROUTES
420 # ADMIN DEFAULTS REST ROUTES
421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
421 with rmap.submapper(path_prefix=ADMIN_PREFIX,
422 controller='admin/defaults') as m:
422 controller='admin/defaults') as m:
423 m.connect('admin_defaults_repositories', '/defaults/repositories',
423 m.connect('admin_defaults_repositories', '/defaults/repositories',
424 action='update_repository_defaults', conditions={'method': ['POST']})
424 action='update_repository_defaults', conditions={'method': ['POST']})
425 m.connect('admin_defaults_repositories', '/defaults/repositories',
425 m.connect('admin_defaults_repositories', '/defaults/repositories',
426 action='index', conditions={'method': ['GET']})
426 action='index', conditions={'method': ['GET']})
427
427
428 # ADMIN DEBUG STYLE ROUTES
428 # ADMIN DEBUG STYLE ROUTES
429 if str2bool(config.get('debug_style')):
429 if str2bool(config.get('debug_style')):
430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
430 with rmap.submapper(path_prefix=ADMIN_PREFIX + '/debug_style',
431 controller='debug_style') as m:
431 controller='debug_style') as m:
432 m.connect('debug_style_home', '',
432 m.connect('debug_style_home', '',
433 action='index', conditions={'method': ['GET']})
433 action='index', conditions={'method': ['GET']})
434 m.connect('debug_style_template', '/t/{t_path}',
434 m.connect('debug_style_template', '/t/{t_path}',
435 action='template', conditions={'method': ['GET']})
435 action='template', conditions={'method': ['GET']})
436
436
437 # ADMIN SETTINGS ROUTES
437 # ADMIN SETTINGS ROUTES
438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
438 with rmap.submapper(path_prefix=ADMIN_PREFIX,
439 controller='admin/settings') as m:
439 controller='admin/settings') as m:
440
440
441 # default
441 # default
442 m.connect('admin_settings', '/settings',
442 m.connect('admin_settings', '/settings',
443 action='settings_global_update',
443 action='settings_global_update',
444 conditions={'method': ['POST']})
444 conditions={'method': ['POST']})
445 m.connect('admin_settings', '/settings',
445 m.connect('admin_settings', '/settings',
446 action='settings_global', conditions={'method': ['GET']})
446 action='settings_global', conditions={'method': ['GET']})
447
447
448 m.connect('admin_settings_vcs', '/settings/vcs',
448 m.connect('admin_settings_vcs', '/settings/vcs',
449 action='settings_vcs_update',
449 action='settings_vcs_update',
450 conditions={'method': ['POST']})
450 conditions={'method': ['POST']})
451 m.connect('admin_settings_vcs', '/settings/vcs',
451 m.connect('admin_settings_vcs', '/settings/vcs',
452 action='settings_vcs',
452 action='settings_vcs',
453 conditions={'method': ['GET']})
453 conditions={'method': ['GET']})
454 m.connect('admin_settings_vcs', '/settings/vcs',
454 m.connect('admin_settings_vcs', '/settings/vcs',
455 action='delete_svn_pattern',
455 action='delete_svn_pattern',
456 conditions={'method': ['DELETE']})
456 conditions={'method': ['DELETE']})
457
457
458 m.connect('admin_settings_mapping', '/settings/mapping',
458 m.connect('admin_settings_mapping', '/settings/mapping',
459 action='settings_mapping_update',
459 action='settings_mapping_update',
460 conditions={'method': ['POST']})
460 conditions={'method': ['POST']})
461 m.connect('admin_settings_mapping', '/settings/mapping',
461 m.connect('admin_settings_mapping', '/settings/mapping',
462 action='settings_mapping', conditions={'method': ['GET']})
462 action='settings_mapping', conditions={'method': ['GET']})
463
463
464 m.connect('admin_settings_global', '/settings/global',
464 m.connect('admin_settings_global', '/settings/global',
465 action='settings_global_update',
465 action='settings_global_update',
466 conditions={'method': ['POST']})
466 conditions={'method': ['POST']})
467 m.connect('admin_settings_global', '/settings/global',
467 m.connect('admin_settings_global', '/settings/global',
468 action='settings_global', conditions={'method': ['GET']})
468 action='settings_global', conditions={'method': ['GET']})
469
469
470 m.connect('admin_settings_visual', '/settings/visual',
470 m.connect('admin_settings_visual', '/settings/visual',
471 action='settings_visual_update',
471 action='settings_visual_update',
472 conditions={'method': ['POST']})
472 conditions={'method': ['POST']})
473 m.connect('admin_settings_visual', '/settings/visual',
473 m.connect('admin_settings_visual', '/settings/visual',
474 action='settings_visual', conditions={'method': ['GET']})
474 action='settings_visual', conditions={'method': ['GET']})
475
475
476 m.connect('admin_settings_issuetracker',
476 m.connect('admin_settings_issuetracker',
477 '/settings/issue-tracker', action='settings_issuetracker',
477 '/settings/issue-tracker', action='settings_issuetracker',
478 conditions={'method': ['GET']})
478 conditions={'method': ['GET']})
479 m.connect('admin_settings_issuetracker_save',
479 m.connect('admin_settings_issuetracker_save',
480 '/settings/issue-tracker/save',
480 '/settings/issue-tracker/save',
481 action='settings_issuetracker_save',
481 action='settings_issuetracker_save',
482 conditions={'method': ['POST']})
482 conditions={'method': ['POST']})
483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
483 m.connect('admin_issuetracker_test', '/settings/issue-tracker/test',
484 action='settings_issuetracker_test',
484 action='settings_issuetracker_test',
485 conditions={'method': ['POST']})
485 conditions={'method': ['POST']})
486 m.connect('admin_issuetracker_delete',
486 m.connect('admin_issuetracker_delete',
487 '/settings/issue-tracker/delete',
487 '/settings/issue-tracker/delete',
488 action='settings_issuetracker_delete',
488 action='settings_issuetracker_delete',
489 conditions={'method': ['DELETE']})
489 conditions={'method': ['DELETE']})
490
490
491 m.connect('admin_settings_email', '/settings/email',
491 m.connect('admin_settings_email', '/settings/email',
492 action='settings_email_update',
492 action='settings_email_update',
493 conditions={'method': ['POST']})
493 conditions={'method': ['POST']})
494 m.connect('admin_settings_email', '/settings/email',
494 m.connect('admin_settings_email', '/settings/email',
495 action='settings_email', conditions={'method': ['GET']})
495 action='settings_email', conditions={'method': ['GET']})
496
496
497 m.connect('admin_settings_hooks', '/settings/hooks',
497 m.connect('admin_settings_hooks', '/settings/hooks',
498 action='settings_hooks_update',
498 action='settings_hooks_update',
499 conditions={'method': ['POST', 'DELETE']})
499 conditions={'method': ['POST', 'DELETE']})
500 m.connect('admin_settings_hooks', '/settings/hooks',
500 m.connect('admin_settings_hooks', '/settings/hooks',
501 action='settings_hooks', conditions={'method': ['GET']})
501 action='settings_hooks', conditions={'method': ['GET']})
502
502
503 m.connect('admin_settings_search', '/settings/search',
503 m.connect('admin_settings_search', '/settings/search',
504 action='settings_search', conditions={'method': ['GET']})
504 action='settings_search', conditions={'method': ['GET']})
505
505
506 m.connect('admin_settings_system', '/settings/system',
506 m.connect('admin_settings_system', '/settings/system',
507 action='settings_system', conditions={'method': ['GET']})
507 action='settings_system', conditions={'method': ['GET']})
508
508
509 m.connect('admin_settings_system_update', '/settings/system/updates',
509 m.connect('admin_settings_system_update', '/settings/system/updates',
510 action='settings_system_update', conditions={'method': ['GET']})
510 action='settings_system_update', conditions={'method': ['GET']})
511
511
512 m.connect('admin_settings_supervisor', '/settings/supervisor',
512 m.connect('admin_settings_supervisor', '/settings/supervisor',
513 action='settings_supervisor', conditions={'method': ['GET']})
513 action='settings_supervisor', conditions={'method': ['GET']})
514 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
514 m.connect('admin_settings_supervisor_log', '/settings/supervisor/{procid}/log',
515 action='settings_supervisor_log', conditions={'method': ['GET']})
515 action='settings_supervisor_log', conditions={'method': ['GET']})
516
516
517 m.connect('admin_settings_labs', '/settings/labs',
517 m.connect('admin_settings_labs', '/settings/labs',
518 action='settings_labs_update',
518 action='settings_labs_update',
519 conditions={'method': ['POST']})
519 conditions={'method': ['POST']})
520 m.connect('admin_settings_labs', '/settings/labs',
520 m.connect('admin_settings_labs', '/settings/labs',
521 action='settings_labs', conditions={'method': ['GET']})
521 action='settings_labs', conditions={'method': ['GET']})
522
522
523 # ADMIN MY ACCOUNT
523 # ADMIN MY ACCOUNT
524 with rmap.submapper(path_prefix=ADMIN_PREFIX,
524 with rmap.submapper(path_prefix=ADMIN_PREFIX,
525 controller='admin/my_account') as m:
525 controller='admin/my_account') as m:
526
526
527 m.connect('my_account', '/my_account',
527 m.connect('my_account', '/my_account',
528 action='my_account', conditions={'method': ['GET']})
528 action='my_account', conditions={'method': ['GET']})
529 m.connect('my_account_edit', '/my_account/edit',
529 m.connect('my_account_edit', '/my_account/edit',
530 action='my_account_edit', conditions={'method': ['GET']})
530 action='my_account_edit', conditions={'method': ['GET']})
531 m.connect('my_account', '/my_account',
531 m.connect('my_account', '/my_account',
532 action='my_account_update', conditions={'method': ['POST']})
532 action='my_account_update', conditions={'method': ['POST']})
533
533
534 m.connect('my_account_password', '/my_account/password',
534 m.connect('my_account_password', '/my_account/password',
535 action='my_account_password', conditions={'method': ['GET', 'POST']})
535 action='my_account_password', conditions={'method': ['GET', 'POST']})
536
536
537 m.connect('my_account_repos', '/my_account/repos',
537 m.connect('my_account_repos', '/my_account/repos',
538 action='my_account_repos', conditions={'method': ['GET']})
538 action='my_account_repos', conditions={'method': ['GET']})
539
539
540 m.connect('my_account_watched', '/my_account/watched',
540 m.connect('my_account_watched', '/my_account/watched',
541 action='my_account_watched', conditions={'method': ['GET']})
541 action='my_account_watched', conditions={'method': ['GET']})
542
542
543 m.connect('my_account_pullrequests', '/my_account/pull_requests',
543 m.connect('my_account_pullrequests', '/my_account/pull_requests',
544 action='my_account_pullrequests', conditions={'method': ['GET']})
544 action='my_account_pullrequests', conditions={'method': ['GET']})
545
545
546 m.connect('my_account_perms', '/my_account/perms',
546 m.connect('my_account_perms', '/my_account/perms',
547 action='my_account_perms', conditions={'method': ['GET']})
547 action='my_account_perms', conditions={'method': ['GET']})
548
548
549 m.connect('my_account_emails', '/my_account/emails',
549 m.connect('my_account_emails', '/my_account/emails',
550 action='my_account_emails', conditions={'method': ['GET']})
550 action='my_account_emails', conditions={'method': ['GET']})
551 m.connect('my_account_emails', '/my_account/emails',
551 m.connect('my_account_emails', '/my_account/emails',
552 action='my_account_emails_add', conditions={'method': ['POST']})
552 action='my_account_emails_add', conditions={'method': ['POST']})
553 m.connect('my_account_emails', '/my_account/emails',
553 m.connect('my_account_emails', '/my_account/emails',
554 action='my_account_emails_delete', conditions={'method': ['DELETE']})
554 action='my_account_emails_delete', conditions={'method': ['DELETE']})
555
555
556 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
556 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
557 action='my_account_auth_tokens', conditions={'method': ['GET']})
557 action='my_account_auth_tokens', conditions={'method': ['GET']})
558 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
558 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
559 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
559 action='my_account_auth_tokens_add', conditions={'method': ['POST']})
560 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
560 m.connect('my_account_auth_tokens', '/my_account/auth_tokens',
561 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
561 action='my_account_auth_tokens_delete', conditions={'method': ['DELETE']})
562 m.connect('my_account_notifications', '/my_account/notifications',
562 m.connect('my_account_notifications', '/my_account/notifications',
563 action='my_notifications',
563 action='my_notifications',
564 conditions={'method': ['GET']})
564 conditions={'method': ['GET']})
565 m.connect('my_account_notifications_toggle_visibility',
565 m.connect('my_account_notifications_toggle_visibility',
566 '/my_account/toggle_visibility',
566 '/my_account/toggle_visibility',
567 action='my_notifications_toggle_visibility',
567 action='my_notifications_toggle_visibility',
568 conditions={'method': ['POST']})
568 conditions={'method': ['POST']})
569
569
570 # NOTIFICATION REST ROUTES
570 # NOTIFICATION REST ROUTES
571 with rmap.submapper(path_prefix=ADMIN_PREFIX,
571 with rmap.submapper(path_prefix=ADMIN_PREFIX,
572 controller='admin/notifications') as m:
572 controller='admin/notifications') as m:
573 m.connect('notifications', '/notifications',
573 m.connect('notifications', '/notifications',
574 action='index', conditions={'method': ['GET']})
574 action='index', conditions={'method': ['GET']})
575 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
575 m.connect('notifications_mark_all_read', '/notifications/mark_all_read',
576 action='mark_all_read', conditions={'method': ['POST']})
576 action='mark_all_read', conditions={'method': ['POST']})
577 m.connect('/notifications/{notification_id}',
577 m.connect('/notifications/{notification_id}',
578 action='update', conditions={'method': ['PUT']})
578 action='update', conditions={'method': ['PUT']})
579 m.connect('/notifications/{notification_id}',
579 m.connect('/notifications/{notification_id}',
580 action='delete', conditions={'method': ['DELETE']})
580 action='delete', conditions={'method': ['DELETE']})
581 m.connect('notification', '/notifications/{notification_id}',
581 m.connect('notification', '/notifications/{notification_id}',
582 action='show', conditions={'method': ['GET']})
582 action='show', conditions={'method': ['GET']})
583
583
584 # ADMIN GIST
584 # ADMIN GIST
585 with rmap.submapper(path_prefix=ADMIN_PREFIX,
585 with rmap.submapper(path_prefix=ADMIN_PREFIX,
586 controller='admin/gists') as m:
586 controller='admin/gists') as m:
587 m.connect('gists', '/gists',
587 m.connect('gists', '/gists',
588 action='create', conditions={'method': ['POST']})
588 action='create', conditions={'method': ['POST']})
589 m.connect('gists', '/gists', jsroute=True,
589 m.connect('gists', '/gists', jsroute=True,
590 action='index', conditions={'method': ['GET']})
590 action='index', conditions={'method': ['GET']})
591 m.connect('new_gist', '/gists/new', jsroute=True,
591 m.connect('new_gist', '/gists/new', jsroute=True,
592 action='new', conditions={'method': ['GET']})
592 action='new', conditions={'method': ['GET']})
593
593
594 m.connect('/gists/{gist_id}',
594 m.connect('/gists/{gist_id}',
595 action='delete', conditions={'method': ['DELETE']})
595 action='delete', conditions={'method': ['DELETE']})
596 m.connect('edit_gist', '/gists/{gist_id}/edit',
596 m.connect('edit_gist', '/gists/{gist_id}/edit',
597 action='edit_form', conditions={'method': ['GET']})
597 action='edit_form', conditions={'method': ['GET']})
598 m.connect('edit_gist', '/gists/{gist_id}/edit',
598 m.connect('edit_gist', '/gists/{gist_id}/edit',
599 action='edit', conditions={'method': ['POST']})
599 action='edit', conditions={'method': ['POST']})
600 m.connect(
600 m.connect(
601 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
601 'edit_gist_check_revision', '/gists/{gist_id}/edit/check_revision',
602 action='check_revision', conditions={'method': ['GET']})
602 action='check_revision', conditions={'method': ['GET']})
603
603
604 m.connect('gist', '/gists/{gist_id}',
604 m.connect('gist', '/gists/{gist_id}',
605 action='show', conditions={'method': ['GET']})
605 action='show', conditions={'method': ['GET']})
606 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
606 m.connect('gist_rev', '/gists/{gist_id}/{revision}',
607 revision='tip',
607 revision='tip',
608 action='show', conditions={'method': ['GET']})
608 action='show', conditions={'method': ['GET']})
609 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
609 m.connect('formatted_gist', '/gists/{gist_id}/{revision}/{format}',
610 revision='tip',
610 revision='tip',
611 action='show', conditions={'method': ['GET']})
611 action='show', conditions={'method': ['GET']})
612 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
612 m.connect('formatted_gist_file', '/gists/{gist_id}/{revision}/{format}/{f_path}',
613 revision='tip',
613 revision='tip',
614 action='show', conditions={'method': ['GET']},
614 action='show', conditions={'method': ['GET']},
615 requirements=URL_NAME_REQUIREMENTS)
615 requirements=URL_NAME_REQUIREMENTS)
616
616
617 # ADMIN MAIN PAGES
617 # ADMIN MAIN PAGES
618 with rmap.submapper(path_prefix=ADMIN_PREFIX,
618 with rmap.submapper(path_prefix=ADMIN_PREFIX,
619 controller='admin/admin') as m:
619 controller='admin/admin') as m:
620 m.connect('admin_home', '', action='index')
620 m.connect('admin_home', '', action='index')
621 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
621 m.connect('admin_add_repo', '/add_repo/{new_repo:[a-z0-9\. _-]*}',
622 action='add_repo')
622 action='add_repo')
623 m.connect(
623 m.connect(
624 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
624 'pull_requests_global_0', '/pull_requests/{pull_request_id:[0-9]+}',
625 action='pull_requests')
625 action='pull_requests')
626 m.connect(
626 m.connect(
627 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
627 'pull_requests_global_1', '/pull-requests/{pull_request_id:[0-9]+}',
628 action='pull_requests')
628 action='pull_requests')
629 m.connect(
629 m.connect(
630 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
630 'pull_requests_global', '/pull-request/{pull_request_id:[0-9]+}',
631 action='pull_requests')
631 action='pull_requests')
632
632
633 # USER JOURNAL
633 # USER JOURNAL
634 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
634 rmap.connect('journal', '%s/journal' % (ADMIN_PREFIX,),
635 controller='journal', action='index')
635 controller='journal', action='index')
636 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
636 rmap.connect('journal_rss', '%s/journal/rss' % (ADMIN_PREFIX,),
637 controller='journal', action='journal_rss')
637 controller='journal', action='journal_rss')
638 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
638 rmap.connect('journal_atom', '%s/journal/atom' % (ADMIN_PREFIX,),
639 controller='journal', action='journal_atom')
639 controller='journal', action='journal_atom')
640
640
641 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
641 rmap.connect('public_journal', '%s/public_journal' % (ADMIN_PREFIX,),
642 controller='journal', action='public_journal')
642 controller='journal', action='public_journal')
643
643
644 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
644 rmap.connect('public_journal_rss', '%s/public_journal/rss' % (ADMIN_PREFIX,),
645 controller='journal', action='public_journal_rss')
645 controller='journal', action='public_journal_rss')
646
646
647 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
647 rmap.connect('public_journal_rss_old', '%s/public_journal_rss' % (ADMIN_PREFIX,),
648 controller='journal', action='public_journal_rss')
648 controller='journal', action='public_journal_rss')
649
649
650 rmap.connect('public_journal_atom',
650 rmap.connect('public_journal_atom',
651 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
651 '%s/public_journal/atom' % (ADMIN_PREFIX,), controller='journal',
652 action='public_journal_atom')
652 action='public_journal_atom')
653
653
654 rmap.connect('public_journal_atom_old',
654 rmap.connect('public_journal_atom_old',
655 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
655 '%s/public_journal_atom' % (ADMIN_PREFIX,), controller='journal',
656 action='public_journal_atom')
656 action='public_journal_atom')
657
657
658 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
658 rmap.connect('toggle_following', '%s/toggle_following' % (ADMIN_PREFIX,),
659 controller='journal', action='toggle_following', jsroute=True,
659 controller='journal', action='toggle_following', jsroute=True,
660 conditions={'method': ['POST']})
660 conditions={'method': ['POST']})
661
661
662 # FULL TEXT SEARCH
662 # FULL TEXT SEARCH
663 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
663 rmap.connect('search', '%s/search' % (ADMIN_PREFIX,),
664 controller='search')
664 controller='search')
665 rmap.connect('search_repo_home', '/{repo_name}/search',
665 rmap.connect('search_repo_home', '/{repo_name}/search',
666 controller='search',
666 controller='search',
667 action='index',
667 action='index',
668 conditions={'function': check_repo},
668 conditions={'function': check_repo},
669 requirements=URL_NAME_REQUIREMENTS)
669 requirements=URL_NAME_REQUIREMENTS)
670
670
671 # FEEDS
671 # FEEDS
672 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
672 rmap.connect('rss_feed_home', '/{repo_name}/feed/rss',
673 controller='feed', action='rss',
673 controller='feed', action='rss',
674 conditions={'function': check_repo},
674 conditions={'function': check_repo},
675 requirements=URL_NAME_REQUIREMENTS)
675 requirements=URL_NAME_REQUIREMENTS)
676
676
677 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
677 rmap.connect('atom_feed_home', '/{repo_name}/feed/atom',
678 controller='feed', action='atom',
678 controller='feed', action='atom',
679 conditions={'function': check_repo},
679 conditions={'function': check_repo},
680 requirements=URL_NAME_REQUIREMENTS)
680 requirements=URL_NAME_REQUIREMENTS)
681
681
682 #==========================================================================
682 #==========================================================================
683 # REPOSITORY ROUTES
683 # REPOSITORY ROUTES
684 #==========================================================================
684 #==========================================================================
685
685
686 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
686 rmap.connect('repo_creating_home', '/{repo_name}/repo_creating',
687 controller='admin/repos', action='repo_creating',
687 controller='admin/repos', action='repo_creating',
688 requirements=URL_NAME_REQUIREMENTS)
688 requirements=URL_NAME_REQUIREMENTS)
689 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
689 rmap.connect('repo_check_home', '/{repo_name}/crepo_check',
690 controller='admin/repos', action='repo_check',
690 controller='admin/repos', action='repo_check',
691 requirements=URL_NAME_REQUIREMENTS)
691 requirements=URL_NAME_REQUIREMENTS)
692
692
693 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
693 rmap.connect('repo_stats', '/{repo_name}/repo_stats/{commit_id}',
694 controller='summary', action='repo_stats',
694 controller='summary', action='repo_stats',
695 conditions={'function': check_repo},
695 conditions={'function': check_repo},
696 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
696 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
697
697
698 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
698 rmap.connect('repo_refs_data', '/{repo_name}/refs-data',
699 controller='summary', action='repo_refs_data', jsroute=True,
699 controller='summary', action='repo_refs_data', jsroute=True,
700 requirements=URL_NAME_REQUIREMENTS)
700 requirements=URL_NAME_REQUIREMENTS)
701 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
701 rmap.connect('repo_refs_changelog_data', '/{repo_name}/refs-data-changelog',
702 controller='summary', action='repo_refs_changelog_data',
702 controller='summary', action='repo_refs_changelog_data',
703 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
703 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
704 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
704 rmap.connect('repo_default_reviewers_data', '/{repo_name}/default-reviewers',
705 controller='summary', action='repo_default_reviewers_data',
705 controller='summary', action='repo_default_reviewers_data',
706 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
706 jsroute=True, requirements=URL_NAME_REQUIREMENTS)
707
707
708 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
708 rmap.connect('changeset_home', '/{repo_name}/changeset/{revision}',
709 controller='changeset', revision='tip', jsroute=True,
709 controller='changeset', revision='tip', jsroute=True,
710 conditions={'function': check_repo},
710 conditions={'function': check_repo},
711 requirements=URL_NAME_REQUIREMENTS)
711 requirements=URL_NAME_REQUIREMENTS)
712 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
712 rmap.connect('changeset_children', '/{repo_name}/changeset_children/{revision}',
713 controller='changeset', revision='tip', action='changeset_children',
713 controller='changeset', revision='tip', action='changeset_children',
714 conditions={'function': check_repo},
714 conditions={'function': check_repo},
715 requirements=URL_NAME_REQUIREMENTS)
715 requirements=URL_NAME_REQUIREMENTS)
716 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
716 rmap.connect('changeset_parents', '/{repo_name}/changeset_parents/{revision}',
717 controller='changeset', revision='tip', action='changeset_parents',
717 controller='changeset', revision='tip', action='changeset_parents',
718 conditions={'function': check_repo},
718 conditions={'function': check_repo},
719 requirements=URL_NAME_REQUIREMENTS)
719 requirements=URL_NAME_REQUIREMENTS)
720
720
721 # repo edit options
721 # repo edit options
722 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
722 rmap.connect('edit_repo', '/{repo_name}/settings', jsroute=True,
723 controller='admin/repos', action='edit',
723 controller='admin/repos', action='edit',
724 conditions={'method': ['GET'], 'function': check_repo},
724 conditions={'method': ['GET'], 'function': check_repo},
725 requirements=URL_NAME_REQUIREMENTS)
725 requirements=URL_NAME_REQUIREMENTS)
726
726
727 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
727 rmap.connect('edit_repo_perms', '/{repo_name}/settings/permissions',
728 jsroute=True,
728 jsroute=True,
729 controller='admin/repos', action='edit_permissions',
729 controller='admin/repos', action='edit_permissions',
730 conditions={'method': ['GET'], 'function': check_repo},
730 conditions={'method': ['GET'], 'function': check_repo},
731 requirements=URL_NAME_REQUIREMENTS)
731 requirements=URL_NAME_REQUIREMENTS)
732 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
732 rmap.connect('edit_repo_perms_update', '/{repo_name}/settings/permissions',
733 controller='admin/repos', action='edit_permissions_update',
733 controller='admin/repos', action='edit_permissions_update',
734 conditions={'method': ['PUT'], 'function': check_repo},
734 conditions={'method': ['PUT'], 'function': check_repo},
735 requirements=URL_NAME_REQUIREMENTS)
735 requirements=URL_NAME_REQUIREMENTS)
736
736
737 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
737 rmap.connect('edit_repo_fields', '/{repo_name}/settings/fields',
738 controller='admin/repos', action='edit_fields',
738 controller='admin/repos', action='edit_fields',
739 conditions={'method': ['GET'], 'function': check_repo},
739 conditions={'method': ['GET'], 'function': check_repo},
740 requirements=URL_NAME_REQUIREMENTS)
740 requirements=URL_NAME_REQUIREMENTS)
741 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
741 rmap.connect('create_repo_fields', '/{repo_name}/settings/fields/new',
742 controller='admin/repos', action='create_repo_field',
742 controller='admin/repos', action='create_repo_field',
743 conditions={'method': ['PUT'], 'function': check_repo},
743 conditions={'method': ['PUT'], 'function': check_repo},
744 requirements=URL_NAME_REQUIREMENTS)
744 requirements=URL_NAME_REQUIREMENTS)
745 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
745 rmap.connect('delete_repo_fields', '/{repo_name}/settings/fields/{field_id}',
746 controller='admin/repos', action='delete_repo_field',
746 controller='admin/repos', action='delete_repo_field',
747 conditions={'method': ['DELETE'], 'function': check_repo},
747 conditions={'method': ['DELETE'], 'function': check_repo},
748 requirements=URL_NAME_REQUIREMENTS)
748 requirements=URL_NAME_REQUIREMENTS)
749
749
750 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
750 rmap.connect('edit_repo_advanced', '/{repo_name}/settings/advanced',
751 controller='admin/repos', action='edit_advanced',
751 controller='admin/repos', action='edit_advanced',
752 conditions={'method': ['GET'], 'function': check_repo},
752 conditions={'method': ['GET'], 'function': check_repo},
753 requirements=URL_NAME_REQUIREMENTS)
753 requirements=URL_NAME_REQUIREMENTS)
754
754
755 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
755 rmap.connect('edit_repo_advanced_locking', '/{repo_name}/settings/advanced/locking',
756 controller='admin/repos', action='edit_advanced_locking',
756 controller='admin/repos', action='edit_advanced_locking',
757 conditions={'method': ['PUT'], 'function': check_repo},
757 conditions={'method': ['PUT'], 'function': check_repo},
758 requirements=URL_NAME_REQUIREMENTS)
758 requirements=URL_NAME_REQUIREMENTS)
759 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
759 rmap.connect('toggle_locking', '/{repo_name}/settings/advanced/locking_toggle',
760 controller='admin/repos', action='toggle_locking',
760 controller='admin/repos', action='toggle_locking',
761 conditions={'method': ['GET'], 'function': check_repo},
761 conditions={'method': ['GET'], 'function': check_repo},
762 requirements=URL_NAME_REQUIREMENTS)
762 requirements=URL_NAME_REQUIREMENTS)
763
763
764 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
764 rmap.connect('edit_repo_advanced_journal', '/{repo_name}/settings/advanced/journal',
765 controller='admin/repos', action='edit_advanced_journal',
765 controller='admin/repos', action='edit_advanced_journal',
766 conditions={'method': ['PUT'], 'function': check_repo},
766 conditions={'method': ['PUT'], 'function': check_repo},
767 requirements=URL_NAME_REQUIREMENTS)
767 requirements=URL_NAME_REQUIREMENTS)
768
768
769 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
769 rmap.connect('edit_repo_advanced_fork', '/{repo_name}/settings/advanced/fork',
770 controller='admin/repos', action='edit_advanced_fork',
770 controller='admin/repos', action='edit_advanced_fork',
771 conditions={'method': ['PUT'], 'function': check_repo},
771 conditions={'method': ['PUT'], 'function': check_repo},
772 requirements=URL_NAME_REQUIREMENTS)
772 requirements=URL_NAME_REQUIREMENTS)
773
773
774 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
774 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
775 controller='admin/repos', action='edit_caches_form',
775 controller='admin/repos', action='edit_caches_form',
776 conditions={'method': ['GET'], 'function': check_repo},
776 conditions={'method': ['GET'], 'function': check_repo},
777 requirements=URL_NAME_REQUIREMENTS)
777 requirements=URL_NAME_REQUIREMENTS)
778 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
778 rmap.connect('edit_repo_caches', '/{repo_name}/settings/caches',
779 controller='admin/repos', action='edit_caches',
779 controller='admin/repos', action='edit_caches',
780 conditions={'method': ['PUT'], 'function': check_repo},
780 conditions={'method': ['PUT'], 'function': check_repo},
781 requirements=URL_NAME_REQUIREMENTS)
781 requirements=URL_NAME_REQUIREMENTS)
782
782
783 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
783 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
784 controller='admin/repos', action='edit_remote_form',
784 controller='admin/repos', action='edit_remote_form',
785 conditions={'method': ['GET'], 'function': check_repo},
785 conditions={'method': ['GET'], 'function': check_repo},
786 requirements=URL_NAME_REQUIREMENTS)
786 requirements=URL_NAME_REQUIREMENTS)
787 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
787 rmap.connect('edit_repo_remote', '/{repo_name}/settings/remote',
788 controller='admin/repos', action='edit_remote',
788 controller='admin/repos', action='edit_remote',
789 conditions={'method': ['PUT'], 'function': check_repo},
789 conditions={'method': ['PUT'], 'function': check_repo},
790 requirements=URL_NAME_REQUIREMENTS)
790 requirements=URL_NAME_REQUIREMENTS)
791
791
792 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
792 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
793 controller='admin/repos', action='edit_statistics_form',
793 controller='admin/repos', action='edit_statistics_form',
794 conditions={'method': ['GET'], 'function': check_repo},
794 conditions={'method': ['GET'], 'function': check_repo},
795 requirements=URL_NAME_REQUIREMENTS)
795 requirements=URL_NAME_REQUIREMENTS)
796 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
796 rmap.connect('edit_repo_statistics', '/{repo_name}/settings/statistics',
797 controller='admin/repos', action='edit_statistics',
797 controller='admin/repos', action='edit_statistics',
798 conditions={'method': ['PUT'], 'function': check_repo},
798 conditions={'method': ['PUT'], 'function': check_repo},
799 requirements=URL_NAME_REQUIREMENTS)
799 requirements=URL_NAME_REQUIREMENTS)
800 rmap.connect('repo_settings_issuetracker',
800 rmap.connect('repo_settings_issuetracker',
801 '/{repo_name}/settings/issue-tracker',
801 '/{repo_name}/settings/issue-tracker',
802 controller='admin/repos', action='repo_issuetracker',
802 controller='admin/repos', action='repo_issuetracker',
803 conditions={'method': ['GET'], 'function': check_repo},
803 conditions={'method': ['GET'], 'function': check_repo},
804 requirements=URL_NAME_REQUIREMENTS)
804 requirements=URL_NAME_REQUIREMENTS)
805 rmap.connect('repo_issuetracker_test',
805 rmap.connect('repo_issuetracker_test',
806 '/{repo_name}/settings/issue-tracker/test',
806 '/{repo_name}/settings/issue-tracker/test',
807 controller='admin/repos', action='repo_issuetracker_test',
807 controller='admin/repos', action='repo_issuetracker_test',
808 conditions={'method': ['POST'], 'function': check_repo},
808 conditions={'method': ['POST'], 'function': check_repo},
809 requirements=URL_NAME_REQUIREMENTS)
809 requirements=URL_NAME_REQUIREMENTS)
810 rmap.connect('repo_issuetracker_delete',
810 rmap.connect('repo_issuetracker_delete',
811 '/{repo_name}/settings/issue-tracker/delete',
811 '/{repo_name}/settings/issue-tracker/delete',
812 controller='admin/repos', action='repo_issuetracker_delete',
812 controller='admin/repos', action='repo_issuetracker_delete',
813 conditions={'method': ['DELETE'], 'function': check_repo},
813 conditions={'method': ['DELETE'], 'function': check_repo},
814 requirements=URL_NAME_REQUIREMENTS)
814 requirements=URL_NAME_REQUIREMENTS)
815 rmap.connect('repo_issuetracker_save',
815 rmap.connect('repo_issuetracker_save',
816 '/{repo_name}/settings/issue-tracker/save',
816 '/{repo_name}/settings/issue-tracker/save',
817 controller='admin/repos', action='repo_issuetracker_save',
817 controller='admin/repos', action='repo_issuetracker_save',
818 conditions={'method': ['POST'], 'function': check_repo},
818 conditions={'method': ['POST'], 'function': check_repo},
819 requirements=URL_NAME_REQUIREMENTS)
819 requirements=URL_NAME_REQUIREMENTS)
820 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
820 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
821 controller='admin/repos', action='repo_settings_vcs_update',
821 controller='admin/repos', action='repo_settings_vcs_update',
822 conditions={'method': ['POST'], 'function': check_repo},
822 conditions={'method': ['POST'], 'function': check_repo},
823 requirements=URL_NAME_REQUIREMENTS)
823 requirements=URL_NAME_REQUIREMENTS)
824 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
824 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
825 controller='admin/repos', action='repo_settings_vcs',
825 controller='admin/repos', action='repo_settings_vcs',
826 conditions={'method': ['GET'], 'function': check_repo},
826 conditions={'method': ['GET'], 'function': check_repo},
827 requirements=URL_NAME_REQUIREMENTS)
827 requirements=URL_NAME_REQUIREMENTS)
828 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
828 rmap.connect('repo_vcs_settings', '/{repo_name}/settings/vcs',
829 controller='admin/repos', action='repo_delete_svn_pattern',
829 controller='admin/repos', action='repo_delete_svn_pattern',
830 conditions={'method': ['DELETE'], 'function': check_repo},
830 conditions={'method': ['DELETE'], 'function': check_repo},
831 requirements=URL_NAME_REQUIREMENTS)
831 requirements=URL_NAME_REQUIREMENTS)
832 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
832 rmap.connect('repo_pullrequest_settings', '/{repo_name}/settings/pullrequest',
833 controller='admin/repos', action='repo_settings_pullrequest',
833 controller='admin/repos', action='repo_settings_pullrequest',
834 conditions={'method': ['GET', 'POST'], 'function': check_repo},
834 conditions={'method': ['GET', 'POST'], 'function': check_repo},
835 requirements=URL_NAME_REQUIREMENTS)
835 requirements=URL_NAME_REQUIREMENTS)
836
836
837 # still working url for backward compat.
837 # still working url for backward compat.
838 rmap.connect('raw_changeset_home_depraced',
838 rmap.connect('raw_changeset_home_depraced',
839 '/{repo_name}/raw-changeset/{revision}',
839 '/{repo_name}/raw-changeset/{revision}',
840 controller='changeset', action='changeset_raw',
840 controller='changeset', action='changeset_raw',
841 revision='tip', conditions={'function': check_repo},
841 revision='tip', conditions={'function': check_repo},
842 requirements=URL_NAME_REQUIREMENTS)
842 requirements=URL_NAME_REQUIREMENTS)
843
843
844 # new URLs
844 # new URLs
845 rmap.connect('changeset_raw_home',
845 rmap.connect('changeset_raw_home',
846 '/{repo_name}/changeset-diff/{revision}',
846 '/{repo_name}/changeset-diff/{revision}',
847 controller='changeset', action='changeset_raw',
847 controller='changeset', action='changeset_raw',
848 revision='tip', conditions={'function': check_repo},
848 revision='tip', conditions={'function': check_repo},
849 requirements=URL_NAME_REQUIREMENTS)
849 requirements=URL_NAME_REQUIREMENTS)
850
850
851 rmap.connect('changeset_patch_home',
851 rmap.connect('changeset_patch_home',
852 '/{repo_name}/changeset-patch/{revision}',
852 '/{repo_name}/changeset-patch/{revision}',
853 controller='changeset', action='changeset_patch',
853 controller='changeset', action='changeset_patch',
854 revision='tip', conditions={'function': check_repo},
854 revision='tip', conditions={'function': check_repo},
855 requirements=URL_NAME_REQUIREMENTS)
855 requirements=URL_NAME_REQUIREMENTS)
856
856
857 rmap.connect('changeset_download_home',
857 rmap.connect('changeset_download_home',
858 '/{repo_name}/changeset-download/{revision}',
858 '/{repo_name}/changeset-download/{revision}',
859 controller='changeset', action='changeset_download',
859 controller='changeset', action='changeset_download',
860 revision='tip', conditions={'function': check_repo},
860 revision='tip', conditions={'function': check_repo},
861 requirements=URL_NAME_REQUIREMENTS)
861 requirements=URL_NAME_REQUIREMENTS)
862
862
863 rmap.connect('changeset_comment',
863 rmap.connect('changeset_comment',
864 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
864 '/{repo_name}/changeset/{revision}/comment', jsroute=True,
865 controller='changeset', revision='tip', action='comment',
865 controller='changeset', revision='tip', action='comment',
866 conditions={'function': check_repo},
866 conditions={'function': check_repo},
867 requirements=URL_NAME_REQUIREMENTS)
867 requirements=URL_NAME_REQUIREMENTS)
868
868
869 rmap.connect('changeset_comment_preview',
869 rmap.connect('changeset_comment_preview',
870 '/{repo_name}/changeset/comment/preview', jsroute=True,
870 '/{repo_name}/changeset/comment/preview', jsroute=True,
871 controller='changeset', action='preview_comment',
871 controller='changeset', action='preview_comment',
872 conditions={'function': check_repo, 'method': ['POST']},
872 conditions={'function': check_repo, 'method': ['POST']},
873 requirements=URL_NAME_REQUIREMENTS)
873 requirements=URL_NAME_REQUIREMENTS)
874
874
875 rmap.connect('changeset_comment_delete',
875 rmap.connect('changeset_comment_delete',
876 '/{repo_name}/changeset/comment/{comment_id}/delete',
876 '/{repo_name}/changeset/comment/{comment_id}/delete',
877 controller='changeset', action='delete_comment',
877 controller='changeset', action='delete_comment',
878 conditions={'function': check_repo, 'method': ['DELETE']},
878 conditions={'function': check_repo, 'method': ['DELETE']},
879 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
879 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
880
880
881 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
881 rmap.connect('changeset_info', '/{repo_name}/changeset_info/{revision}',
882 controller='changeset', action='changeset_info',
882 controller='changeset', action='changeset_info',
883 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
883 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
884
884
885 rmap.connect('compare_home',
885 rmap.connect('compare_home',
886 '/{repo_name}/compare',
886 '/{repo_name}/compare',
887 controller='compare', action='index',
887 controller='compare', action='index',
888 conditions={'function': check_repo},
888 conditions={'function': check_repo},
889 requirements=URL_NAME_REQUIREMENTS)
889 requirements=URL_NAME_REQUIREMENTS)
890
890
891 rmap.connect('compare_url',
891 rmap.connect('compare_url',
892 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
892 '/{repo_name}/compare/{source_ref_type}@{source_ref:.*?}...{target_ref_type}@{target_ref:.*?}',
893 controller='compare', action='compare',
893 controller='compare', action='compare',
894 conditions={'function': check_repo},
894 conditions={'function': check_repo},
895 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
895 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
896
896
897 rmap.connect('pullrequest_home',
897 rmap.connect('pullrequest_home',
898 '/{repo_name}/pull-request/new', controller='pullrequests',
898 '/{repo_name}/pull-request/new', controller='pullrequests',
899 action='index', conditions={'function': check_repo,
899 action='index', conditions={'function': check_repo,
900 'method': ['GET']},
900 'method': ['GET']},
901 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
901 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
902
902
903 rmap.connect('pullrequest',
903 rmap.connect('pullrequest',
904 '/{repo_name}/pull-request/new', controller='pullrequests',
904 '/{repo_name}/pull-request/new', controller='pullrequests',
905 action='create', conditions={'function': check_repo,
905 action='create', conditions={'function': check_repo,
906 'method': ['POST']},
906 'method': ['POST']},
907 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
907 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
908
908
909 rmap.connect('pullrequest_repo_refs',
909 rmap.connect('pullrequest_repo_refs',
910 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
910 '/{repo_name}/pull-request/refs/{target_repo_name:.*?[^/]}',
911 controller='pullrequests',
911 controller='pullrequests',
912 action='get_repo_refs',
912 action='get_repo_refs',
913 conditions={'function': check_repo, 'method': ['GET']},
913 conditions={'function': check_repo, 'method': ['GET']},
914 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
914 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
915
915
916 rmap.connect('pullrequest_repo_destinations',
916 rmap.connect('pullrequest_repo_destinations',
917 '/{repo_name}/pull-request/repo-destinations',
917 '/{repo_name}/pull-request/repo-destinations',
918 controller='pullrequests',
918 controller='pullrequests',
919 action='get_repo_destinations',
919 action='get_repo_destinations',
920 conditions={'function': check_repo, 'method': ['GET']},
920 conditions={'function': check_repo, 'method': ['GET']},
921 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
921 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
922
922
923 rmap.connect('pullrequest_show',
923 rmap.connect('pullrequest_show',
924 '/{repo_name}/pull-request/{pull_request_id}',
924 '/{repo_name}/pull-request/{pull_request_id}',
925 controller='pullrequests',
925 controller='pullrequests',
926 action='show', conditions={'function': check_repo,
926 action='show', conditions={'function': check_repo,
927 'method': ['GET']},
927 'method': ['GET']},
928 requirements=URL_NAME_REQUIREMENTS)
928 requirements=URL_NAME_REQUIREMENTS)
929
929
930 rmap.connect('pullrequest_update',
930 rmap.connect('pullrequest_update',
931 '/{repo_name}/pull-request/{pull_request_id}',
931 '/{repo_name}/pull-request/{pull_request_id}',
932 controller='pullrequests',
932 controller='pullrequests',
933 action='update', conditions={'function': check_repo,
933 action='update', conditions={'function': check_repo,
934 'method': ['PUT']},
934 'method': ['PUT']},
935 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
935 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
936
936
937 rmap.connect('pullrequest_merge',
937 rmap.connect('pullrequest_merge',
938 '/{repo_name}/pull-request/{pull_request_id}',
938 '/{repo_name}/pull-request/{pull_request_id}',
939 controller='pullrequests',
939 controller='pullrequests',
940 action='merge', conditions={'function': check_repo,
940 action='merge', conditions={'function': check_repo,
941 'method': ['POST']},
941 'method': ['POST']},
942 requirements=URL_NAME_REQUIREMENTS)
942 requirements=URL_NAME_REQUIREMENTS)
943
943
944 rmap.connect('pullrequest_delete',
944 rmap.connect('pullrequest_delete',
945 '/{repo_name}/pull-request/{pull_request_id}',
945 '/{repo_name}/pull-request/{pull_request_id}',
946 controller='pullrequests',
946 controller='pullrequests',
947 action='delete', conditions={'function': check_repo,
947 action='delete', conditions={'function': check_repo,
948 'method': ['DELETE']},
948 'method': ['DELETE']},
949 requirements=URL_NAME_REQUIREMENTS)
949 requirements=URL_NAME_REQUIREMENTS)
950
950
951 rmap.connect('pullrequest_show_all',
951 rmap.connect('pullrequest_show_all',
952 '/{repo_name}/pull-request',
952 '/{repo_name}/pull-request',
953 controller='pullrequests',
953 controller='pullrequests',
954 action='show_all', conditions={'function': check_repo,
954 action='show_all', conditions={'function': check_repo,
955 'method': ['GET']},
955 'method': ['GET']},
956 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
956 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
957
957
958 rmap.connect('pullrequest_comment',
958 rmap.connect('pullrequest_comment',
959 '/{repo_name}/pull-request-comment/{pull_request_id}',
959 '/{repo_name}/pull-request-comment/{pull_request_id}',
960 controller='pullrequests',
960 controller='pullrequests',
961 action='comment', conditions={'function': check_repo,
961 action='comment', conditions={'function': check_repo,
962 'method': ['POST']},
962 'method': ['POST']},
963 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
963 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
964
964
965 rmap.connect('pullrequest_comment_delete',
965 rmap.connect('pullrequest_comment_delete',
966 '/{repo_name}/pull-request-comment/{comment_id}/delete',
966 '/{repo_name}/pull-request-comment/{comment_id}/delete',
967 controller='pullrequests', action='delete_comment',
967 controller='pullrequests', action='delete_comment',
968 conditions={'function': check_repo, 'method': ['DELETE']},
968 conditions={'function': check_repo, 'method': ['DELETE']},
969 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
969 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
970
970
971 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
971 rmap.connect('summary_home_explicit', '/{repo_name}/summary',
972 controller='summary', conditions={'function': check_repo},
972 controller='summary', conditions={'function': check_repo},
973 requirements=URL_NAME_REQUIREMENTS)
973 requirements=URL_NAME_REQUIREMENTS)
974
974
975 rmap.connect('branches_home', '/{repo_name}/branches',
975 rmap.connect('branches_home', '/{repo_name}/branches',
976 controller='branches', conditions={'function': check_repo},
976 controller='branches', conditions={'function': check_repo},
977 requirements=URL_NAME_REQUIREMENTS)
977 requirements=URL_NAME_REQUIREMENTS)
978
978
979 rmap.connect('tags_home', '/{repo_name}/tags',
979 rmap.connect('tags_home', '/{repo_name}/tags',
980 controller='tags', conditions={'function': check_repo},
980 controller='tags', conditions={'function': check_repo},
981 requirements=URL_NAME_REQUIREMENTS)
981 requirements=URL_NAME_REQUIREMENTS)
982
982
983 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
983 rmap.connect('bookmarks_home', '/{repo_name}/bookmarks',
984 controller='bookmarks', conditions={'function': check_repo},
984 controller='bookmarks', conditions={'function': check_repo},
985 requirements=URL_NAME_REQUIREMENTS)
985 requirements=URL_NAME_REQUIREMENTS)
986
986
987 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
987 rmap.connect('changelog_home', '/{repo_name}/changelog', jsroute=True,
988 controller='changelog', conditions={'function': check_repo},
988 controller='changelog', conditions={'function': check_repo},
989 requirements=URL_NAME_REQUIREMENTS)
989 requirements=URL_NAME_REQUIREMENTS)
990
990
991 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
991 rmap.connect('changelog_summary_home', '/{repo_name}/changelog_summary',
992 controller='changelog', action='changelog_summary',
992 controller='changelog', action='changelog_summary',
993 conditions={'function': check_repo},
993 conditions={'function': check_repo},
994 requirements=URL_NAME_REQUIREMENTS)
994 requirements=URL_NAME_REQUIREMENTS)
995
995
996 rmap.connect('changelog_file_home',
996 rmap.connect('changelog_file_home',
997 '/{repo_name}/changelog/{revision}/{f_path}',
997 '/{repo_name}/changelog/{revision}/{f_path}',
998 controller='changelog', f_path=None,
998 controller='changelog', f_path=None,
999 conditions={'function': check_repo},
999 conditions={'function': check_repo},
1000 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1000 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1001
1001
1002 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1002 rmap.connect('changelog_details', '/{repo_name}/changelog_details/{cs}',
1003 controller='changelog', action='changelog_details',
1003 controller='changelog', action='changelog_details',
1004 conditions={'function': check_repo},
1004 conditions={'function': check_repo},
1005 requirements=URL_NAME_REQUIREMENTS)
1005 requirements=URL_NAME_REQUIREMENTS)
1006
1006
1007 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1007 rmap.connect('files_home', '/{repo_name}/files/{revision}/{f_path}',
1008 controller='files', revision='tip', f_path='',
1008 controller='files', revision='tip', f_path='',
1009 conditions={'function': check_repo},
1009 conditions={'function': check_repo},
1010 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1010 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1011
1011
1012 rmap.connect('files_home_simple_catchrev',
1012 rmap.connect('files_home_simple_catchrev',
1013 '/{repo_name}/files/{revision}',
1013 '/{repo_name}/files/{revision}',
1014 controller='files', revision='tip', f_path='',
1014 controller='files', revision='tip', f_path='',
1015 conditions={'function': check_repo},
1015 conditions={'function': check_repo},
1016 requirements=URL_NAME_REQUIREMENTS)
1016 requirements=URL_NAME_REQUIREMENTS)
1017
1017
1018 rmap.connect('files_home_simple_catchall',
1018 rmap.connect('files_home_simple_catchall',
1019 '/{repo_name}/files',
1019 '/{repo_name}/files',
1020 controller='files', revision='tip', f_path='',
1020 controller='files', revision='tip', f_path='',
1021 conditions={'function': check_repo},
1021 conditions={'function': check_repo},
1022 requirements=URL_NAME_REQUIREMENTS)
1022 requirements=URL_NAME_REQUIREMENTS)
1023
1023
1024 rmap.connect('files_history_home',
1024 rmap.connect('files_history_home',
1025 '/{repo_name}/history/{revision}/{f_path}',
1025 '/{repo_name}/history/{revision}/{f_path}',
1026 controller='files', action='history', revision='tip', f_path='',
1026 controller='files', action='history', revision='tip', f_path='',
1027 conditions={'function': check_repo},
1027 conditions={'function': check_repo},
1028 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1028 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1029
1029
1030 rmap.connect('files_authors_home',
1030 rmap.connect('files_authors_home',
1031 '/{repo_name}/authors/{revision}/{f_path}',
1031 '/{repo_name}/authors/{revision}/{f_path}',
1032 controller='files', action='authors', revision='tip', f_path='',
1032 controller='files', action='authors', revision='tip', f_path='',
1033 conditions={'function': check_repo},
1033 conditions={'function': check_repo},
1034 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1034 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1035
1035
1036 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1036 rmap.connect('files_diff_home', '/{repo_name}/diff/{f_path}',
1037 controller='files', action='diff', f_path='',
1037 controller='files', action='diff', f_path='',
1038 conditions={'function': check_repo},
1038 conditions={'function': check_repo},
1039 requirements=URL_NAME_REQUIREMENTS)
1039 requirements=URL_NAME_REQUIREMENTS)
1040
1040
1041 rmap.connect('files_diff_2way_home',
1041 rmap.connect('files_diff_2way_home',
1042 '/{repo_name}/diff-2way/{f_path}',
1042 '/{repo_name}/diff-2way/{f_path}',
1043 controller='files', action='diff_2way', f_path='',
1043 controller='files', action='diff_2way', f_path='',
1044 conditions={'function': check_repo},
1044 conditions={'function': check_repo},
1045 requirements=URL_NAME_REQUIREMENTS)
1045 requirements=URL_NAME_REQUIREMENTS)
1046
1046
1047 rmap.connect('files_rawfile_home',
1047 rmap.connect('files_rawfile_home',
1048 '/{repo_name}/rawfile/{revision}/{f_path}',
1048 '/{repo_name}/rawfile/{revision}/{f_path}',
1049 controller='files', action='rawfile', revision='tip',
1049 controller='files', action='rawfile', revision='tip',
1050 f_path='', conditions={'function': check_repo},
1050 f_path='', conditions={'function': check_repo},
1051 requirements=URL_NAME_REQUIREMENTS)
1051 requirements=URL_NAME_REQUIREMENTS)
1052
1052
1053 rmap.connect('files_raw_home',
1053 rmap.connect('files_raw_home',
1054 '/{repo_name}/raw/{revision}/{f_path}',
1054 '/{repo_name}/raw/{revision}/{f_path}',
1055 controller='files', action='raw', revision='tip', f_path='',
1055 controller='files', action='raw', revision='tip', f_path='',
1056 conditions={'function': check_repo},
1056 conditions={'function': check_repo},
1057 requirements=URL_NAME_REQUIREMENTS)
1057 requirements=URL_NAME_REQUIREMENTS)
1058
1058
1059 rmap.connect('files_render_home',
1059 rmap.connect('files_render_home',
1060 '/{repo_name}/render/{revision}/{f_path}',
1060 '/{repo_name}/render/{revision}/{f_path}',
1061 controller='files', action='index', revision='tip', f_path='',
1061 controller='files', action='index', revision='tip', f_path='',
1062 rendered=True, conditions={'function': check_repo},
1062 rendered=True, conditions={'function': check_repo},
1063 requirements=URL_NAME_REQUIREMENTS)
1063 requirements=URL_NAME_REQUIREMENTS)
1064
1064
1065 rmap.connect('files_annotate_home',
1065 rmap.connect('files_annotate_home',
1066 '/{repo_name}/annotate/{revision}/{f_path}',
1066 '/{repo_name}/annotate/{revision}/{f_path}',
1067 controller='files', action='index', revision='tip',
1067 controller='files', action='index', revision='tip',
1068 f_path='', annotate=True, conditions={'function': check_repo},
1068 f_path='', annotate=True, conditions={'function': check_repo},
1069 requirements=URL_NAME_REQUIREMENTS)
1069 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1070
1070
1071 rmap.connect('files_edit',
1071 rmap.connect('files_edit',
1072 '/{repo_name}/edit/{revision}/{f_path}',
1072 '/{repo_name}/edit/{revision}/{f_path}',
1073 controller='files', action='edit', revision='tip',
1073 controller='files', action='edit', revision='tip',
1074 f_path='',
1074 f_path='',
1075 conditions={'function': check_repo, 'method': ['POST']},
1075 conditions={'function': check_repo, 'method': ['POST']},
1076 requirements=URL_NAME_REQUIREMENTS)
1076 requirements=URL_NAME_REQUIREMENTS)
1077
1077
1078 rmap.connect('files_edit_home',
1078 rmap.connect('files_edit_home',
1079 '/{repo_name}/edit/{revision}/{f_path}',
1079 '/{repo_name}/edit/{revision}/{f_path}',
1080 controller='files', action='edit_home', revision='tip',
1080 controller='files', action='edit_home', revision='tip',
1081 f_path='', conditions={'function': check_repo},
1081 f_path='', conditions={'function': check_repo},
1082 requirements=URL_NAME_REQUIREMENTS)
1082 requirements=URL_NAME_REQUIREMENTS)
1083
1083
1084 rmap.connect('files_add',
1084 rmap.connect('files_add',
1085 '/{repo_name}/add/{revision}/{f_path}',
1085 '/{repo_name}/add/{revision}/{f_path}',
1086 controller='files', action='add', revision='tip',
1086 controller='files', action='add', revision='tip',
1087 f_path='',
1087 f_path='',
1088 conditions={'function': check_repo, 'method': ['POST']},
1088 conditions={'function': check_repo, 'method': ['POST']},
1089 requirements=URL_NAME_REQUIREMENTS)
1089 requirements=URL_NAME_REQUIREMENTS)
1090
1090
1091 rmap.connect('files_add_home',
1091 rmap.connect('files_add_home',
1092 '/{repo_name}/add/{revision}/{f_path}',
1092 '/{repo_name}/add/{revision}/{f_path}',
1093 controller='files', action='add_home', revision='tip',
1093 controller='files', action='add_home', revision='tip',
1094 f_path='', conditions={'function': check_repo},
1094 f_path='', conditions={'function': check_repo},
1095 requirements=URL_NAME_REQUIREMENTS)
1095 requirements=URL_NAME_REQUIREMENTS)
1096
1096
1097 rmap.connect('files_delete',
1097 rmap.connect('files_delete',
1098 '/{repo_name}/delete/{revision}/{f_path}',
1098 '/{repo_name}/delete/{revision}/{f_path}',
1099 controller='files', action='delete', revision='tip',
1099 controller='files', action='delete', revision='tip',
1100 f_path='',
1100 f_path='',
1101 conditions={'function': check_repo, 'method': ['POST']},
1101 conditions={'function': check_repo, 'method': ['POST']},
1102 requirements=URL_NAME_REQUIREMENTS)
1102 requirements=URL_NAME_REQUIREMENTS)
1103
1103
1104 rmap.connect('files_delete_home',
1104 rmap.connect('files_delete_home',
1105 '/{repo_name}/delete/{revision}/{f_path}',
1105 '/{repo_name}/delete/{revision}/{f_path}',
1106 controller='files', action='delete_home', revision='tip',
1106 controller='files', action='delete_home', revision='tip',
1107 f_path='', conditions={'function': check_repo},
1107 f_path='', conditions={'function': check_repo},
1108 requirements=URL_NAME_REQUIREMENTS)
1108 requirements=URL_NAME_REQUIREMENTS)
1109
1109
1110 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1110 rmap.connect('files_archive_home', '/{repo_name}/archive/{fname}',
1111 controller='files', action='archivefile',
1111 controller='files', action='archivefile',
1112 conditions={'function': check_repo},
1112 conditions={'function': check_repo},
1113 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1113 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1114
1114
1115 rmap.connect('files_nodelist_home',
1115 rmap.connect('files_nodelist_home',
1116 '/{repo_name}/nodelist/{revision}/{f_path}',
1116 '/{repo_name}/nodelist/{revision}/{f_path}',
1117 controller='files', action='nodelist',
1117 controller='files', action='nodelist',
1118 conditions={'function': check_repo},
1118 conditions={'function': check_repo},
1119 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1119 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1120
1120
1121 rmap.connect('files_nodetree_full',
1121 rmap.connect('files_nodetree_full',
1122 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1122 '/{repo_name}/nodetree_full/{commit_id}/{f_path}',
1123 controller='files', action='nodetree_full',
1123 controller='files', action='nodetree_full',
1124 conditions={'function': check_repo},
1124 conditions={'function': check_repo},
1125 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1125 requirements=URL_NAME_REQUIREMENTS, jsroute=True)
1126
1126
1127 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1127 rmap.connect('repo_fork_create_home', '/{repo_name}/fork',
1128 controller='forks', action='fork_create',
1128 controller='forks', action='fork_create',
1129 conditions={'function': check_repo, 'method': ['POST']},
1129 conditions={'function': check_repo, 'method': ['POST']},
1130 requirements=URL_NAME_REQUIREMENTS)
1130 requirements=URL_NAME_REQUIREMENTS)
1131
1131
1132 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1132 rmap.connect('repo_fork_home', '/{repo_name}/fork',
1133 controller='forks', action='fork',
1133 controller='forks', action='fork',
1134 conditions={'function': check_repo},
1134 conditions={'function': check_repo},
1135 requirements=URL_NAME_REQUIREMENTS)
1135 requirements=URL_NAME_REQUIREMENTS)
1136
1136
1137 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1137 rmap.connect('repo_forks_home', '/{repo_name}/forks',
1138 controller='forks', action='forks',
1138 controller='forks', action='forks',
1139 conditions={'function': check_repo},
1139 conditions={'function': check_repo},
1140 requirements=URL_NAME_REQUIREMENTS)
1140 requirements=URL_NAME_REQUIREMENTS)
1141
1141
1142 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1142 rmap.connect('repo_followers_home', '/{repo_name}/followers',
1143 controller='followers', action='followers',
1143 controller='followers', action='followers',
1144 conditions={'function': check_repo},
1144 conditions={'function': check_repo},
1145 requirements=URL_NAME_REQUIREMENTS)
1145 requirements=URL_NAME_REQUIREMENTS)
1146
1146
1147 # must be here for proper group/repo catching pattern
1147 # must be here for proper group/repo catching pattern
1148 _connect_with_slash(
1148 _connect_with_slash(
1149 rmap, 'repo_group_home', '/{group_name}',
1149 rmap, 'repo_group_home', '/{group_name}',
1150 controller='home', action='index_repo_group',
1150 controller='home', action='index_repo_group',
1151 conditions={'function': check_group},
1151 conditions={'function': check_group},
1152 requirements=URL_NAME_REQUIREMENTS)
1152 requirements=URL_NAME_REQUIREMENTS)
1153
1153
1154 # catch all, at the end
1154 # catch all, at the end
1155 _connect_with_slash(
1155 _connect_with_slash(
1156 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1156 rmap, 'summary_home', '/{repo_name}', jsroute=True,
1157 controller='summary', action='index',
1157 controller='summary', action='index',
1158 conditions={'function': check_repo},
1158 conditions={'function': check_repo},
1159 requirements=URL_NAME_REQUIREMENTS)
1159 requirements=URL_NAME_REQUIREMENTS)
1160
1160
1161 return rmap
1161 return rmap
1162
1162
1163
1163
1164 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1164 def _connect_with_slash(mapper, name, path, *args, **kwargs):
1165 """
1165 """
1166 Connect a route with an optional trailing slash in `path`.
1166 Connect a route with an optional trailing slash in `path`.
1167 """
1167 """
1168 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1168 mapper.connect(name + '_slash', path + '/', *args, **kwargs)
1169 mapper.connect(name, path, *args, **kwargs)
1169 mapper.connect(name, path, *args, **kwargs)
@@ -1,264 +1,270 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2012-2016 RhodeCode GmbH
3 # Copyright (C) 2012-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Compare controller for showing differences between two commits/refs/tags etc.
22 Compare controller for showing differences between two commits/refs/tags etc.
23 """
23 """
24
24
25 import logging
25 import logging
26
26
27 from webob.exc import HTTPBadRequest
27 from webob.exc import HTTPBadRequest
28 from pylons import request, tmpl_context as c, url
28 from pylons import request, tmpl_context as c, url
29 from pylons.controllers.util import redirect
29 from pylons.controllers.util import redirect
30 from pylons.i18n.translation import _
30 from pylons.i18n.translation import _
31
31
32 from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name
32 from rhodecode.controllers.utils import parse_path_ref, get_commit_from_ref_name
33 from rhodecode.lib import helpers as h
33 from rhodecode.lib import helpers as h
34 from rhodecode.lib import diffs, codeblocks
34 from rhodecode.lib import diffs, codeblocks
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
35 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
36 from rhodecode.lib.base import BaseRepoController, render
36 from rhodecode.lib.base import BaseRepoController, render
37 from rhodecode.lib.utils import safe_str
37 from rhodecode.lib.utils import safe_str
38 from rhodecode.lib.utils2 import safe_unicode, str2bool
38 from rhodecode.lib.utils2 import safe_unicode, str2bool
39 from rhodecode.lib.vcs.exceptions import (
39 from rhodecode.lib.vcs.exceptions import (
40 EmptyRepositoryError, RepositoryError, RepositoryRequirementError,
40 EmptyRepositoryError, RepositoryError, RepositoryRequirementError,
41 NodeDoesNotExistError)
41 NodeDoesNotExistError)
42 from rhodecode.model.db import Repository, ChangesetStatus
42 from rhodecode.model.db import Repository, ChangesetStatus
43
43
44 log = logging.getLogger(__name__)
44 log = logging.getLogger(__name__)
45
45
46
46
47 class CompareController(BaseRepoController):
47 class CompareController(BaseRepoController):
48
48
49 def __before__(self):
49 def __before__(self):
50 super(CompareController, self).__before__()
50 super(CompareController, self).__before__()
51
51
52 def _get_commit_or_redirect(
52 def _get_commit_or_redirect(
53 self, ref, ref_type, repo, redirect_after=True, partial=False):
53 self, ref, ref_type, repo, redirect_after=True, partial=False):
54 """
54 """
55 This is a safe way to get a commit. If an error occurs it
55 This is a safe way to get a commit. If an error occurs it
56 redirects to a commit with a proper message. If partial is set
56 redirects to a commit with a proper message. If partial is set
57 then it does not do redirect raise and throws an exception instead.
57 then it does not do redirect raise and throws an exception instead.
58 """
58 """
59 try:
59 try:
60 return get_commit_from_ref_name(repo, safe_str(ref), ref_type)
60 return get_commit_from_ref_name(repo, safe_str(ref), ref_type)
61 except EmptyRepositoryError:
61 except EmptyRepositoryError:
62 if not redirect_after:
62 if not redirect_after:
63 return repo.scm_instance().EMPTY_COMMIT
63 return repo.scm_instance().EMPTY_COMMIT
64 h.flash(h.literal(_('There are no commits yet')),
64 h.flash(h.literal(_('There are no commits yet')),
65 category='warning')
65 category='warning')
66 redirect(url('summary_home', repo_name=repo.repo_name))
66 redirect(url('summary_home', repo_name=repo.repo_name))
67
67
68 except RepositoryError as e:
68 except RepositoryError as e:
69 msg = safe_str(e)
69 msg = safe_str(e)
70 log.exception(msg)
70 log.exception(msg)
71 h.flash(msg, category='warning')
71 h.flash(msg, category='warning')
72 if not partial:
72 if not partial:
73 redirect(h.url('summary_home', repo_name=repo.repo_name))
73 redirect(h.url('summary_home', repo_name=repo.repo_name))
74 raise HTTPBadRequest()
74 raise HTTPBadRequest()
75
75
76 @LoginRequired()
76 @LoginRequired()
77 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
77 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
78 'repository.admin')
78 'repository.admin')
79 def index(self, repo_name):
79 def index(self, repo_name):
80 c.compare_home = True
80 c.compare_home = True
81 c.commit_ranges = []
81 c.commit_ranges = []
82 c.diffset = None
82 c.diffset = None
83 c.limited_diff = False
83 c.limited_diff = False
84 source_repo = c.rhodecode_db_repo.repo_name
84 source_repo = c.rhodecode_db_repo.repo_name
85 target_repo = request.GET.get('target_repo', source_repo)
85 target_repo = request.GET.get('target_repo', source_repo)
86 c.source_repo = Repository.get_by_repo_name(source_repo)
86 c.source_repo = Repository.get_by_repo_name(source_repo)
87 c.target_repo = Repository.get_by_repo_name(target_repo)
87 c.target_repo = Repository.get_by_repo_name(target_repo)
88 c.source_ref = c.target_ref = _('Select commit')
88 c.source_ref = c.target_ref = _('Select commit')
89 c.source_ref_type = ""
89 c.source_ref_type = ""
90 c.target_ref_type = ""
90 c.target_ref_type = ""
91 c.commit_statuses = ChangesetStatus.STATUSES
91 c.commit_statuses = ChangesetStatus.STATUSES
92 c.preview_mode = False
92 c.preview_mode = False
93 c.file_path = None
93 return render('compare/compare_diff.html')
94 return render('compare/compare_diff.html')
94
95
95 @LoginRequired()
96 @LoginRequired()
96 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
97 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
97 'repository.admin')
98 'repository.admin')
98 def compare(self, repo_name, source_ref_type, source_ref,
99 def compare(self, repo_name, source_ref_type, source_ref,
99 target_ref_type, target_ref):
100 target_ref_type, target_ref):
100 # source_ref will be evaluated in source_repo
101 # source_ref will be evaluated in source_repo
101 source_repo_name = c.rhodecode_db_repo.repo_name
102 source_repo_name = c.rhodecode_db_repo.repo_name
102 source_path, source_id = parse_path_ref(source_ref)
103 source_path, source_id = parse_path_ref(source_ref)
103
104
104 # target_ref will be evaluated in target_repo
105 # target_ref will be evaluated in target_repo
105 target_repo_name = request.GET.get('target_repo', source_repo_name)
106 target_repo_name = request.GET.get('target_repo', source_repo_name)
106 target_path, target_id = parse_path_ref(target_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 c.commit_statuses = ChangesetStatus.STATUSES
111 c.commit_statuses = ChangesetStatus.STATUSES
109
112
110 # if merge is True
113 # if merge is True
111 # Show what changes since the shared ancestor commit of target/source
114 # Show what changes since the shared ancestor commit of target/source
112 # the source would get if it was merged with target. Only commits
115 # the source would get if it was merged with target. Only commits
113 # which are in target but not in source will be shown.
116 # which are in target but not in source will be shown.
114 merge = str2bool(request.GET.get('merge'))
117 merge = str2bool(request.GET.get('merge'))
115 # if merge is False
118 # if merge is False
116 # Show a raw diff of source/target refs even if no ancestor exists
119 # Show a raw diff of source/target refs even if no ancestor exists
117
120
118
119 # c.fulldiff disables cut_off_limit
121 # c.fulldiff disables cut_off_limit
120 c.fulldiff = str2bool(request.GET.get('fulldiff'))
122 c.fulldiff = str2bool(request.GET.get('fulldiff'))
121
123
122 # if partial, returns just compare_commits.html (commits log)
124 # if partial, returns just compare_commits.html (commits log)
123 partial = request.is_xhr
125 partial = request.is_xhr
124
126
125 # swap url for compare_diff page
127 # swap url for compare_diff page
126 c.swap_url = h.url(
128 c.swap_url = h.url(
127 'compare_url',
129 'compare_url',
128 repo_name=target_repo_name,
130 repo_name=target_repo_name,
129 source_ref_type=target_ref_type,
131 source_ref_type=target_ref_type,
130 source_ref=target_ref,
132 source_ref=target_ref,
131 target_repo=source_repo_name,
133 target_repo=source_repo_name,
132 target_ref_type=source_ref_type,
134 target_ref_type=source_ref_type,
133 target_ref=source_ref,
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 source_repo = Repository.get_by_repo_name(source_repo_name)
139 source_repo = Repository.get_by_repo_name(source_repo_name)
137 target_repo = Repository.get_by_repo_name(target_repo_name)
140 target_repo = Repository.get_by_repo_name(target_repo_name)
138
141
139 if source_repo is None:
142 if source_repo is None:
140 msg = _('Could not find the original repo: %(repo)s') % {
143 msg = _('Could not find the original repo: %(repo)s') % {
141 'repo': source_repo}
144 'repo': source_repo}
142
145
143 log.error(msg)
146 log.error(msg)
144 h.flash(msg, category='error')
147 h.flash(msg, category='error')
145 return redirect(url('compare_home', repo_name=c.repo_name))
148 return redirect(url('compare_home', repo_name=c.repo_name))
146
149
147 if target_repo is None:
150 if target_repo is None:
148 msg = _('Could not find the other repo: %(repo)s') % {
151 msg = _('Could not find the other repo: %(repo)s') % {
149 'repo': target_repo_name}
152 'repo': target_repo_name}
150 log.error(msg)
153 log.error(msg)
151 h.flash(msg, category='error')
154 h.flash(msg, category='error')
152 return redirect(url('compare_home', repo_name=c.repo_name))
155 return redirect(url('compare_home', repo_name=c.repo_name))
153
156
154 source_alias = source_repo.scm_instance().alias
157 source_scm = source_repo.scm_instance()
155 target_alias = target_repo.scm_instance().alias
158 target_scm = target_repo.scm_instance()
159
160 source_alias = source_scm.alias
161 target_alias = target_scm.alias
156 if source_alias != target_alias:
162 if source_alias != target_alias:
157 msg = _('The comparison of two different kinds of remote repos '
163 msg = _('The comparison of two different kinds of remote repos '
158 'is not available')
164 'is not available')
159 log.error(msg)
165 log.error(msg)
160 h.flash(msg, category='error')
166 h.flash(msg, category='error')
161 return redirect(url('compare_home', repo_name=c.repo_name))
167 return redirect(url('compare_home', repo_name=c.repo_name))
162
168
163 source_commit = self._get_commit_or_redirect(
169 source_commit = self._get_commit_or_redirect(
164 ref=source_id, ref_type=source_ref_type, repo=source_repo,
170 ref=source_id, ref_type=source_ref_type, repo=source_repo,
165 partial=partial)
171 partial=partial)
166 target_commit = self._get_commit_or_redirect(
172 target_commit = self._get_commit_or_redirect(
167 ref=target_id, ref_type=target_ref_type, repo=target_repo,
173 ref=target_id, ref_type=target_ref_type, repo=target_repo,
168 partial=partial)
174 partial=partial)
169
175
170 c.compare_home = False
176 c.compare_home = False
171 c.source_repo = source_repo
177 c.source_repo = source_repo
172 c.target_repo = target_repo
178 c.target_repo = target_repo
173 c.source_ref = source_ref
179 c.source_ref = source_ref
174 c.target_ref = target_ref
180 c.target_ref = target_ref
175 c.source_ref_type = source_ref_type
181 c.source_ref_type = source_ref_type
176 c.target_ref_type = target_ref_type
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 pre_load = ["author", "branch", "date", "message"]
184 pre_load = ["author", "branch", "date", "message"]
182 c.ancestor = None
185 c.ancestor = None
183 try:
186 try:
184 c.commit_ranges = source_scm.compare(
187 c.commit_ranges = source_scm.compare(
185 source_commit.raw_id, target_commit.raw_id,
188 source_commit.raw_id, target_commit.raw_id,
186 target_scm, merge, pre_load=pre_load)
189 target_scm, merge, pre_load=pre_load)
187 if merge:
190 if merge:
188 c.ancestor = source_scm.get_common_ancestor(
191 c.ancestor = source_scm.get_common_ancestor(
189 source_commit.raw_id, target_commit.raw_id, target_scm)
192 source_commit.raw_id, target_commit.raw_id, target_scm)
190 except RepositoryRequirementError:
193 except RepositoryRequirementError:
191 msg = _('Could not compare repos with different '
194 msg = _('Could not compare repos with different '
192 'large file settings')
195 'large file settings')
193 log.error(msg)
196 log.error(msg)
194 if partial:
197 if partial:
195 return msg
198 return msg
196 h.flash(msg, category='error')
199 h.flash(msg, category='error')
197 return redirect(url('compare_home', repo_name=c.repo_name))
200 return redirect(url('compare_home', repo_name=c.repo_name))
198
201
199 c.statuses = c.rhodecode_db_repo.statuses(
202 c.statuses = c.rhodecode_db_repo.statuses(
200 [x.raw_id for x in c.commit_ranges])
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 if not c.ancestor:
206 if not c.ancestor:
204 return '' # cannot merge if there is no ancestor
207 return '' # cannot merge if there is no ancestor
205 return render('compare/compare_commits.html')
208 return render('compare/compare_commits.html')
206
209
207 if c.ancestor:
210 if c.ancestor:
208 # case we want a simple diff without incoming commits,
211 # case we want a simple diff without incoming commits,
209 # previewing what will be merged.
212 # previewing what will be merged.
210 # Make the diff on target repo (which is known to have target_ref)
213 # Make the diff on target repo (which is known to have target_ref)
211 log.debug('Using ancestor %s as source_ref instead of %s'
214 log.debug('Using ancestor %s as source_ref instead of %s'
212 % (c.ancestor, source_ref))
215 % (c.ancestor, source_ref))
213 source_repo = target_repo
216 source_repo = target_repo
214 source_commit = target_repo.get_commit(commit_id=c.ancestor)
217 source_commit = target_repo.get_commit(commit_id=c.ancestor)
215
218
216 # diff_limit will cut off the whole diff if the limit is applied
219 # diff_limit will cut off the whole diff if the limit is applied
217 # otherwise it will just hide the big files from the front-end
220 # otherwise it will just hide the big files from the front-end
218 diff_limit = self.cut_off_limit_diff
221 diff_limit = self.cut_off_limit_diff
219 file_limit = self.cut_off_limit_file
222 file_limit = self.cut_off_limit_file
220
223
221 log.debug('calculating diff between '
224 log.debug('calculating diff between '
222 'source_ref:%s and target_ref:%s for repo `%s`',
225 'source_ref:%s and target_ref:%s for repo `%s`',
223 source_commit, target_commit,
226 source_commit, target_commit,
224 safe_unicode(source_repo.scm_instance().path))
227 safe_unicode(source_repo.scm_instance().path))
225
228
226 if source_commit.repository != target_commit.repository:
229 if source_commit.repository != target_commit.repository:
227 msg = _(
230 msg = _(
228 "Repositories unrelated. "
231 "Repositories unrelated. "
229 "Cannot compare commit %(commit1)s from repository %(repo1)s "
232 "Cannot compare commit %(commit1)s from repository %(repo1)s "
230 "with commit %(commit2)s from repository %(repo2)s.") % {
233 "with commit %(commit2)s from repository %(repo2)s.") % {
231 'commit1': h.show_id(source_commit),
234 'commit1': h.show_id(source_commit),
232 'repo1': source_repo.repo_name,
235 'repo1': source_repo.repo_name,
233 'commit2': h.show_id(target_commit),
236 'commit2': h.show_id(target_commit),
234 'repo2': target_repo.repo_name,
237 'repo2': target_repo.repo_name,
235 }
238 }
236 h.flash(msg, category='error')
239 h.flash(msg, category='error')
237 raise HTTPBadRequest()
240 raise HTTPBadRequest()
238
241
239 txtdiff = source_repo.scm_instance().get_diff(
242 txtdiff = source_repo.scm_instance().get_diff(
240 commit1=source_commit, commit2=target_commit,
243 commit1=source_commit, commit2=target_commit,
241 path1=source_path, path=target_path)
244 path=target_path, path1=source_path)
245
242 diff_processor = diffs.DiffProcessor(
246 diff_processor = diffs.DiffProcessor(
243 txtdiff, format='newdiff', diff_limit=diff_limit,
247 txtdiff, format='newdiff', diff_limit=diff_limit,
244 file_limit=file_limit, show_full_diff=c.fulldiff)
248 file_limit=file_limit, show_full_diff=c.fulldiff)
245 _parsed = diff_processor.prepare()
249 _parsed = diff_processor.prepare()
246
250
247 def _node_getter(commit):
251 def _node_getter(commit):
248 """ Returns a function that returns a node for a commit or None """
252 """ Returns a function that returns a node for a commit or None """
249 def get_node(fname):
253 def get_node(fname):
250 try:
254 try:
251 return commit.get_node(fname)
255 return commit.get_node(fname)
252 except NodeDoesNotExistError:
256 except NodeDoesNotExistError:
253 return None
257 return None
254 return get_node
258 return get_node
255
259
256 c.diffset = codeblocks.DiffSet(
260 c.diffset = codeblocks.DiffSet(
257 repo_name=source_repo.repo_name,
261 repo_name=source_repo.repo_name,
258 source_node_getter=_node_getter(source_commit),
262 source_node_getter=_node_getter(source_commit),
259 target_node_getter=_node_getter(target_commit),
263 target_node_getter=_node_getter(target_commit),
260 ).render_patchset(_parsed, source_ref, target_ref)
264 ).render_patchset(_parsed, source_ref, target_ref)
261
265
262 c.preview_mode = merge
266 c.preview_mode = merge
267 c.source_commit = source_commit
268 c.target_commit = target_commit
263
269
264 return render('compare/compare_diff.html')
270 return render('compare/compare_diff.html')
@@ -1,1127 +1,1061 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Files controller for RhodeCode Enterprise
22 Files controller for RhodeCode Enterprise
23 """
23 """
24
24
25 import itertools
25 import itertools
26 import logging
26 import logging
27 import os
27 import os
28 import shutil
28 import shutil
29 import tempfile
29 import tempfile
30
30
31 from pylons import request, response, tmpl_context as c, url
31 from pylons import request, response, tmpl_context as c, url
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from pylons.controllers.util import redirect
33 from pylons.controllers.util import redirect
34 from webob.exc import HTTPNotFound, HTTPBadRequest
34 from webob.exc import HTTPNotFound, HTTPBadRequest
35
35
36 from rhodecode.controllers.utils import parse_path_ref
36 from rhodecode.controllers.utils import parse_path_ref
37 from rhodecode.lib import diffs, helpers as h, caches
37 from rhodecode.lib import diffs, helpers as h, caches
38 from rhodecode.lib.compat import OrderedDict
38 from rhodecode.lib.compat import OrderedDict
39 from rhodecode.lib.codeblocks import (
39 from rhodecode.lib.codeblocks import (
40 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
40 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
41 from rhodecode.lib.utils import jsonify, action_logger
41 from rhodecode.lib.utils import jsonify, action_logger
42 from rhodecode.lib.utils2 import (
42 from rhodecode.lib.utils2 import (
43 convert_line_endings, detect_mode, safe_str, str2bool)
43 convert_line_endings, detect_mode, safe_str, str2bool)
44 from rhodecode.lib.auth import (
44 from rhodecode.lib.auth import (
45 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired, XHRRequired)
45 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired, XHRRequired)
46 from rhodecode.lib.base import BaseRepoController, render
46 from rhodecode.lib.base import BaseRepoController, render
47 from rhodecode.lib.vcs import path as vcspath
47 from rhodecode.lib.vcs import path as vcspath
48 from rhodecode.lib.vcs.backends.base import EmptyCommit
48 from rhodecode.lib.vcs.backends.base import EmptyCommit
49 from rhodecode.lib.vcs.conf import settings
49 from rhodecode.lib.vcs.conf import settings
50 from rhodecode.lib.vcs.exceptions import (
50 from rhodecode.lib.vcs.exceptions import (
51 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
51 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
52 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
52 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
53 NodeDoesNotExistError, CommitError, NodeError)
53 NodeDoesNotExistError, CommitError, NodeError)
54 from rhodecode.lib.vcs.nodes import FileNode
54 from rhodecode.lib.vcs.nodes import FileNode
55
55
56 from rhodecode.model.repo import RepoModel
56 from rhodecode.model.repo import RepoModel
57 from rhodecode.model.scm import ScmModel
57 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.db import Repository
58 from rhodecode.model.db import Repository
59
59
60 from rhodecode.controllers.changeset import (
60 from rhodecode.controllers.changeset import (
61 _ignorews_url, _context_url, get_line_ctx, get_ignore_ws)
61 _ignorews_url, _context_url, get_line_ctx, get_ignore_ws)
62 from rhodecode.lib.exceptions import NonRelativePathError
62 from rhodecode.lib.exceptions import NonRelativePathError
63
63
64 log = logging.getLogger(__name__)
64 log = logging.getLogger(__name__)
65
65
66
66
67 class FilesController(BaseRepoController):
67 class FilesController(BaseRepoController):
68
68
69 def __before__(self):
69 def __before__(self):
70 super(FilesController, self).__before__()
70 super(FilesController, self).__before__()
71 c.cut_off_limit = self.cut_off_limit_file
71 c.cut_off_limit = self.cut_off_limit_file
72
72
73 def _get_default_encoding(self):
73 def _get_default_encoding(self):
74 enc_list = getattr(c, 'default_encodings', [])
74 enc_list = getattr(c, 'default_encodings', [])
75 return enc_list[0] if enc_list else 'UTF-8'
75 return enc_list[0] if enc_list else 'UTF-8'
76
76
77 def __get_commit_or_redirect(self, commit_id, repo_name,
77 def __get_commit_or_redirect(self, commit_id, repo_name,
78 redirect_after=True):
78 redirect_after=True):
79 """
79 """
80 This is a safe way to get commit. If an error occurs it redirects to
80 This is a safe way to get commit. If an error occurs it redirects to
81 tip with proper message
81 tip with proper message
82
82
83 :param commit_id: id of commit to fetch
83 :param commit_id: id of commit to fetch
84 :param repo_name: repo name to redirect after
84 :param repo_name: repo name to redirect after
85 :param redirect_after: toggle redirection
85 :param redirect_after: toggle redirection
86 """
86 """
87 try:
87 try:
88 return c.rhodecode_repo.get_commit(commit_id)
88 return c.rhodecode_repo.get_commit(commit_id)
89 except EmptyRepositoryError:
89 except EmptyRepositoryError:
90 if not redirect_after:
90 if not redirect_after:
91 return None
91 return None
92 url_ = url('files_add_home',
92 url_ = url('files_add_home',
93 repo_name=c.repo_name,
93 repo_name=c.repo_name,
94 revision=0, f_path='', anchor='edit')
94 revision=0, f_path='', anchor='edit')
95 if h.HasRepoPermissionAny(
95 if h.HasRepoPermissionAny(
96 'repository.write', 'repository.admin')(c.repo_name):
96 'repository.write', 'repository.admin')(c.repo_name):
97 add_new = h.link_to(
97 add_new = h.link_to(
98 _('Click here to add a new file.'),
98 _('Click here to add a new file.'),
99 url_, class_="alert-link")
99 url_, class_="alert-link")
100 else:
100 else:
101 add_new = ""
101 add_new = ""
102 h.flash(h.literal(
102 h.flash(h.literal(
103 _('There are no files yet. %s') % add_new), category='warning')
103 _('There are no files yet. %s') % add_new), category='warning')
104 redirect(h.url('summary_home', repo_name=repo_name))
104 redirect(h.url('summary_home', repo_name=repo_name))
105 except (CommitDoesNotExistError, LookupError):
105 except (CommitDoesNotExistError, LookupError):
106 msg = _('No such commit exists for this repository')
106 msg = _('No such commit exists for this repository')
107 h.flash(msg, category='error')
107 h.flash(msg, category='error')
108 raise HTTPNotFound()
108 raise HTTPNotFound()
109 except RepositoryError as e:
109 except RepositoryError as e:
110 h.flash(safe_str(e), category='error')
110 h.flash(safe_str(e), category='error')
111 raise HTTPNotFound()
111 raise HTTPNotFound()
112
112
113 def __get_filenode_or_redirect(self, repo_name, commit, path):
113 def __get_filenode_or_redirect(self, repo_name, commit, path):
114 """
114 """
115 Returns file_node, if error occurs or given path is directory,
115 Returns file_node, if error occurs or given path is directory,
116 it'll redirect to top level path
116 it'll redirect to top level path
117
117
118 :param repo_name: repo_name
118 :param repo_name: repo_name
119 :param commit: given commit
119 :param commit: given commit
120 :param path: path to lookup
120 :param path: path to lookup
121 """
121 """
122 try:
122 try:
123 file_node = commit.get_node(path)
123 file_node = commit.get_node(path)
124 if file_node.is_dir():
124 if file_node.is_dir():
125 raise RepositoryError('The given path is a directory')
125 raise RepositoryError('The given path is a directory')
126 except CommitDoesNotExistError:
126 except CommitDoesNotExistError:
127 msg = _('No such commit exists for this repository')
127 msg = _('No such commit exists for this repository')
128 log.exception(msg)
128 log.exception(msg)
129 h.flash(msg, category='error')
129 h.flash(msg, category='error')
130 raise HTTPNotFound()
130 raise HTTPNotFound()
131 except RepositoryError as e:
131 except RepositoryError as e:
132 h.flash(safe_str(e), category='error')
132 h.flash(safe_str(e), category='error')
133 raise HTTPNotFound()
133 raise HTTPNotFound()
134
134
135 return file_node
135 return file_node
136
136
137 def __get_tree_cache_manager(self, repo_name, namespace_type):
137 def __get_tree_cache_manager(self, repo_name, namespace_type):
138 _namespace = caches.get_repo_namespace_key(namespace_type, repo_name)
138 _namespace = caches.get_repo_namespace_key(namespace_type, repo_name)
139 return caches.get_cache_manager('repo_cache_long', _namespace)
139 return caches.get_cache_manager('repo_cache_long', _namespace)
140
140
141 def _get_tree_at_commit(self, repo_name, commit_id, f_path,
141 def _get_tree_at_commit(self, repo_name, commit_id, f_path,
142 full_load=False, force=False):
142 full_load=False, force=False):
143 def _cached_tree():
143 def _cached_tree():
144 log.debug('Generating cached file tree for %s, %s, %s',
144 log.debug('Generating cached file tree for %s, %s, %s',
145 repo_name, commit_id, f_path)
145 repo_name, commit_id, f_path)
146 c.full_load = full_load
146 c.full_load = full_load
147 return render('files/files_browser_tree.html')
147 return render('files/files_browser_tree.html')
148
148
149 cache_manager = self.__get_tree_cache_manager(
149 cache_manager = self.__get_tree_cache_manager(
150 repo_name, caches.FILE_TREE)
150 repo_name, caches.FILE_TREE)
151
151
152 cache_key = caches.compute_key_from_params(
152 cache_key = caches.compute_key_from_params(
153 repo_name, commit_id, f_path)
153 repo_name, commit_id, f_path)
154
154
155 if force:
155 if force:
156 # we want to force recompute of caches
156 # we want to force recompute of caches
157 cache_manager.remove_value(cache_key)
157 cache_manager.remove_value(cache_key)
158
158
159 return cache_manager.get(cache_key, createfunc=_cached_tree)
159 return cache_manager.get(cache_key, createfunc=_cached_tree)
160
160
161 def _get_nodelist_at_commit(self, repo_name, commit_id, f_path):
161 def _get_nodelist_at_commit(self, repo_name, commit_id, f_path):
162 def _cached_nodes():
162 def _cached_nodes():
163 log.debug('Generating cached nodelist for %s, %s, %s',
163 log.debug('Generating cached nodelist for %s, %s, %s',
164 repo_name, commit_id, f_path)
164 repo_name, commit_id, f_path)
165 _d, _f = ScmModel().get_nodes(
165 _d, _f = ScmModel().get_nodes(
166 repo_name, commit_id, f_path, flat=False)
166 repo_name, commit_id, f_path, flat=False)
167 return _d + _f
167 return _d + _f
168
168
169 cache_manager = self.__get_tree_cache_manager(
169 cache_manager = self.__get_tree_cache_manager(
170 repo_name, caches.FILE_SEARCH_TREE_META)
170 repo_name, caches.FILE_SEARCH_TREE_META)
171
171
172 cache_key = caches.compute_key_from_params(
172 cache_key = caches.compute_key_from_params(
173 repo_name, commit_id, f_path)
173 repo_name, commit_id, f_path)
174 return cache_manager.get(cache_key, createfunc=_cached_nodes)
174 return cache_manager.get(cache_key, createfunc=_cached_nodes)
175
175
176 @LoginRequired()
176 @LoginRequired()
177 @HasRepoPermissionAnyDecorator(
177 @HasRepoPermissionAnyDecorator(
178 'repository.read', 'repository.write', 'repository.admin')
178 'repository.read', 'repository.write', 'repository.admin')
179 def index(
179 def index(
180 self, repo_name, revision, f_path, annotate=False, rendered=False):
180 self, repo_name, revision, f_path, annotate=False, rendered=False):
181 commit_id = revision
181 commit_id = revision
182
182
183 # redirect to given commit_id from form if given
183 # redirect to given commit_id from form if given
184 get_commit_id = request.GET.get('at_rev', None)
184 get_commit_id = request.GET.get('at_rev', None)
185 if get_commit_id:
185 if get_commit_id:
186 self.__get_commit_or_redirect(get_commit_id, repo_name)
186 self.__get_commit_or_redirect(get_commit_id, repo_name)
187
187
188 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
188 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
189 c.branch = request.GET.get('branch', None)
189 c.branch = request.GET.get('branch', None)
190 c.f_path = f_path
190 c.f_path = f_path
191 c.annotate = annotate
191 c.annotate = annotate
192 # default is false, but .rst/.md files later are autorendered, we can
192 # default is false, but .rst/.md files later are autorendered, we can
193 # overwrite autorendering by setting this GET flag
193 # overwrite autorendering by setting this GET flag
194 c.renderer = rendered or not request.GET.get('no-render', False)
194 c.renderer = rendered or not request.GET.get('no-render', False)
195
195
196 # prev link
196 # prev link
197 try:
197 try:
198 prev_commit = c.commit.prev(c.branch)
198 prev_commit = c.commit.prev(c.branch)
199 c.prev_commit = prev_commit
199 c.prev_commit = prev_commit
200 c.url_prev = url('files_home', repo_name=c.repo_name,
200 c.url_prev = url('files_home', repo_name=c.repo_name,
201 revision=prev_commit.raw_id, f_path=f_path)
201 revision=prev_commit.raw_id, f_path=f_path)
202 if c.branch:
202 if c.branch:
203 c.url_prev += '?branch=%s' % c.branch
203 c.url_prev += '?branch=%s' % c.branch
204 except (CommitDoesNotExistError, VCSError):
204 except (CommitDoesNotExistError, VCSError):
205 c.url_prev = '#'
205 c.url_prev = '#'
206 c.prev_commit = EmptyCommit()
206 c.prev_commit = EmptyCommit()
207
207
208 # next link
208 # next link
209 try:
209 try:
210 next_commit = c.commit.next(c.branch)
210 next_commit = c.commit.next(c.branch)
211 c.next_commit = next_commit
211 c.next_commit = next_commit
212 c.url_next = url('files_home', repo_name=c.repo_name,
212 c.url_next = url('files_home', repo_name=c.repo_name,
213 revision=next_commit.raw_id, f_path=f_path)
213 revision=next_commit.raw_id, f_path=f_path)
214 if c.branch:
214 if c.branch:
215 c.url_next += '?branch=%s' % c.branch
215 c.url_next += '?branch=%s' % c.branch
216 except (CommitDoesNotExistError, VCSError):
216 except (CommitDoesNotExistError, VCSError):
217 c.url_next = '#'
217 c.url_next = '#'
218 c.next_commit = EmptyCommit()
218 c.next_commit = EmptyCommit()
219
219
220 # files or dirs
220 # files or dirs
221 try:
221 try:
222 c.file = c.commit.get_node(f_path)
222 c.file = c.commit.get_node(f_path)
223 c.file_author = True
223 c.file_author = True
224 c.file_tree = ''
224 c.file_tree = ''
225 if c.file.is_file():
225 if c.file.is_file():
226 c.file_source_page = 'true'
226 c.file_source_page = 'true'
227 c.file_last_commit = c.file.last_commit
227 c.file_last_commit = c.file.last_commit
228 if c.file.size < self.cut_off_limit_file:
228 if c.file.size < self.cut_off_limit_file:
229 if c.annotate: # annotation has precedence over renderer
229 if c.annotate: # annotation has precedence over renderer
230 c.annotated_lines = filenode_as_annotated_lines_tokens(
230 c.annotated_lines = filenode_as_annotated_lines_tokens(
231 c.file
231 c.file
232 )
232 )
233 else:
233 else:
234 c.renderer = (
234 c.renderer = (
235 c.renderer and h.renderer_from_filename(c.file.path)
235 c.renderer and h.renderer_from_filename(c.file.path)
236 )
236 )
237 if not c.renderer:
237 if not c.renderer:
238 c.lines = filenode_as_lines_tokens(c.file)
238 c.lines = filenode_as_lines_tokens(c.file)
239
239
240 c.on_branch_head = self._is_valid_head(
240 c.on_branch_head = self._is_valid_head(
241 commit_id, c.rhodecode_repo)
241 commit_id, c.rhodecode_repo)
242 c.branch_or_raw_id = c.commit.branch or c.commit.raw_id
242 c.branch_or_raw_id = c.commit.branch or c.commit.raw_id
243
243
244 author = c.file_last_commit.author
244 author = c.file_last_commit.author
245 c.authors = [(h.email(author),
245 c.authors = [(h.email(author),
246 h.person(author, 'username_or_name_or_email'))]
246 h.person(author, 'username_or_name_or_email'))]
247 else:
247 else:
248 c.file_source_page = 'false'
248 c.file_source_page = 'false'
249 c.authors = []
249 c.authors = []
250 c.file_tree = self._get_tree_at_commit(
250 c.file_tree = self._get_tree_at_commit(
251 repo_name, c.commit.raw_id, f_path)
251 repo_name, c.commit.raw_id, f_path)
252
252
253 except RepositoryError as e:
253 except RepositoryError as e:
254 h.flash(safe_str(e), category='error')
254 h.flash(safe_str(e), category='error')
255 raise HTTPNotFound()
255 raise HTTPNotFound()
256
256
257 if request.environ.get('HTTP_X_PJAX'):
257 if request.environ.get('HTTP_X_PJAX'):
258 return render('files/files_pjax.html')
258 return render('files/files_pjax.html')
259
259
260 return render('files/files.html')
260 return render('files/files.html')
261
261
262 @LoginRequired()
262 @LoginRequired()
263 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
263 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
264 'repository.admin')
264 'repository.admin')
265 @jsonify
265 @jsonify
266 def history(self, repo_name, revision, f_path):
266 def history(self, repo_name, revision, f_path):
267 commit = self.__get_commit_or_redirect(revision, repo_name)
267 commit = self.__get_commit_or_redirect(revision, repo_name)
268 f_path = f_path
268 f_path = f_path
269 _file = commit.get_node(f_path)
269 _file = commit.get_node(f_path)
270 if _file.is_file():
270 if _file.is_file():
271 file_history, _hist = self._get_node_history(commit, f_path)
271 file_history, _hist = self._get_node_history(commit, f_path)
272
272
273 res = []
273 res = []
274 for obj in file_history:
274 for obj in file_history:
275 res.append({
275 res.append({
276 'text': obj[1],
276 'text': obj[1],
277 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]]
277 'children': [{'id': o[0], 'text': o[1]} for o in obj[0]]
278 })
278 })
279
279
280 data = {
280 data = {
281 'more': False,
281 'more': False,
282 'results': res
282 'results': res
283 }
283 }
284 return data
284 return data
285
285
286 @LoginRequired()
286 @LoginRequired()
287 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
287 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
288 'repository.admin')
288 'repository.admin')
289 def authors(self, repo_name, revision, f_path):
289 def authors(self, repo_name, revision, f_path):
290 commit = self.__get_commit_or_redirect(revision, repo_name)
290 commit = self.__get_commit_or_redirect(revision, repo_name)
291 file_node = commit.get_node(f_path)
291 file_node = commit.get_node(f_path)
292 if file_node.is_file():
292 if file_node.is_file():
293 c.file_last_commit = file_node.last_commit
293 c.file_last_commit = file_node.last_commit
294 if request.GET.get('annotate') == '1':
294 if request.GET.get('annotate') == '1':
295 # use _hist from annotation if annotation mode is on
295 # use _hist from annotation if annotation mode is on
296 commit_ids = set(x[1] for x in file_node.annotate)
296 commit_ids = set(x[1] for x in file_node.annotate)
297 _hist = (
297 _hist = (
298 c.rhodecode_repo.get_commit(commit_id)
298 c.rhodecode_repo.get_commit(commit_id)
299 for commit_id in commit_ids)
299 for commit_id in commit_ids)
300 else:
300 else:
301 _f_history, _hist = self._get_node_history(commit, f_path)
301 _f_history, _hist = self._get_node_history(commit, f_path)
302 c.file_author = False
302 c.file_author = False
303 c.authors = []
303 c.authors = []
304 for author in set(commit.author for commit in _hist):
304 for author in set(commit.author for commit in _hist):
305 c.authors.append((
305 c.authors.append((
306 h.email(author),
306 h.email(author),
307 h.person(author, 'username_or_name_or_email')))
307 h.person(author, 'username_or_name_or_email')))
308 return render('files/file_authors_box.html')
308 return render('files/file_authors_box.html')
309
309
310 @LoginRequired()
310 @LoginRequired()
311 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
311 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
312 'repository.admin')
312 'repository.admin')
313 def rawfile(self, repo_name, revision, f_path):
313 def rawfile(self, repo_name, revision, f_path):
314 """
314 """
315 Action for download as raw
315 Action for download as raw
316 """
316 """
317 commit = self.__get_commit_or_redirect(revision, repo_name)
317 commit = self.__get_commit_or_redirect(revision, repo_name)
318 file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path)
318 file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path)
319
319
320 response.content_disposition = 'attachment; filename=%s' % \
320 response.content_disposition = 'attachment; filename=%s' % \
321 safe_str(f_path.split(Repository.NAME_SEP)[-1])
321 safe_str(f_path.split(Repository.NAME_SEP)[-1])
322
322
323 response.content_type = file_node.mimetype
323 response.content_type = file_node.mimetype
324 charset = self._get_default_encoding()
324 charset = self._get_default_encoding()
325 if charset:
325 if charset:
326 response.charset = charset
326 response.charset = charset
327
327
328 return file_node.content
328 return file_node.content
329
329
330 @LoginRequired()
330 @LoginRequired()
331 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
331 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
332 'repository.admin')
332 'repository.admin')
333 def raw(self, repo_name, revision, f_path):
333 def raw(self, repo_name, revision, f_path):
334 """
334 """
335 Action for show as raw, some mimetypes are "rendered",
335 Action for show as raw, some mimetypes are "rendered",
336 those include images, icons.
336 those include images, icons.
337 """
337 """
338 commit = self.__get_commit_or_redirect(revision, repo_name)
338 commit = self.__get_commit_or_redirect(revision, repo_name)
339 file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path)
339 file_node = self.__get_filenode_or_redirect(repo_name, commit, f_path)
340
340
341 raw_mimetype_mapping = {
341 raw_mimetype_mapping = {
342 # map original mimetype to a mimetype used for "show as raw"
342 # map original mimetype to a mimetype used for "show as raw"
343 # you can also provide a content-disposition to override the
343 # you can also provide a content-disposition to override the
344 # default "attachment" disposition.
344 # default "attachment" disposition.
345 # orig_type: (new_type, new_dispo)
345 # orig_type: (new_type, new_dispo)
346
346
347 # show images inline:
347 # show images inline:
348 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
348 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
349 # for example render an SVG with javascript inside or even render
349 # for example render an SVG with javascript inside or even render
350 # HTML.
350 # HTML.
351 'image/x-icon': ('image/x-icon', 'inline'),
351 'image/x-icon': ('image/x-icon', 'inline'),
352 'image/png': ('image/png', 'inline'),
352 'image/png': ('image/png', 'inline'),
353 'image/gif': ('image/gif', 'inline'),
353 'image/gif': ('image/gif', 'inline'),
354 'image/jpeg': ('image/jpeg', 'inline'),
354 'image/jpeg': ('image/jpeg', 'inline'),
355 }
355 }
356
356
357 mimetype = file_node.mimetype
357 mimetype = file_node.mimetype
358 try:
358 try:
359 mimetype, dispo = raw_mimetype_mapping[mimetype]
359 mimetype, dispo = raw_mimetype_mapping[mimetype]
360 except KeyError:
360 except KeyError:
361 # we don't know anything special about this, handle it safely
361 # we don't know anything special about this, handle it safely
362 if file_node.is_binary:
362 if file_node.is_binary:
363 # do same as download raw for binary files
363 # do same as download raw for binary files
364 mimetype, dispo = 'application/octet-stream', 'attachment'
364 mimetype, dispo = 'application/octet-stream', 'attachment'
365 else:
365 else:
366 # do not just use the original mimetype, but force text/plain,
366 # do not just use the original mimetype, but force text/plain,
367 # otherwise it would serve text/html and that might be unsafe.
367 # otherwise it would serve text/html and that might be unsafe.
368 # Note: underlying vcs library fakes text/plain mimetype if the
368 # Note: underlying vcs library fakes text/plain mimetype if the
369 # mimetype can not be determined and it thinks it is not
369 # mimetype can not be determined and it thinks it is not
370 # binary.This might lead to erroneous text display in some
370 # binary.This might lead to erroneous text display in some
371 # cases, but helps in other cases, like with text files
371 # cases, but helps in other cases, like with text files
372 # without extension.
372 # without extension.
373 mimetype, dispo = 'text/plain', 'inline'
373 mimetype, dispo = 'text/plain', 'inline'
374
374
375 if dispo == 'attachment':
375 if dispo == 'attachment':
376 dispo = 'attachment; filename=%s' % safe_str(
376 dispo = 'attachment; filename=%s' % safe_str(
377 f_path.split(os.sep)[-1])
377 f_path.split(os.sep)[-1])
378
378
379 response.content_disposition = dispo
379 response.content_disposition = dispo
380 response.content_type = mimetype
380 response.content_type = mimetype
381 charset = self._get_default_encoding()
381 charset = self._get_default_encoding()
382 if charset:
382 if charset:
383 response.charset = charset
383 response.charset = charset
384 return file_node.content
384 return file_node.content
385
385
386 @CSRFRequired()
386 @CSRFRequired()
387 @LoginRequired()
387 @LoginRequired()
388 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
388 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
389 def delete(self, repo_name, revision, f_path):
389 def delete(self, repo_name, revision, f_path):
390 commit_id = revision
390 commit_id = revision
391
391
392 repo = c.rhodecode_db_repo
392 repo = c.rhodecode_db_repo
393 if repo.enable_locking and repo.locked[0]:
393 if repo.enable_locking and repo.locked[0]:
394 h.flash(_('This repository has been locked by %s on %s')
394 h.flash(_('This repository has been locked by %s on %s')
395 % (h.person_by_id(repo.locked[0]),
395 % (h.person_by_id(repo.locked[0]),
396 h.format_date(h.time_to_datetime(repo.locked[1]))),
396 h.format_date(h.time_to_datetime(repo.locked[1]))),
397 'warning')
397 'warning')
398 return redirect(h.url('files_home',
398 return redirect(h.url('files_home',
399 repo_name=repo_name, revision='tip'))
399 repo_name=repo_name, revision='tip'))
400
400
401 if not self._is_valid_head(commit_id, repo.scm_instance()):
401 if not self._is_valid_head(commit_id, repo.scm_instance()):
402 h.flash(_('You can only delete files with revision '
402 h.flash(_('You can only delete files with revision '
403 'being a valid branch '), category='warning')
403 'being a valid branch '), category='warning')
404 return redirect(h.url('files_home',
404 return redirect(h.url('files_home',
405 repo_name=repo_name, revision='tip',
405 repo_name=repo_name, revision='tip',
406 f_path=f_path))
406 f_path=f_path))
407
407
408 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
408 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
409 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
409 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
410
410
411 c.default_message = _(
411 c.default_message = _(
412 'Deleted file %s via RhodeCode Enterprise') % (f_path)
412 'Deleted file %s via RhodeCode Enterprise') % (f_path)
413 c.f_path = f_path
413 c.f_path = f_path
414 node_path = f_path
414 node_path = f_path
415 author = c.rhodecode_user.full_contact
415 author = c.rhodecode_user.full_contact
416 message = request.POST.get('message') or c.default_message
416 message = request.POST.get('message') or c.default_message
417 try:
417 try:
418 nodes = {
418 nodes = {
419 node_path: {
419 node_path: {
420 'content': ''
420 'content': ''
421 }
421 }
422 }
422 }
423 self.scm_model.delete_nodes(
423 self.scm_model.delete_nodes(
424 user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo,
424 user=c.rhodecode_user.user_id, repo=c.rhodecode_db_repo,
425 message=message,
425 message=message,
426 nodes=nodes,
426 nodes=nodes,
427 parent_commit=c.commit,
427 parent_commit=c.commit,
428 author=author,
428 author=author,
429 )
429 )
430
430
431 h.flash(_('Successfully deleted file %s') % f_path,
431 h.flash(_('Successfully deleted file %s') % f_path,
432 category='success')
432 category='success')
433 except Exception:
433 except Exception:
434 msg = _('Error occurred during commit')
434 msg = _('Error occurred during commit')
435 log.exception(msg)
435 log.exception(msg)
436 h.flash(msg, category='error')
436 h.flash(msg, category='error')
437 return redirect(url('changeset_home',
437 return redirect(url('changeset_home',
438 repo_name=c.repo_name, revision='tip'))
438 repo_name=c.repo_name, revision='tip'))
439
439
440 @LoginRequired()
440 @LoginRequired()
441 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
441 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
442 def delete_home(self, repo_name, revision, f_path):
442 def delete_home(self, repo_name, revision, f_path):
443 commit_id = revision
443 commit_id = revision
444
444
445 repo = c.rhodecode_db_repo
445 repo = c.rhodecode_db_repo
446 if repo.enable_locking and repo.locked[0]:
446 if repo.enable_locking and repo.locked[0]:
447 h.flash(_('This repository has been locked by %s on %s')
447 h.flash(_('This repository has been locked by %s on %s')
448 % (h.person_by_id(repo.locked[0]),
448 % (h.person_by_id(repo.locked[0]),
449 h.format_date(h.time_to_datetime(repo.locked[1]))),
449 h.format_date(h.time_to_datetime(repo.locked[1]))),
450 'warning')
450 'warning')
451 return redirect(h.url('files_home',
451 return redirect(h.url('files_home',
452 repo_name=repo_name, revision='tip'))
452 repo_name=repo_name, revision='tip'))
453
453
454 if not self._is_valid_head(commit_id, repo.scm_instance()):
454 if not self._is_valid_head(commit_id, repo.scm_instance()):
455 h.flash(_('You can only delete files with revision '
455 h.flash(_('You can only delete files with revision '
456 'being a valid branch '), category='warning')
456 'being a valid branch '), category='warning')
457 return redirect(h.url('files_home',
457 return redirect(h.url('files_home',
458 repo_name=repo_name, revision='tip',
458 repo_name=repo_name, revision='tip',
459 f_path=f_path))
459 f_path=f_path))
460
460
461 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
461 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
462 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
462 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
463
463
464 c.default_message = _(
464 c.default_message = _(
465 'Deleted file %s via RhodeCode Enterprise') % (f_path)
465 'Deleted file %s via RhodeCode Enterprise') % (f_path)
466 c.f_path = f_path
466 c.f_path = f_path
467
467
468 return render('files/files_delete.html')
468 return render('files/files_delete.html')
469
469
470 @CSRFRequired()
470 @CSRFRequired()
471 @LoginRequired()
471 @LoginRequired()
472 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
472 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
473 def edit(self, repo_name, revision, f_path):
473 def edit(self, repo_name, revision, f_path):
474 commit_id = revision
474 commit_id = revision
475
475
476 repo = c.rhodecode_db_repo
476 repo = c.rhodecode_db_repo
477 if repo.enable_locking and repo.locked[0]:
477 if repo.enable_locking and repo.locked[0]:
478 h.flash(_('This repository has been locked by %s on %s')
478 h.flash(_('This repository has been locked by %s on %s')
479 % (h.person_by_id(repo.locked[0]),
479 % (h.person_by_id(repo.locked[0]),
480 h.format_date(h.time_to_datetime(repo.locked[1]))),
480 h.format_date(h.time_to_datetime(repo.locked[1]))),
481 'warning')
481 'warning')
482 return redirect(h.url('files_home',
482 return redirect(h.url('files_home',
483 repo_name=repo_name, revision='tip'))
483 repo_name=repo_name, revision='tip'))
484
484
485 if not self._is_valid_head(commit_id, repo.scm_instance()):
485 if not self._is_valid_head(commit_id, repo.scm_instance()):
486 h.flash(_('You can only edit files with revision '
486 h.flash(_('You can only edit files with revision '
487 'being a valid branch '), category='warning')
487 'being a valid branch '), category='warning')
488 return redirect(h.url('files_home',
488 return redirect(h.url('files_home',
489 repo_name=repo_name, revision='tip',
489 repo_name=repo_name, revision='tip',
490 f_path=f_path))
490 f_path=f_path))
491
491
492 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
492 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
493 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
493 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
494
494
495 if c.file.is_binary:
495 if c.file.is_binary:
496 return redirect(url('files_home', repo_name=c.repo_name,
496 return redirect(url('files_home', repo_name=c.repo_name,
497 revision=c.commit.raw_id, f_path=f_path))
497 revision=c.commit.raw_id, f_path=f_path))
498 c.default_message = _(
498 c.default_message = _(
499 'Edited file %s via RhodeCode Enterprise') % (f_path)
499 'Edited file %s via RhodeCode Enterprise') % (f_path)
500 c.f_path = f_path
500 c.f_path = f_path
501 old_content = c.file.content
501 old_content = c.file.content
502 sl = old_content.splitlines(1)
502 sl = old_content.splitlines(1)
503 first_line = sl[0] if sl else ''
503 first_line = sl[0] if sl else ''
504
504
505 # modes: 0 - Unix, 1 - Mac, 2 - DOS
505 # modes: 0 - Unix, 1 - Mac, 2 - DOS
506 mode = detect_mode(first_line, 0)
506 mode = detect_mode(first_line, 0)
507 content = convert_line_endings(request.POST.get('content', ''), mode)
507 content = convert_line_endings(request.POST.get('content', ''), mode)
508
508
509 message = request.POST.get('message') or c.default_message
509 message = request.POST.get('message') or c.default_message
510 org_f_path = c.file.unicode_path
510 org_f_path = c.file.unicode_path
511 filename = request.POST['filename']
511 filename = request.POST['filename']
512 org_filename = c.file.name
512 org_filename = c.file.name
513
513
514 if content == old_content and filename == org_filename:
514 if content == old_content and filename == org_filename:
515 h.flash(_('No changes'), category='warning')
515 h.flash(_('No changes'), category='warning')
516 return redirect(url('changeset_home', repo_name=c.repo_name,
516 return redirect(url('changeset_home', repo_name=c.repo_name,
517 revision='tip'))
517 revision='tip'))
518 try:
518 try:
519 mapping = {
519 mapping = {
520 org_f_path: {
520 org_f_path: {
521 'org_filename': org_f_path,
521 'org_filename': org_f_path,
522 'filename': os.path.join(c.file.dir_path, filename),
522 'filename': os.path.join(c.file.dir_path, filename),
523 'content': content,
523 'content': content,
524 'lexer': '',
524 'lexer': '',
525 'op': 'mod',
525 'op': 'mod',
526 }
526 }
527 }
527 }
528
528
529 ScmModel().update_nodes(
529 ScmModel().update_nodes(
530 user=c.rhodecode_user.user_id,
530 user=c.rhodecode_user.user_id,
531 repo=c.rhodecode_db_repo,
531 repo=c.rhodecode_db_repo,
532 message=message,
532 message=message,
533 nodes=mapping,
533 nodes=mapping,
534 parent_commit=c.commit,
534 parent_commit=c.commit,
535 )
535 )
536
536
537 h.flash(_('Successfully committed to %s') % f_path,
537 h.flash(_('Successfully committed to %s') % f_path,
538 category='success')
538 category='success')
539 except Exception:
539 except Exception:
540 msg = _('Error occurred during commit')
540 msg = _('Error occurred during commit')
541 log.exception(msg)
541 log.exception(msg)
542 h.flash(msg, category='error')
542 h.flash(msg, category='error')
543 return redirect(url('changeset_home',
543 return redirect(url('changeset_home',
544 repo_name=c.repo_name, revision='tip'))
544 repo_name=c.repo_name, revision='tip'))
545
545
546 @LoginRequired()
546 @LoginRequired()
547 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
547 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
548 def edit_home(self, repo_name, revision, f_path):
548 def edit_home(self, repo_name, revision, f_path):
549 commit_id = revision
549 commit_id = revision
550
550
551 repo = c.rhodecode_db_repo
551 repo = c.rhodecode_db_repo
552 if repo.enable_locking and repo.locked[0]:
552 if repo.enable_locking and repo.locked[0]:
553 h.flash(_('This repository has been locked by %s on %s')
553 h.flash(_('This repository has been locked by %s on %s')
554 % (h.person_by_id(repo.locked[0]),
554 % (h.person_by_id(repo.locked[0]),
555 h.format_date(h.time_to_datetime(repo.locked[1]))),
555 h.format_date(h.time_to_datetime(repo.locked[1]))),
556 'warning')
556 'warning')
557 return redirect(h.url('files_home',
557 return redirect(h.url('files_home',
558 repo_name=repo_name, revision='tip'))
558 repo_name=repo_name, revision='tip'))
559
559
560 if not self._is_valid_head(commit_id, repo.scm_instance()):
560 if not self._is_valid_head(commit_id, repo.scm_instance()):
561 h.flash(_('You can only edit files with revision '
561 h.flash(_('You can only edit files with revision '
562 'being a valid branch '), category='warning')
562 'being a valid branch '), category='warning')
563 return redirect(h.url('files_home',
563 return redirect(h.url('files_home',
564 repo_name=repo_name, revision='tip',
564 repo_name=repo_name, revision='tip',
565 f_path=f_path))
565 f_path=f_path))
566
566
567 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
567 c.commit = self.__get_commit_or_redirect(commit_id, repo_name)
568 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
568 c.file = self.__get_filenode_or_redirect(repo_name, c.commit, f_path)
569
569
570 if c.file.is_binary:
570 if c.file.is_binary:
571 return redirect(url('files_home', repo_name=c.repo_name,
571 return redirect(url('files_home', repo_name=c.repo_name,
572 revision=c.commit.raw_id, f_path=f_path))
572 revision=c.commit.raw_id, f_path=f_path))
573 c.default_message = _(
573 c.default_message = _(
574 'Edited file %s via RhodeCode Enterprise') % (f_path)
574 'Edited file %s via RhodeCode Enterprise') % (f_path)
575 c.f_path = f_path
575 c.f_path = f_path
576
576
577 return render('files/files_edit.html')
577 return render('files/files_edit.html')
578
578
579 def _is_valid_head(self, commit_id, repo):
579 def _is_valid_head(self, commit_id, repo):
580 # check if commit is a branch identifier- basically we cannot
580 # check if commit is a branch identifier- basically we cannot
581 # create multiple heads via file editing
581 # create multiple heads via file editing
582 valid_heads = repo.branches.keys() + repo.branches.values()
582 valid_heads = repo.branches.keys() + repo.branches.values()
583
583
584 if h.is_svn(repo) and not repo.is_empty():
584 if h.is_svn(repo) and not repo.is_empty():
585 # Note: Subversion only has one head, we add it here in case there
585 # Note: Subversion only has one head, we add it here in case there
586 # is no branch matched.
586 # is no branch matched.
587 valid_heads.append(repo.get_commit(commit_idx=-1).raw_id)
587 valid_heads.append(repo.get_commit(commit_idx=-1).raw_id)
588
588
589 # check if commit is a branch name or branch hash
589 # check if commit is a branch name or branch hash
590 return commit_id in valid_heads
590 return commit_id in valid_heads
591
591
592 @CSRFRequired()
592 @CSRFRequired()
593 @LoginRequired()
593 @LoginRequired()
594 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
594 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
595 def add(self, repo_name, revision, f_path):
595 def add(self, repo_name, revision, f_path):
596 repo = Repository.get_by_repo_name(repo_name)
596 repo = Repository.get_by_repo_name(repo_name)
597 if repo.enable_locking and repo.locked[0]:
597 if repo.enable_locking and repo.locked[0]:
598 h.flash(_('This repository has been locked by %s on %s')
598 h.flash(_('This repository has been locked by %s on %s')
599 % (h.person_by_id(repo.locked[0]),
599 % (h.person_by_id(repo.locked[0]),
600 h.format_date(h.time_to_datetime(repo.locked[1]))),
600 h.format_date(h.time_to_datetime(repo.locked[1]))),
601 'warning')
601 'warning')
602 return redirect(h.url('files_home',
602 return redirect(h.url('files_home',
603 repo_name=repo_name, revision='tip'))
603 repo_name=repo_name, revision='tip'))
604
604
605 r_post = request.POST
605 r_post = request.POST
606
606
607 c.commit = self.__get_commit_or_redirect(
607 c.commit = self.__get_commit_or_redirect(
608 revision, repo_name, redirect_after=False)
608 revision, repo_name, redirect_after=False)
609 if c.commit is None:
609 if c.commit is None:
610 c.commit = EmptyCommit(alias=c.rhodecode_repo.alias)
610 c.commit = EmptyCommit(alias=c.rhodecode_repo.alias)
611 c.default_message = (_('Added file via RhodeCode Enterprise'))
611 c.default_message = (_('Added file via RhodeCode Enterprise'))
612 c.f_path = f_path
612 c.f_path = f_path
613 unix_mode = 0
613 unix_mode = 0
614 content = convert_line_endings(r_post.get('content', ''), unix_mode)
614 content = convert_line_endings(r_post.get('content', ''), unix_mode)
615
615
616 message = r_post.get('message') or c.default_message
616 message = r_post.get('message') or c.default_message
617 filename = r_post.get('filename')
617 filename = r_post.get('filename')
618 location = r_post.get('location', '') # dir location
618 location = r_post.get('location', '') # dir location
619 file_obj = r_post.get('upload_file', None)
619 file_obj = r_post.get('upload_file', None)
620
620
621 if file_obj is not None and hasattr(file_obj, 'filename'):
621 if file_obj is not None and hasattr(file_obj, 'filename'):
622 filename = file_obj.filename
622 filename = file_obj.filename
623 content = file_obj.file
623 content = file_obj.file
624
624
625 if hasattr(content, 'file'):
625 if hasattr(content, 'file'):
626 # non posix systems store real file under file attr
626 # non posix systems store real file under file attr
627 content = content.file
627 content = content.file
628
628
629 # If there's no commit, redirect to repo summary
629 # If there's no commit, redirect to repo summary
630 if type(c.commit) is EmptyCommit:
630 if type(c.commit) is EmptyCommit:
631 redirect_url = "summary_home"
631 redirect_url = "summary_home"
632 else:
632 else:
633 redirect_url = "changeset_home"
633 redirect_url = "changeset_home"
634
634
635 if not filename:
635 if not filename:
636 h.flash(_('No filename'), category='warning')
636 h.flash(_('No filename'), category='warning')
637 return redirect(url(redirect_url, repo_name=c.repo_name,
637 return redirect(url(redirect_url, repo_name=c.repo_name,
638 revision='tip'))
638 revision='tip'))
639
639
640 # extract the location from filename,
640 # extract the location from filename,
641 # allows using foo/bar.txt syntax to create subdirectories
641 # allows using foo/bar.txt syntax to create subdirectories
642 subdir_loc = filename.rsplit('/', 1)
642 subdir_loc = filename.rsplit('/', 1)
643 if len(subdir_loc) == 2:
643 if len(subdir_loc) == 2:
644 location = os.path.join(location, subdir_loc[0])
644 location = os.path.join(location, subdir_loc[0])
645
645
646 # strip all crap out of file, just leave the basename
646 # strip all crap out of file, just leave the basename
647 filename = os.path.basename(filename)
647 filename = os.path.basename(filename)
648 node_path = os.path.join(location, filename)
648 node_path = os.path.join(location, filename)
649 author = c.rhodecode_user.full_contact
649 author = c.rhodecode_user.full_contact
650
650
651 try:
651 try:
652 nodes = {
652 nodes = {
653 node_path: {
653 node_path: {
654 'content': content
654 'content': content
655 }
655 }
656 }
656 }
657 self.scm_model.create_nodes(
657 self.scm_model.create_nodes(
658 user=c.rhodecode_user.user_id,
658 user=c.rhodecode_user.user_id,
659 repo=c.rhodecode_db_repo,
659 repo=c.rhodecode_db_repo,
660 message=message,
660 message=message,
661 nodes=nodes,
661 nodes=nodes,
662 parent_commit=c.commit,
662 parent_commit=c.commit,
663 author=author,
663 author=author,
664 )
664 )
665
665
666 h.flash(_('Successfully committed to %s') % node_path,
666 h.flash(_('Successfully committed to %s') % node_path,
667 category='success')
667 category='success')
668 except NonRelativePathError as e:
668 except NonRelativePathError as e:
669 h.flash(_(
669 h.flash(_(
670 'The location specified must be a relative path and must not '
670 'The location specified must be a relative path and must not '
671 'contain .. in the path'), category='warning')
671 'contain .. in the path'), category='warning')
672 return redirect(url('changeset_home', repo_name=c.repo_name,
672 return redirect(url('changeset_home', repo_name=c.repo_name,
673 revision='tip'))
673 revision='tip'))
674 except (NodeError, NodeAlreadyExistsError) as e:
674 except (NodeError, NodeAlreadyExistsError) as e:
675 h.flash(_(e), category='error')
675 h.flash(_(e), category='error')
676 except Exception:
676 except Exception:
677 msg = _('Error occurred during commit')
677 msg = _('Error occurred during commit')
678 log.exception(msg)
678 log.exception(msg)
679 h.flash(msg, category='error')
679 h.flash(msg, category='error')
680 return redirect(url('changeset_home',
680 return redirect(url('changeset_home',
681 repo_name=c.repo_name, revision='tip'))
681 repo_name=c.repo_name, revision='tip'))
682
682
683 @LoginRequired()
683 @LoginRequired()
684 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
684 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
685 def add_home(self, repo_name, revision, f_path):
685 def add_home(self, repo_name, revision, f_path):
686
686
687 repo = Repository.get_by_repo_name(repo_name)
687 repo = Repository.get_by_repo_name(repo_name)
688 if repo.enable_locking and repo.locked[0]:
688 if repo.enable_locking and repo.locked[0]:
689 h.flash(_('This repository has been locked by %s on %s')
689 h.flash(_('This repository has been locked by %s on %s')
690 % (h.person_by_id(repo.locked[0]),
690 % (h.person_by_id(repo.locked[0]),
691 h.format_date(h.time_to_datetime(repo.locked[1]))),
691 h.format_date(h.time_to_datetime(repo.locked[1]))),
692 'warning')
692 'warning')
693 return redirect(h.url('files_home',
693 return redirect(h.url('files_home',
694 repo_name=repo_name, revision='tip'))
694 repo_name=repo_name, revision='tip'))
695
695
696 c.commit = self.__get_commit_or_redirect(
696 c.commit = self.__get_commit_or_redirect(
697 revision, repo_name, redirect_after=False)
697 revision, repo_name, redirect_after=False)
698 if c.commit is None:
698 if c.commit is None:
699 c.commit = EmptyCommit(alias=c.rhodecode_repo.alias)
699 c.commit = EmptyCommit(alias=c.rhodecode_repo.alias)
700 c.default_message = (_('Added file via RhodeCode Enterprise'))
700 c.default_message = (_('Added file via RhodeCode Enterprise'))
701 c.f_path = f_path
701 c.f_path = f_path
702
702
703 return render('files/files_add.html')
703 return render('files/files_add.html')
704
704
705 @LoginRequired()
705 @LoginRequired()
706 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
706 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
707 'repository.admin')
707 'repository.admin')
708 def archivefile(self, repo_name, fname):
708 def archivefile(self, repo_name, fname):
709 fileformat = None
709 fileformat = None
710 commit_id = None
710 commit_id = None
711 ext = None
711 ext = None
712 subrepos = request.GET.get('subrepos') == 'true'
712 subrepos = request.GET.get('subrepos') == 'true'
713
713
714 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
714 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
715 archive_spec = fname.split(ext_data[1])
715 archive_spec = fname.split(ext_data[1])
716 if len(archive_spec) == 2 and archive_spec[1] == '':
716 if len(archive_spec) == 2 and archive_spec[1] == '':
717 fileformat = a_type or ext_data[1]
717 fileformat = a_type or ext_data[1]
718 commit_id = archive_spec[0]
718 commit_id = archive_spec[0]
719 ext = ext_data[1]
719 ext = ext_data[1]
720
720
721 dbrepo = RepoModel().get_by_repo_name(repo_name)
721 dbrepo = RepoModel().get_by_repo_name(repo_name)
722 if not dbrepo.enable_downloads:
722 if not dbrepo.enable_downloads:
723 return _('Downloads disabled')
723 return _('Downloads disabled')
724
724
725 try:
725 try:
726 commit = c.rhodecode_repo.get_commit(commit_id)
726 commit = c.rhodecode_repo.get_commit(commit_id)
727 content_type = settings.ARCHIVE_SPECS[fileformat][0]
727 content_type = settings.ARCHIVE_SPECS[fileformat][0]
728 except CommitDoesNotExistError:
728 except CommitDoesNotExistError:
729 return _('Unknown revision %s') % commit_id
729 return _('Unknown revision %s') % commit_id
730 except EmptyRepositoryError:
730 except EmptyRepositoryError:
731 return _('Empty repository')
731 return _('Empty repository')
732 except KeyError:
732 except KeyError:
733 return _('Unknown archive type')
733 return _('Unknown archive type')
734
734
735 # archive cache
735 # archive cache
736 from rhodecode import CONFIG
736 from rhodecode import CONFIG
737
737
738 archive_name = '%s-%s%s%s' % (
738 archive_name = '%s-%s%s%s' % (
739 safe_str(repo_name.replace('/', '_')),
739 safe_str(repo_name.replace('/', '_')),
740 '-sub' if subrepos else '',
740 '-sub' if subrepos else '',
741 safe_str(commit.short_id), ext)
741 safe_str(commit.short_id), ext)
742
742
743 use_cached_archive = False
743 use_cached_archive = False
744 archive_cache_enabled = CONFIG.get(
744 archive_cache_enabled = CONFIG.get(
745 'archive_cache_dir') and not request.GET.get('no_cache')
745 'archive_cache_dir') and not request.GET.get('no_cache')
746
746
747 if archive_cache_enabled:
747 if archive_cache_enabled:
748 # check if we it's ok to write
748 # check if we it's ok to write
749 if not os.path.isdir(CONFIG['archive_cache_dir']):
749 if not os.path.isdir(CONFIG['archive_cache_dir']):
750 os.makedirs(CONFIG['archive_cache_dir'])
750 os.makedirs(CONFIG['archive_cache_dir'])
751 cached_archive_path = os.path.join(
751 cached_archive_path = os.path.join(
752 CONFIG['archive_cache_dir'], archive_name)
752 CONFIG['archive_cache_dir'], archive_name)
753 if os.path.isfile(cached_archive_path):
753 if os.path.isfile(cached_archive_path):
754 log.debug('Found cached archive in %s', cached_archive_path)
754 log.debug('Found cached archive in %s', cached_archive_path)
755 fd, archive = None, cached_archive_path
755 fd, archive = None, cached_archive_path
756 use_cached_archive = True
756 use_cached_archive = True
757 else:
757 else:
758 log.debug('Archive %s is not yet cached', archive_name)
758 log.debug('Archive %s is not yet cached', archive_name)
759
759
760 if not use_cached_archive:
760 if not use_cached_archive:
761 # generate new archive
761 # generate new archive
762 fd, archive = tempfile.mkstemp()
762 fd, archive = tempfile.mkstemp()
763 log.debug('Creating new temp archive in %s' % (archive,))
763 log.debug('Creating new temp archive in %s' % (archive,))
764 try:
764 try:
765 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos)
765 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos)
766 except ImproperArchiveTypeError:
766 except ImproperArchiveTypeError:
767 return _('Unknown archive type')
767 return _('Unknown archive type')
768 if archive_cache_enabled:
768 if archive_cache_enabled:
769 # if we generated the archive and we have cache enabled
769 # if we generated the archive and we have cache enabled
770 # let's use this for future
770 # let's use this for future
771 log.debug('Storing new archive in %s' % (cached_archive_path,))
771 log.debug('Storing new archive in %s' % (cached_archive_path,))
772 shutil.move(archive, cached_archive_path)
772 shutil.move(archive, cached_archive_path)
773 archive = cached_archive_path
773 archive = cached_archive_path
774
774
775 def get_chunked_archive(archive):
775 def get_chunked_archive(archive):
776 with open(archive, 'rb') as stream:
776 with open(archive, 'rb') as stream:
777 while True:
777 while True:
778 data = stream.read(16 * 1024)
778 data = stream.read(16 * 1024)
779 if not data:
779 if not data:
780 if fd: # fd means we used temporary file
780 if fd: # fd means we used temporary file
781 os.close(fd)
781 os.close(fd)
782 if not archive_cache_enabled:
782 if not archive_cache_enabled:
783 log.debug('Destroying temp archive %s', archive)
783 log.debug('Destroying temp archive %s', archive)
784 os.remove(archive)
784 os.remove(archive)
785 break
785 break
786 yield data
786 yield data
787
787
788 # store download action
788 # store download action
789 action_logger(user=c.rhodecode_user,
789 action_logger(user=c.rhodecode_user,
790 action='user_downloaded_archive:%s' % archive_name,
790 action='user_downloaded_archive:%s' % archive_name,
791 repo=repo_name, ipaddr=self.ip_addr, commit=True)
791 repo=repo_name, ipaddr=self.ip_addr, commit=True)
792 response.content_disposition = str(
792 response.content_disposition = str(
793 'attachment; filename=%s' % archive_name)
793 'attachment; filename=%s' % archive_name)
794 response.content_type = str(content_type)
794 response.content_type = str(content_type)
795
795
796 return get_chunked_archive(archive)
796 return get_chunked_archive(archive)
797
797
798 @LoginRequired()
798 @LoginRequired()
799 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
799 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
800 'repository.admin')
800 'repository.admin')
801 def diff(self, repo_name, f_path):
801 def diff(self, repo_name, f_path):
802 ignore_whitespace = request.GET.get('ignorews') == '1'
802
803 line_context = request.GET.get('context', 3)
803 c.action = request.GET.get('diff')
804 diff1 = request.GET.get('diff1', '')
804 diff1 = request.GET.get('diff1', '')
805 diff2 = request.GET.get('diff2', '')
805
806
806 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
807 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
807
808
808 diff2 = request.GET.get('diff2', '')
809 ignore_whitespace = str2bool(request.GET.get('ignorews'))
809 c.action = request.GET.get('diff')
810 line_context = request.GET.get('context', 3)
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] = []
817
811
818 if not any((diff1, diff2)):
812 if not any((diff1, diff2)):
819 h.flash(
813 h.flash(
820 'Need query parameter "diff1" or "diff2" to generate a diff.',
814 'Need query parameter "diff1" or "diff2" to generate a diff.',
821 category='error')
815 category='error')
822 raise HTTPBadRequest()
816 raise HTTPBadRequest()
823
817
824 # special case if we want a show commit_id only, it's impl here
818 if c.action not in ['download', 'raw']:
825 # to reduce JS and callbacks
819 # redirect to new view if we render diff
826
820 return redirect(
827 if request.GET.get('show_rev') and diff1:
821 url('compare_url', repo_name=repo_name,
828 if str2bool(request.GET.get('annotate', 'False')):
822 source_ref_type='rev',
829 _url = url('files_annotate_home', repo_name=c.repo_name,
823 source_ref=diff1,
830 revision=diff1, f_path=path1)
824 target_repo=c.repo_name,
831 else:
825 target_ref_type='rev',
832 _url = url('files_home', repo_name=c.repo_name,
826 target_ref=diff2,
833 revision=diff1, f_path=path1)
827 f_path=f_path))
834
835 return redirect(_url)
836
828
837 try:
829 try:
838 node1 = self._get_file_node(diff1, path1)
830 node1 = self._get_file_node(diff1, path1)
839 node2 = self._get_file_node(diff2, f_path)
831 node2 = self._get_file_node(diff2, f_path)
840 except (RepositoryError, NodeError):
832 except (RepositoryError, NodeError):
841 log.exception("Exception while trying to get node from repository")
833 log.exception("Exception while trying to get node from repository")
842 return redirect(url(
834 return redirect(url(
843 'files_home', repo_name=c.repo_name, f_path=f_path))
835 'files_home', repo_name=c.repo_name, f_path=f_path))
844
836
845 if all(isinstance(node.commit, EmptyCommit)
837 if all(isinstance(node.commit, EmptyCommit)
846 for node in (node1, node2)):
838 for node in (node1, node2)):
847 raise HTTPNotFound
839 raise HTTPNotFound
848
840
849 c.commit_1 = node1.commit
841 c.commit_1 = node1.commit
850 c.commit_2 = node2.commit
842 c.commit_2 = node2.commit
851
843
852 if c.action == 'download':
844 if c.action == 'download':
853 _diff = diffs.get_gitdiff(node1, node2,
845 _diff = diffs.get_gitdiff(node1, node2,
854 ignore_whitespace=ignore_whitespace,
846 ignore_whitespace=ignore_whitespace,
855 context=line_context)
847 context=line_context)
856 diff = diffs.DiffProcessor(_diff, format='gitdiff')
848 diff = diffs.DiffProcessor(_diff, format='gitdiff')
857
849
858 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
850 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
859 response.content_type = 'text/plain'
851 response.content_type = 'text/plain'
860 response.content_disposition = (
852 response.content_disposition = (
861 'attachment; filename=%s' % (diff_name,)
853 'attachment; filename=%s' % (diff_name,)
862 )
854 )
863 charset = self._get_default_encoding()
855 charset = self._get_default_encoding()
864 if charset:
856 if charset:
865 response.charset = charset
857 response.charset = charset
866 return diff.as_raw()
858 return diff.as_raw()
867
859
868 elif c.action == 'raw':
860 elif c.action == 'raw':
869 _diff = diffs.get_gitdiff(node1, node2,
861 _diff = diffs.get_gitdiff(node1, node2,
870 ignore_whitespace=ignore_whitespace,
862 ignore_whitespace=ignore_whitespace,
871 context=line_context)
863 context=line_context)
872 diff = diffs.DiffProcessor(_diff, format='gitdiff')
864 diff = diffs.DiffProcessor(_diff, format='gitdiff')
873 response.content_type = 'text/plain'
865 response.content_type = 'text/plain'
874 charset = self._get_default_encoding()
866 charset = self._get_default_encoding()
875 if charset:
867 if charset:
876 response.charset = charset
868 response.charset = charset
877 return diff.as_raw()
869 return diff.as_raw()
878
870
879 else:
871 else:
880 fid = h.FID(diff2, node2.path)
872 return redirect(
881 line_context_lcl = get_line_ctx(fid, request.GET)
873 url('compare_url', repo_name=repo_name,
882 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
874 source_ref_type='rev',
883
875 source_ref=diff1,
884 __, commit1, commit2, diff, st, data = diffs.wrapped_diff(
876 target_repo=c.repo_name,
885 filenode_old=node1,
877 target_ref_type='rev',
886 filenode_new=node2,
878 target_ref=diff2,
887 diff_limit=self.cut_off_limit_diff,
879 f_path=f_path))
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')
917
880
918 @LoginRequired()
881 @LoginRequired()
919 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
882 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
920 'repository.admin')
883 'repository.admin')
921 def diff_2way(self, repo_name, f_path):
884 def diff_2way(self, repo_name, f_path):
885 """
886 Kept only to make OLD links work
887 """
922 diff1 = request.GET.get('diff1', '')
888 diff1 = request.GET.get('diff1', '')
923 diff2 = request.GET.get('diff2', '')
889 diff2 = request.GET.get('diff2', '')
924
890
925 nodes = []
891 if not any((diff1, diff2)):
926 unknown_commits = []
892 h.flash(
927 for commit in [diff1, diff2]:
893 'Need query parameter "diff1" or "diff2" to generate a diff.',
928 try:
894 category='error')
929 nodes.append(self._get_file_node(commit, f_path))
895 raise HTTPBadRequest()
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
945
896
946 f_gitdiff = diffs.get_gitdiff(node1, node2, ignore_whitespace=False)
897 return redirect(
947 diff_processor = diffs.DiffProcessor(f_gitdiff, format='gitdiff')
898 url('compare_url', repo_name=repo_name,
948 diff_data = diff_processor.prepare()
899 source_ref_type='rev',
949
900 source_ref=diff1,
950 if not diff_data or diff_data[0]['raw_diff'] == '':
901 target_repo=c.repo_name,
951 h.flash(h.literal(_('%(file_path)s has not changed '
902 target_ref_type='rev',
952 'between %(commit_1)s and %(commit_2)s.') % {
903 target_ref=diff2,
953 'file_path': f_path,
904 f_path=f_path,
954 'commit_1': node1.commit.id,
905 diffmode='sideside'))
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')
972
906
973 def _get_file_node(self, commit_id, f_path):
907 def _get_file_node(self, commit_id, f_path):
974 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
908 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
975 commit = c.rhodecode_repo.get_commit(commit_id=commit_id)
909 commit = c.rhodecode_repo.get_commit(commit_id=commit_id)
976 try:
910 try:
977 node = commit.get_node(f_path)
911 node = commit.get_node(f_path)
978 if node.is_dir():
912 if node.is_dir():
979 raise NodeError('%s path is a %s not a file'
913 raise NodeError('%s path is a %s not a file'
980 % (node, type(node)))
914 % (node, type(node)))
981 except NodeDoesNotExistError:
915 except NodeDoesNotExistError:
982 commit = EmptyCommit(
916 commit = EmptyCommit(
983 commit_id=commit_id,
917 commit_id=commit_id,
984 idx=commit.idx,
918 idx=commit.idx,
985 repo=commit.repository,
919 repo=commit.repository,
986 alias=commit.repository.alias,
920 alias=commit.repository.alias,
987 message=commit.message,
921 message=commit.message,
988 author=commit.author,
922 author=commit.author,
989 date=commit.date)
923 date=commit.date)
990 node = FileNode(f_path, '', commit=commit)
924 node = FileNode(f_path, '', commit=commit)
991 else:
925 else:
992 commit = EmptyCommit(
926 commit = EmptyCommit(
993 repo=c.rhodecode_repo,
927 repo=c.rhodecode_repo,
994 alias=c.rhodecode_repo.alias)
928 alias=c.rhodecode_repo.alias)
995 node = FileNode(f_path, '', commit=commit)
929 node = FileNode(f_path, '', commit=commit)
996 return node
930 return node
997
931
998 def _get_node_history(self, commit, f_path, commits=None):
932 def _get_node_history(self, commit, f_path, commits=None):
999 """
933 """
1000 get commit history for given node
934 get commit history for given node
1001
935
1002 :param commit: commit to calculate history
936 :param commit: commit to calculate history
1003 :param f_path: path for node to calculate history for
937 :param f_path: path for node to calculate history for
1004 :param commits: if passed don't calculate history and take
938 :param commits: if passed don't calculate history and take
1005 commits defined in this list
939 commits defined in this list
1006 """
940 """
1007 # calculate history based on tip
941 # calculate history based on tip
1008 tip = c.rhodecode_repo.get_commit()
942 tip = c.rhodecode_repo.get_commit()
1009 if commits is None:
943 if commits is None:
1010 pre_load = ["author", "branch"]
944 pre_load = ["author", "branch"]
1011 try:
945 try:
1012 commits = tip.get_file_history(f_path, pre_load=pre_load)
946 commits = tip.get_file_history(f_path, pre_load=pre_load)
1013 except (NodeDoesNotExistError, CommitError):
947 except (NodeDoesNotExistError, CommitError):
1014 # this node is not present at tip!
948 # this node is not present at tip!
1015 commits = commit.get_file_history(f_path, pre_load=pre_load)
949 commits = commit.get_file_history(f_path, pre_load=pre_load)
1016
950
1017 history = []
951 history = []
1018 commits_group = ([], _("Changesets"))
952 commits_group = ([], _("Changesets"))
1019 for commit in commits:
953 for commit in commits:
1020 branch = ' (%s)' % commit.branch if commit.branch else ''
954 branch = ' (%s)' % commit.branch if commit.branch else ''
1021 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
955 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
1022 commits_group[0].append((commit.raw_id, n_desc,))
956 commits_group[0].append((commit.raw_id, n_desc,))
1023 history.append(commits_group)
957 history.append(commits_group)
1024
958
1025 symbolic_reference = self._symbolic_reference
959 symbolic_reference = self._symbolic_reference
1026
960
1027 if c.rhodecode_repo.alias == 'svn':
961 if c.rhodecode_repo.alias == 'svn':
1028 adjusted_f_path = self._adjust_file_path_for_svn(
962 adjusted_f_path = self._adjust_file_path_for_svn(
1029 f_path, c.rhodecode_repo)
963 f_path, c.rhodecode_repo)
1030 if adjusted_f_path != f_path:
964 if adjusted_f_path != f_path:
1031 log.debug(
965 log.debug(
1032 'Recognized svn tag or branch in file "%s", using svn '
966 'Recognized svn tag or branch in file "%s", using svn '
1033 'specific symbolic references', f_path)
967 'specific symbolic references', f_path)
1034 f_path = adjusted_f_path
968 f_path = adjusted_f_path
1035 symbolic_reference = self._symbolic_reference_svn
969 symbolic_reference = self._symbolic_reference_svn
1036
970
1037 branches = self._create_references(
971 branches = self._create_references(
1038 c.rhodecode_repo.branches, symbolic_reference, f_path)
972 c.rhodecode_repo.branches, symbolic_reference, f_path)
1039 branches_group = (branches, _("Branches"))
973 branches_group = (branches, _("Branches"))
1040
974
1041 tags = self._create_references(
975 tags = self._create_references(
1042 c.rhodecode_repo.tags, symbolic_reference, f_path)
976 c.rhodecode_repo.tags, symbolic_reference, f_path)
1043 tags_group = (tags, _("Tags"))
977 tags_group = (tags, _("Tags"))
1044
978
1045 history.append(branches_group)
979 history.append(branches_group)
1046 history.append(tags_group)
980 history.append(tags_group)
1047
981
1048 return history, commits
982 return history, commits
1049
983
1050 def _adjust_file_path_for_svn(self, f_path, repo):
984 def _adjust_file_path_for_svn(self, f_path, repo):
1051 """
985 """
1052 Computes the relative path of `f_path`.
986 Computes the relative path of `f_path`.
1053
987
1054 This is mainly based on prefix matching of the recognized tags and
988 This is mainly based on prefix matching of the recognized tags and
1055 branches in the underlying repository.
989 branches in the underlying repository.
1056 """
990 """
1057 tags_and_branches = itertools.chain(
991 tags_and_branches = itertools.chain(
1058 repo.branches.iterkeys(),
992 repo.branches.iterkeys(),
1059 repo.tags.iterkeys())
993 repo.tags.iterkeys())
1060 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
994 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
1061
995
1062 for name in tags_and_branches:
996 for name in tags_and_branches:
1063 if f_path.startswith(name + '/'):
997 if f_path.startswith(name + '/'):
1064 f_path = vcspath.relpath(f_path, name)
998 f_path = vcspath.relpath(f_path, name)
1065 break
999 break
1066 return f_path
1000 return f_path
1067
1001
1068 def _create_references(
1002 def _create_references(
1069 self, branches_or_tags, symbolic_reference, f_path):
1003 self, branches_or_tags, symbolic_reference, f_path):
1070 items = []
1004 items = []
1071 for name, commit_id in branches_or_tags.items():
1005 for name, commit_id in branches_or_tags.items():
1072 sym_ref = symbolic_reference(commit_id, name, f_path)
1006 sym_ref = symbolic_reference(commit_id, name, f_path)
1073 items.append((sym_ref, name))
1007 items.append((sym_ref, name))
1074 return items
1008 return items
1075
1009
1076 def _symbolic_reference(self, commit_id, name, f_path):
1010 def _symbolic_reference(self, commit_id, name, f_path):
1077 return commit_id
1011 return commit_id
1078
1012
1079 def _symbolic_reference_svn(self, commit_id, name, f_path):
1013 def _symbolic_reference_svn(self, commit_id, name, f_path):
1080 new_f_path = vcspath.join(name, f_path)
1014 new_f_path = vcspath.join(name, f_path)
1081 return u'%s@%s' % (new_f_path, commit_id)
1015 return u'%s@%s' % (new_f_path, commit_id)
1082
1016
1083 @LoginRequired()
1017 @LoginRequired()
1084 @XHRRequired()
1018 @XHRRequired()
1085 @HasRepoPermissionAnyDecorator(
1019 @HasRepoPermissionAnyDecorator(
1086 'repository.read', 'repository.write', 'repository.admin')
1020 'repository.read', 'repository.write', 'repository.admin')
1087 @jsonify
1021 @jsonify
1088 def nodelist(self, repo_name, revision, f_path):
1022 def nodelist(self, repo_name, revision, f_path):
1089 commit = self.__get_commit_or_redirect(revision, repo_name)
1023 commit = self.__get_commit_or_redirect(revision, repo_name)
1090
1024
1091 metadata = self._get_nodelist_at_commit(
1025 metadata = self._get_nodelist_at_commit(
1092 repo_name, commit.raw_id, f_path)
1026 repo_name, commit.raw_id, f_path)
1093 return {'nodes': metadata}
1027 return {'nodes': metadata}
1094
1028
1095 @LoginRequired()
1029 @LoginRequired()
1096 @XHRRequired()
1030 @XHRRequired()
1097 @HasRepoPermissionAnyDecorator(
1031 @HasRepoPermissionAnyDecorator(
1098 'repository.read', 'repository.write', 'repository.admin')
1032 'repository.read', 'repository.write', 'repository.admin')
1099 def nodetree_full(self, repo_name, commit_id, f_path):
1033 def nodetree_full(self, repo_name, commit_id, f_path):
1100 """
1034 """
1101 Returns rendered html of file tree that contains commit date,
1035 Returns rendered html of file tree that contains commit date,
1102 author, revision for the specified combination of
1036 author, revision for the specified combination of
1103 repo, commit_id and file path
1037 repo, commit_id and file path
1104
1038
1105 :param repo_name: name of the repository
1039 :param repo_name: name of the repository
1106 :param commit_id: commit_id of file tree
1040 :param commit_id: commit_id of file tree
1107 :param f_path: file path of the requested directory
1041 :param f_path: file path of the requested directory
1108 """
1042 """
1109
1043
1110 commit = self.__get_commit_or_redirect(commit_id, repo_name)
1044 commit = self.__get_commit_or_redirect(commit_id, repo_name)
1111 try:
1045 try:
1112 dir_node = commit.get_node(f_path)
1046 dir_node = commit.get_node(f_path)
1113 except RepositoryError as e:
1047 except RepositoryError as e:
1114 return 'error {}'.format(safe_str(e))
1048 return 'error {}'.format(safe_str(e))
1115
1049
1116 if dir_node.is_file():
1050 if dir_node.is_file():
1117 return ''
1051 return ''
1118
1052
1119 c.file = dir_node
1053 c.file = dir_node
1120 c.commit = commit
1054 c.commit = commit
1121
1055
1122 # using force=True here, make a little trick. We flush the cache and
1056 # using force=True here, make a little trick. We flush the cache and
1123 # compute it using the same key as without full_load, so the fully
1057 # compute it using the same key as without full_load, so the fully
1124 # loaded cached tree is now returned instead of partial
1058 # loaded cached tree is now returned instead of partial
1125 return self._get_tree_at_commit(
1059 return self._get_tree_at_commit(
1126 repo_name, commit.raw_id, dir_node.path, full_load=True,
1060 repo_name, commit.raw_id, dir_node.path, full_load=True,
1127 force=True)
1061 force=True)
@@ -1,106 +1,107 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2010-2016 RhodeCode GmbH
3 # Copyright (C) 2010-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Utilities to be shared by multiple controllers.
22 Utilities to be shared by multiple controllers.
23
23
24 Should only contain utilities to be shared in the controller layer.
24 Should only contain utilities to be shared in the controller layer.
25 """
25 """
26
26
27 from rhodecode.lib import helpers as h
27 from rhodecode.lib import helpers as h
28 from rhodecode.lib.vcs.exceptions import RepositoryError
28 from rhodecode.lib.vcs.exceptions import RepositoryError
29
29
30
30 def parse_path_ref(ref, default_path=None):
31 def parse_path_ref(ref, default_path=None):
31 """
32 """
32 Parse out a path and reference combination and return both parts of it.
33 Parse out a path and reference combination and return both parts of it.
33
34
34 This is used to allow support of path based comparisons for Subversion
35 This is used to allow support of path based comparisons for Subversion
35 as an iterim solution in parameter handling.
36 as an iterim solution in parameter handling.
36 """
37 """
37 if '@' in ref:
38 if '@' in ref:
38 return ref.rsplit('@', 1)
39 return ref.rsplit('@', 1)
39 else:
40 else:
40 return default_path, ref
41 return default_path, ref
41
42
42
43
43 def get_format_ref_id(repo):
44 def get_format_ref_id(repo):
44 """Returns a `repo` specific reference formatter function"""
45 """Returns a `repo` specific reference formatter function"""
45 if h.is_svn(repo):
46 if h.is_svn(repo):
46 return _format_ref_id_svn
47 return _format_ref_id_svn
47 else:
48 else:
48 return _format_ref_id
49 return _format_ref_id
49
50
50
51
51 def _format_ref_id(name, raw_id):
52 def _format_ref_id(name, raw_id):
52 """Default formatting of a given reference `name`"""
53 """Default formatting of a given reference `name`"""
53 return name
54 return name
54
55
55
56
56 def _format_ref_id_svn(name, raw_id):
57 def _format_ref_id_svn(name, raw_id):
57 """Special way of formatting a reference for Subversion including path"""
58 """Special way of formatting a reference for Subversion including path"""
58 return '%s@%s' % (name, raw_id)
59 return '%s@%s' % (name, raw_id)
59
60
60
61
61 def get_commit_from_ref_name(repo, ref_name, ref_type=None):
62 def get_commit_from_ref_name(repo, ref_name, ref_type=None):
62 """
63 """
63 Gets the commit for a `ref_name` taking into account `ref_type`.
64 Gets the commit for a `ref_name` taking into account `ref_type`.
64 Needed in case a bookmark / tag share the same name.
65 Needed in case a bookmark / tag share the same name.
65
66
66 :param repo: the repo instance
67 :param repo: the repo instance
67 :param ref_name: the name of the ref to get
68 :param ref_name: the name of the ref to get
68 :param ref_type: optional, used to disambiguate colliding refs
69 :param ref_type: optional, used to disambiguate colliding refs
69 """
70 """
70 repo_scm = repo.scm_instance()
71 repo_scm = repo.scm_instance()
71 ref_type_mapping = {
72 ref_type_mapping = {
72 'book': repo_scm.bookmarks,
73 'book': repo_scm.bookmarks,
73 'bookmark': repo_scm.bookmarks,
74 'bookmark': repo_scm.bookmarks,
74 'tag': repo_scm.tags,
75 'tag': repo_scm.tags,
75 'branch': repo_scm.branches,
76 'branch': repo_scm.branches,
76 }
77 }
77
78
78 commit_id = ref_name
79 commit_id = ref_name
79 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
80 if repo_scm.alias != 'svn': # pass svn refs straight to backend until
80 # the branch issue with svn is fixed
81 # the branch issue with svn is fixed
81 if ref_type and ref_type in ref_type_mapping:
82 if ref_type and ref_type in ref_type_mapping:
82 try:
83 try:
83 commit_id = ref_type_mapping[ref_type][ref_name]
84 commit_id = ref_type_mapping[ref_type][ref_name]
84 except KeyError:
85 except KeyError:
85 raise RepositoryError(
86 raise RepositoryError(
86 '%s "%s" does not exist' % (ref_type, ref_name))
87 '%s "%s" does not exist' % (ref_type, ref_name))
87
88
88 return repo_scm.get_commit(commit_id)
89 return repo_scm.get_commit(commit_id)
89
90
90
91
91 def reviewer_as_json(user, reasons):
92 def reviewer_as_json(user, reasons):
92 """
93 """
93 Returns json struct of a reviewer for frontend
94 Returns json struct of a reviewer for frontend
94
95
95 :param user: the reviewer
96 :param user: the reviewer
96 :param reasons: list of strings of why they are reviewers
97 :param reasons: list of strings of why they are reviewers
97 """
98 """
98
99
99 return {
100 return {
100 'user_id': user.user_id,
101 'user_id': user.user_id,
101 'reasons': reasons,
102 'reasons': reasons,
102 'username': user.username,
103 'username': user.username,
103 'firstname': user.firstname,
104 'firstname': user.firstname,
104 'lastname': user.lastname,
105 'lastname': user.lastname,
105 'gravatar_link': h.gravatar_url(user.email, 14),
106 'gravatar_link': h.gravatar_url(user.email, 14),
106 }
107 }
@@ -1,1576 +1,1587 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2016 RhodeCode GmbH
3 # Copyright (C) 2014-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21 """
21 """
22 Base module for all VCS systems
22 Base module for all VCS systems
23 """
23 """
24
24
25 import collections
25 import collections
26 import datetime
26 import datetime
27 import itertools
27 import itertools
28 import logging
28 import logging
29 import os
29 import os
30 import time
30 import time
31 import warnings
31 import warnings
32
32
33 from zope.cachedescriptors.property import Lazy as LazyProperty
33 from zope.cachedescriptors.property import Lazy as LazyProperty
34
34
35 from rhodecode.lib.utils2 import safe_str, safe_unicode
35 from rhodecode.lib.utils2 import safe_str, safe_unicode
36 from rhodecode.lib.vcs import connection
36 from rhodecode.lib.vcs import connection
37 from rhodecode.lib.vcs.utils import author_name, author_email
37 from rhodecode.lib.vcs.utils import author_name, author_email
38 from rhodecode.lib.vcs.conf import settings
38 from rhodecode.lib.vcs.conf import settings
39 from rhodecode.lib.vcs.exceptions import (
39 from rhodecode.lib.vcs.exceptions import (
40 CommitError, EmptyRepositoryError, NodeAlreadyAddedError,
40 CommitError, EmptyRepositoryError, NodeAlreadyAddedError,
41 NodeAlreadyChangedError, NodeAlreadyExistsError, NodeAlreadyRemovedError,
41 NodeAlreadyChangedError, NodeAlreadyExistsError, NodeAlreadyRemovedError,
42 NodeDoesNotExistError, NodeNotChangedError, VCSError,
42 NodeDoesNotExistError, NodeNotChangedError, VCSError,
43 ImproperArchiveTypeError, BranchDoesNotExistError, CommitDoesNotExistError,
43 ImproperArchiveTypeError, BranchDoesNotExistError, CommitDoesNotExistError,
44 RepositoryError)
44 RepositoryError)
45
45
46
46
47 log = logging.getLogger(__name__)
47 log = logging.getLogger(__name__)
48
48
49
49
50 FILEMODE_DEFAULT = 0100644
50 FILEMODE_DEFAULT = 0100644
51 FILEMODE_EXECUTABLE = 0100755
51 FILEMODE_EXECUTABLE = 0100755
52
52
53 Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id'))
53 Reference = collections.namedtuple('Reference', ('type', 'name', 'commit_id'))
54 MergeResponse = collections.namedtuple(
54 MergeResponse = collections.namedtuple(
55 'MergeResponse',
55 'MergeResponse',
56 ('possible', 'executed', 'merge_ref', 'failure_reason'))
56 ('possible', 'executed', 'merge_ref', 'failure_reason'))
57
57
58
58
59 class MergeFailureReason(object):
59 class MergeFailureReason(object):
60 """
60 """
61 Enumeration with all the reasons why the server side merge could fail.
61 Enumeration with all the reasons why the server side merge could fail.
62
62
63 DO NOT change the number of the reasons, as they may be stored in the
63 DO NOT change the number of the reasons, as they may be stored in the
64 database.
64 database.
65
65
66 Changing the name of a reason is acceptable and encouraged to deprecate old
66 Changing the name of a reason is acceptable and encouraged to deprecate old
67 reasons.
67 reasons.
68 """
68 """
69
69
70 # Everything went well.
70 # Everything went well.
71 NONE = 0
71 NONE = 0
72
72
73 # An unexpected exception was raised. Check the logs for more details.
73 # An unexpected exception was raised. Check the logs for more details.
74 UNKNOWN = 1
74 UNKNOWN = 1
75
75
76 # The merge was not successful, there are conflicts.
76 # The merge was not successful, there are conflicts.
77 MERGE_FAILED = 2
77 MERGE_FAILED = 2
78
78
79 # The merge succeeded but we could not push it to the target repository.
79 # The merge succeeded but we could not push it to the target repository.
80 PUSH_FAILED = 3
80 PUSH_FAILED = 3
81
81
82 # The specified target is not a head in the target repository.
82 # The specified target is not a head in the target repository.
83 TARGET_IS_NOT_HEAD = 4
83 TARGET_IS_NOT_HEAD = 4
84
84
85 # The source repository contains more branches than the target. Pushing
85 # The source repository contains more branches than the target. Pushing
86 # the merge will create additional branches in the target.
86 # the merge will create additional branches in the target.
87 HG_SOURCE_HAS_MORE_BRANCHES = 5
87 HG_SOURCE_HAS_MORE_BRANCHES = 5
88
88
89 # The target reference has multiple heads. That does not allow to correctly
89 # The target reference has multiple heads. That does not allow to correctly
90 # identify the target location. This could only happen for mercurial
90 # identify the target location. This could only happen for mercurial
91 # branches.
91 # branches.
92 HG_TARGET_HAS_MULTIPLE_HEADS = 6
92 HG_TARGET_HAS_MULTIPLE_HEADS = 6
93
93
94 # The target repository is locked
94 # The target repository is locked
95 TARGET_IS_LOCKED = 7
95 TARGET_IS_LOCKED = 7
96
96
97 # Deprecated, use MISSING_TARGET_REF or MISSING_SOURCE_REF instead.
97 # Deprecated, use MISSING_TARGET_REF or MISSING_SOURCE_REF instead.
98 # A involved commit could not be found.
98 # A involved commit could not be found.
99 _DEPRECATED_MISSING_COMMIT = 8
99 _DEPRECATED_MISSING_COMMIT = 8
100
100
101 # The target repo reference is missing.
101 # The target repo reference is missing.
102 MISSING_TARGET_REF = 9
102 MISSING_TARGET_REF = 9
103
103
104 # The source repo reference is missing.
104 # The source repo reference is missing.
105 MISSING_SOURCE_REF = 10
105 MISSING_SOURCE_REF = 10
106
106
107 # The merge was not successful, there are conflicts related to sub
107 # The merge was not successful, there are conflicts related to sub
108 # repositories.
108 # repositories.
109 SUBREPO_MERGE_FAILED = 11
109 SUBREPO_MERGE_FAILED = 11
110
110
111
111
112 class UpdateFailureReason(object):
112 class UpdateFailureReason(object):
113 """
113 """
114 Enumeration with all the reasons why the pull request update could fail.
114 Enumeration with all the reasons why the pull request update could fail.
115
115
116 DO NOT change the number of the reasons, as they may be stored in the
116 DO NOT change the number of the reasons, as they may be stored in the
117 database.
117 database.
118
118
119 Changing the name of a reason is acceptable and encouraged to deprecate old
119 Changing the name of a reason is acceptable and encouraged to deprecate old
120 reasons.
120 reasons.
121 """
121 """
122
122
123 # Everything went well.
123 # Everything went well.
124 NONE = 0
124 NONE = 0
125
125
126 # An unexpected exception was raised. Check the logs for more details.
126 # An unexpected exception was raised. Check the logs for more details.
127 UNKNOWN = 1
127 UNKNOWN = 1
128
128
129 # The pull request is up to date.
129 # The pull request is up to date.
130 NO_CHANGE = 2
130 NO_CHANGE = 2
131
131
132 # The pull request has a reference type that is not supported for update.
132 # The pull request has a reference type that is not supported for update.
133 WRONG_REF_TPYE = 3
133 WRONG_REF_TPYE = 3
134
134
135 # Update failed because the target reference is missing.
135 # Update failed because the target reference is missing.
136 MISSING_TARGET_REF = 4
136 MISSING_TARGET_REF = 4
137
137
138 # Update failed because the source reference is missing.
138 # Update failed because the source reference is missing.
139 MISSING_SOURCE_REF = 5
139 MISSING_SOURCE_REF = 5
140
140
141
141
142 class BaseRepository(object):
142 class BaseRepository(object):
143 """
143 """
144 Base Repository for final backends
144 Base Repository for final backends
145
145
146 .. attribute:: DEFAULT_BRANCH_NAME
146 .. attribute:: DEFAULT_BRANCH_NAME
147
147
148 name of default branch (i.e. "trunk" for svn, "master" for git etc.
148 name of default branch (i.e. "trunk" for svn, "master" for git etc.
149
149
150 .. attribute:: commit_ids
150 .. attribute:: commit_ids
151
151
152 list of all available commit ids, in ascending order
152 list of all available commit ids, in ascending order
153
153
154 .. attribute:: path
154 .. attribute:: path
155
155
156 absolute path to the repository
156 absolute path to the repository
157
157
158 .. attribute:: bookmarks
158 .. attribute:: bookmarks
159
159
160 Mapping from name to :term:`Commit ID` of the bookmark. Empty in case
160 Mapping from name to :term:`Commit ID` of the bookmark. Empty in case
161 there are no bookmarks or the backend implementation does not support
161 there are no bookmarks or the backend implementation does not support
162 bookmarks.
162 bookmarks.
163
163
164 .. attribute:: tags
164 .. attribute:: tags
165
165
166 Mapping from name to :term:`Commit ID` of the tag.
166 Mapping from name to :term:`Commit ID` of the tag.
167
167
168 """
168 """
169
169
170 DEFAULT_BRANCH_NAME = None
170 DEFAULT_BRANCH_NAME = None
171 DEFAULT_CONTACT = u"Unknown"
171 DEFAULT_CONTACT = u"Unknown"
172 DEFAULT_DESCRIPTION = u"unknown"
172 DEFAULT_DESCRIPTION = u"unknown"
173 EMPTY_COMMIT_ID = '0' * 40
173 EMPTY_COMMIT_ID = '0' * 40
174
174
175 path = None
175 path = None
176
176
177 def __init__(self, repo_path, config=None, create=False, **kwargs):
177 def __init__(self, repo_path, config=None, create=False, **kwargs):
178 """
178 """
179 Initializes repository. Raises RepositoryError if repository could
179 Initializes repository. Raises RepositoryError if repository could
180 not be find at the given ``repo_path`` or directory at ``repo_path``
180 not be find at the given ``repo_path`` or directory at ``repo_path``
181 exists and ``create`` is set to True.
181 exists and ``create`` is set to True.
182
182
183 :param repo_path: local path of the repository
183 :param repo_path: local path of the repository
184 :param config: repository configuration
184 :param config: repository configuration
185 :param create=False: if set to True, would try to create repository.
185 :param create=False: if set to True, would try to create repository.
186 :param src_url=None: if set, should be proper url from which repository
186 :param src_url=None: if set, should be proper url from which repository
187 would be cloned; requires ``create`` parameter to be set to True -
187 would be cloned; requires ``create`` parameter to be set to True -
188 raises RepositoryError if src_url is set and create evaluates to
188 raises RepositoryError if src_url is set and create evaluates to
189 False
189 False
190 """
190 """
191 raise NotImplementedError
191 raise NotImplementedError
192
192
193 def __repr__(self):
193 def __repr__(self):
194 return '<%s at %s>' % (self.__class__.__name__, self.path)
194 return '<%s at %s>' % (self.__class__.__name__, self.path)
195
195
196 def __len__(self):
196 def __len__(self):
197 return self.count()
197 return self.count()
198
198
199 def __eq__(self, other):
199 def __eq__(self, other):
200 same_instance = isinstance(other, self.__class__)
200 same_instance = isinstance(other, self.__class__)
201 return same_instance and other.path == self.path
201 return same_instance and other.path == self.path
202
202
203 def __ne__(self, other):
203 def __ne__(self, other):
204 return not self.__eq__(other)
204 return not self.__eq__(other)
205
205
206 @LazyProperty
206 @LazyProperty
207 def EMPTY_COMMIT(self):
207 def EMPTY_COMMIT(self):
208 return EmptyCommit(self.EMPTY_COMMIT_ID)
208 return EmptyCommit(self.EMPTY_COMMIT_ID)
209
209
210 @LazyProperty
210 @LazyProperty
211 def alias(self):
211 def alias(self):
212 for k, v in settings.BACKENDS.items():
212 for k, v in settings.BACKENDS.items():
213 if v.split('.')[-1] == str(self.__class__.__name__):
213 if v.split('.')[-1] == str(self.__class__.__name__):
214 return k
214 return k
215
215
216 @LazyProperty
216 @LazyProperty
217 def name(self):
217 def name(self):
218 return safe_unicode(os.path.basename(self.path))
218 return safe_unicode(os.path.basename(self.path))
219
219
220 @LazyProperty
220 @LazyProperty
221 def description(self):
221 def description(self):
222 raise NotImplementedError
222 raise NotImplementedError
223
223
224 def refs(self):
224 def refs(self):
225 """
225 """
226 returns a `dict` with branches, bookmarks, tags, and closed_branches
226 returns a `dict` with branches, bookmarks, tags, and closed_branches
227 for this repository
227 for this repository
228 """
228 """
229 return dict(
229 return dict(
230 branches=self.branches,
230 branches=self.branches,
231 branches_closed=self.branches_closed,
231 branches_closed=self.branches_closed,
232 tags=self.tags,
232 tags=self.tags,
233 bookmarks=self.bookmarks
233 bookmarks=self.bookmarks
234 )
234 )
235
235
236 @LazyProperty
236 @LazyProperty
237 def branches(self):
237 def branches(self):
238 """
238 """
239 A `dict` which maps branch names to commit ids.
239 A `dict` which maps branch names to commit ids.
240 """
240 """
241 raise NotImplementedError
241 raise NotImplementedError
242
242
243 @LazyProperty
243 @LazyProperty
244 def tags(self):
244 def tags(self):
245 """
245 """
246 A `dict` which maps tags names to commit ids.
246 A `dict` which maps tags names to commit ids.
247 """
247 """
248 raise NotImplementedError
248 raise NotImplementedError
249
249
250 @LazyProperty
250 @LazyProperty
251 def size(self):
251 def size(self):
252 """
252 """
253 Returns combined size in bytes for all repository files
253 Returns combined size in bytes for all repository files
254 """
254 """
255 tip = self.get_commit()
255 tip = self.get_commit()
256 return tip.size
256 return tip.size
257
257
258 def size_at_commit(self, commit_id):
258 def size_at_commit(self, commit_id):
259 commit = self.get_commit(commit_id)
259 commit = self.get_commit(commit_id)
260 return commit.size
260 return commit.size
261
261
262 def is_empty(self):
262 def is_empty(self):
263 return not bool(self.commit_ids)
263 return not bool(self.commit_ids)
264
264
265 @staticmethod
265 @staticmethod
266 def check_url(url, config):
266 def check_url(url, config):
267 """
267 """
268 Function will check given url and try to verify if it's a valid
268 Function will check given url and try to verify if it's a valid
269 link.
269 link.
270 """
270 """
271 raise NotImplementedError
271 raise NotImplementedError
272
272
273 @staticmethod
273 @staticmethod
274 def is_valid_repository(path):
274 def is_valid_repository(path):
275 """
275 """
276 Check if given `path` contains a valid repository of this backend
276 Check if given `path` contains a valid repository of this backend
277 """
277 """
278 raise NotImplementedError
278 raise NotImplementedError
279
279
280 # ==========================================================================
280 # ==========================================================================
281 # COMMITS
281 # COMMITS
282 # ==========================================================================
282 # ==========================================================================
283
283
284 def get_commit(self, commit_id=None, commit_idx=None, pre_load=None):
284 def get_commit(self, commit_id=None, commit_idx=None, pre_load=None):
285 """
285 """
286 Returns instance of `BaseCommit` class. If `commit_id` and `commit_idx`
286 Returns instance of `BaseCommit` class. If `commit_id` and `commit_idx`
287 are both None, most recent commit is returned.
287 are both None, most recent commit is returned.
288
288
289 :param pre_load: Optional. List of commit attributes to load.
289 :param pre_load: Optional. List of commit attributes to load.
290
290
291 :raises ``EmptyRepositoryError``: if there are no commits
291 :raises ``EmptyRepositoryError``: if there are no commits
292 """
292 """
293 raise NotImplementedError
293 raise NotImplementedError
294
294
295 def __iter__(self):
295 def __iter__(self):
296 for commit_id in self.commit_ids:
296 for commit_id in self.commit_ids:
297 yield self.get_commit(commit_id=commit_id)
297 yield self.get_commit(commit_id=commit_id)
298
298
299 def get_commits(
299 def get_commits(
300 self, start_id=None, end_id=None, start_date=None, end_date=None,
300 self, start_id=None, end_id=None, start_date=None, end_date=None,
301 branch_name=None, pre_load=None):
301 branch_name=None, pre_load=None):
302 """
302 """
303 Returns iterator of `BaseCommit` objects from start to end
303 Returns iterator of `BaseCommit` objects from start to end
304 not inclusive. This should behave just like a list, ie. end is not
304 not inclusive. This should behave just like a list, ie. end is not
305 inclusive.
305 inclusive.
306
306
307 :param start_id: None or str, must be a valid commit id
307 :param start_id: None or str, must be a valid commit id
308 :param end_id: None or str, must be a valid commit id
308 :param end_id: None or str, must be a valid commit id
309 :param start_date:
309 :param start_date:
310 :param end_date:
310 :param end_date:
311 :param branch_name:
311 :param branch_name:
312 :param pre_load:
312 :param pre_load:
313 """
313 """
314 raise NotImplementedError
314 raise NotImplementedError
315
315
316 def __getitem__(self, key):
316 def __getitem__(self, key):
317 """
317 """
318 Allows index based access to the commit objects of this repository.
318 Allows index based access to the commit objects of this repository.
319 """
319 """
320 pre_load = ["author", "branch", "date", "message", "parents"]
320 pre_load = ["author", "branch", "date", "message", "parents"]
321 if isinstance(key, slice):
321 if isinstance(key, slice):
322 return self._get_range(key, pre_load)
322 return self._get_range(key, pre_load)
323 return self.get_commit(commit_idx=key, pre_load=pre_load)
323 return self.get_commit(commit_idx=key, pre_load=pre_load)
324
324
325 def _get_range(self, slice_obj, pre_load):
325 def _get_range(self, slice_obj, pre_load):
326 for commit_id in self.commit_ids.__getitem__(slice_obj):
326 for commit_id in self.commit_ids.__getitem__(slice_obj):
327 yield self.get_commit(commit_id=commit_id, pre_load=pre_load)
327 yield self.get_commit(commit_id=commit_id, pre_load=pre_load)
328
328
329 def count(self):
329 def count(self):
330 return len(self.commit_ids)
330 return len(self.commit_ids)
331
331
332 def tag(self, name, user, commit_id=None, message=None, date=None, **opts):
332 def tag(self, name, user, commit_id=None, message=None, date=None, **opts):
333 """
333 """
334 Creates and returns a tag for the given ``commit_id``.
334 Creates and returns a tag for the given ``commit_id``.
335
335
336 :param name: name for new tag
336 :param name: name for new tag
337 :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
337 :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
338 :param commit_id: commit id for which new tag would be created
338 :param commit_id: commit id for which new tag would be created
339 :param message: message of the tag's commit
339 :param message: message of the tag's commit
340 :param date: date of tag's commit
340 :param date: date of tag's commit
341
341
342 :raises TagAlreadyExistError: if tag with same name already exists
342 :raises TagAlreadyExistError: if tag with same name already exists
343 """
343 """
344 raise NotImplementedError
344 raise NotImplementedError
345
345
346 def remove_tag(self, name, user, message=None, date=None):
346 def remove_tag(self, name, user, message=None, date=None):
347 """
347 """
348 Removes tag with the given ``name``.
348 Removes tag with the given ``name``.
349
349
350 :param name: name of the tag to be removed
350 :param name: name of the tag to be removed
351 :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
351 :param user: full username, i.e.: "Joe Doe <joe.doe@example.com>"
352 :param message: message of the tag's removal commit
352 :param message: message of the tag's removal commit
353 :param date: date of tag's removal commit
353 :param date: date of tag's removal commit
354
354
355 :raises TagDoesNotExistError: if tag with given name does not exists
355 :raises TagDoesNotExistError: if tag with given name does not exists
356 """
356 """
357 raise NotImplementedError
357 raise NotImplementedError
358
358
359 def get_diff(
359 def get_diff(
360 self, commit1, commit2, path=None, ignore_whitespace=False,
360 self, commit1, commit2, path=None, ignore_whitespace=False,
361 context=3, path1=None):
361 context=3, path1=None):
362 """
362 """
363 Returns (git like) *diff*, as plain text. Shows changes introduced by
363 Returns (git like) *diff*, as plain text. Shows changes introduced by
364 `commit2` since `commit1`.
364 `commit2` since `commit1`.
365
365
366 :param commit1: Entry point from which diff is shown. Can be
366 :param commit1: Entry point from which diff is shown. Can be
367 ``self.EMPTY_COMMIT`` - in this case, patch showing all
367 ``self.EMPTY_COMMIT`` - in this case, patch showing all
368 the changes since empty state of the repository until `commit2`
368 the changes since empty state of the repository until `commit2`
369 :param commit2: Until which commit changes should be shown.
369 :param commit2: Until which commit changes should be shown.
370 :param path: Can be set to a path of a file to create a diff of that
370 :param path: Can be set to a path of a file to create a diff of that
371 file. If `path1` is also set, this value is only associated to
371 file. If `path1` is also set, this value is only associated to
372 `commit2`.
372 `commit2`.
373 :param ignore_whitespace: If set to ``True``, would not show whitespace
373 :param ignore_whitespace: If set to ``True``, would not show whitespace
374 changes. Defaults to ``False``.
374 changes. Defaults to ``False``.
375 :param context: How many lines before/after changed lines should be
375 :param context: How many lines before/after changed lines should be
376 shown. Defaults to ``3``.
376 shown. Defaults to ``3``.
377 :param path1: Can be set to a path to associate with `commit1`. This
377 :param path1: Can be set to a path to associate with `commit1`. This
378 parameter works only for backends which support diff generation for
378 parameter works only for backends which support diff generation for
379 different paths. Other backends will raise a `ValueError` if `path1`
379 different paths. Other backends will raise a `ValueError` if `path1`
380 is set and has a different value than `path`.
380 is set and has a different value than `path`.
381 :param file_path: filter this diff by given path pattern
381 """
382 """
382 raise NotImplementedError
383 raise NotImplementedError
383
384
384 def strip(self, commit_id, branch=None):
385 def strip(self, commit_id, branch=None):
385 """
386 """
386 Strip given commit_id from the repository
387 Strip given commit_id from the repository
387 """
388 """
388 raise NotImplementedError
389 raise NotImplementedError
389
390
390 def get_common_ancestor(self, commit_id1, commit_id2, repo2):
391 def get_common_ancestor(self, commit_id1, commit_id2, repo2):
391 """
392 """
392 Return a latest common ancestor commit if one exists for this repo
393 Return a latest common ancestor commit if one exists for this repo
393 `commit_id1` vs `commit_id2` from `repo2`.
394 `commit_id1` vs `commit_id2` from `repo2`.
394
395
395 :param commit_id1: Commit it from this repository to use as a
396 :param commit_id1: Commit it from this repository to use as a
396 target for the comparison.
397 target for the comparison.
397 :param commit_id2: Source commit id to use for comparison.
398 :param commit_id2: Source commit id to use for comparison.
398 :param repo2: Source repository to use for comparison.
399 :param repo2: Source repository to use for comparison.
399 """
400 """
400 raise NotImplementedError
401 raise NotImplementedError
401
402
402 def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None):
403 def compare(self, commit_id1, commit_id2, repo2, merge, pre_load=None):
403 """
404 """
404 Compare this repository's revision `commit_id1` with `commit_id2`.
405 Compare this repository's revision `commit_id1` with `commit_id2`.
405
406
406 Returns a tuple(commits, ancestor) that would be merged from
407 Returns a tuple(commits, ancestor) that would be merged from
407 `commit_id2`. Doing a normal compare (``merge=False``), ``None``
408 `commit_id2`. Doing a normal compare (``merge=False``), ``None``
408 will be returned as ancestor.
409 will be returned as ancestor.
409
410
410 :param commit_id1: Commit it from this repository to use as a
411 :param commit_id1: Commit it from this repository to use as a
411 target for the comparison.
412 target for the comparison.
412 :param commit_id2: Source commit id to use for comparison.
413 :param commit_id2: Source commit id to use for comparison.
413 :param repo2: Source repository to use for comparison.
414 :param repo2: Source repository to use for comparison.
414 :param merge: If set to ``True`` will do a merge compare which also
415 :param merge: If set to ``True`` will do a merge compare which also
415 returns the common ancestor.
416 returns the common ancestor.
416 :param pre_load: Optional. List of commit attributes to load.
417 :param pre_load: Optional. List of commit attributes to load.
417 """
418 """
418 raise NotImplementedError
419 raise NotImplementedError
419
420
420 def merge(self, target_ref, source_repo, source_ref, workspace_id,
421 def merge(self, target_ref, source_repo, source_ref, workspace_id,
421 user_name='', user_email='', message='', dry_run=False,
422 user_name='', user_email='', message='', dry_run=False,
422 use_rebase=False):
423 use_rebase=False):
423 """
424 """
424 Merge the revisions specified in `source_ref` from `source_repo`
425 Merge the revisions specified in `source_ref` from `source_repo`
425 onto the `target_ref` of this repository.
426 onto the `target_ref` of this repository.
426
427
427 `source_ref` and `target_ref` are named tupls with the following
428 `source_ref` and `target_ref` are named tupls with the following
428 fields `type`, `name` and `commit_id`.
429 fields `type`, `name` and `commit_id`.
429
430
430 Returns a MergeResponse named tuple with the following fields
431 Returns a MergeResponse named tuple with the following fields
431 'possible', 'executed', 'source_commit', 'target_commit',
432 'possible', 'executed', 'source_commit', 'target_commit',
432 'merge_commit'.
433 'merge_commit'.
433
434
434 :param target_ref: `target_ref` points to the commit on top of which
435 :param target_ref: `target_ref` points to the commit on top of which
435 the `source_ref` should be merged.
436 the `source_ref` should be merged.
436 :param source_repo: The repository that contains the commits to be
437 :param source_repo: The repository that contains the commits to be
437 merged.
438 merged.
438 :param source_ref: `source_ref` points to the topmost commit from
439 :param source_ref: `source_ref` points to the topmost commit from
439 the `source_repo` which should be merged.
440 the `source_repo` which should be merged.
440 :param workspace_id: `workspace_id` unique identifier.
441 :param workspace_id: `workspace_id` unique identifier.
441 :param user_name: Merge commit `user_name`.
442 :param user_name: Merge commit `user_name`.
442 :param user_email: Merge commit `user_email`.
443 :param user_email: Merge commit `user_email`.
443 :param message: Merge commit `message`.
444 :param message: Merge commit `message`.
444 :param dry_run: If `True` the merge will not take place.
445 :param dry_run: If `True` the merge will not take place.
445 :param use_rebase: If `True` commits from the source will be rebased
446 :param use_rebase: If `True` commits from the source will be rebased
446 on top of the target instead of being merged.
447 on top of the target instead of being merged.
447 """
448 """
448 if dry_run:
449 if dry_run:
449 message = message or 'dry_run_merge_message'
450 message = message or 'dry_run_merge_message'
450 user_email = user_email or 'dry-run-merge@rhodecode.com'
451 user_email = user_email or 'dry-run-merge@rhodecode.com'
451 user_name = user_name or 'Dry-Run User'
452 user_name = user_name or 'Dry-Run User'
452 else:
453 else:
453 if not user_name:
454 if not user_name:
454 raise ValueError('user_name cannot be empty')
455 raise ValueError('user_name cannot be empty')
455 if not user_email:
456 if not user_email:
456 raise ValueError('user_email cannot be empty')
457 raise ValueError('user_email cannot be empty')
457 if not message:
458 if not message:
458 raise ValueError('message cannot be empty')
459 raise ValueError('message cannot be empty')
459
460
460 shadow_repository_path = self._maybe_prepare_merge_workspace(
461 shadow_repository_path = self._maybe_prepare_merge_workspace(
461 workspace_id, target_ref)
462 workspace_id, target_ref)
462
463
463 try:
464 try:
464 return self._merge_repo(
465 return self._merge_repo(
465 shadow_repository_path, target_ref, source_repo,
466 shadow_repository_path, target_ref, source_repo,
466 source_ref, message, user_name, user_email, dry_run=dry_run,
467 source_ref, message, user_name, user_email, dry_run=dry_run,
467 use_rebase=use_rebase)
468 use_rebase=use_rebase)
468 except RepositoryError:
469 except RepositoryError:
469 log.exception(
470 log.exception(
470 'Unexpected failure when running merge, dry-run=%s',
471 'Unexpected failure when running merge, dry-run=%s',
471 dry_run)
472 dry_run)
472 return MergeResponse(
473 return MergeResponse(
473 False, False, None, MergeFailureReason.UNKNOWN)
474 False, False, None, MergeFailureReason.UNKNOWN)
474
475
475 def _merge_repo(self, shadow_repository_path, target_ref,
476 def _merge_repo(self, shadow_repository_path, target_ref,
476 source_repo, source_ref, merge_message,
477 source_repo, source_ref, merge_message,
477 merger_name, merger_email, dry_run=False, use_rebase=False):
478 merger_name, merger_email, dry_run=False, use_rebase=False):
478 """Internal implementation of merge."""
479 """Internal implementation of merge."""
479 raise NotImplementedError
480 raise NotImplementedError
480
481
481 def _maybe_prepare_merge_workspace(self, workspace_id, target_ref):
482 def _maybe_prepare_merge_workspace(self, workspace_id, target_ref):
482 """
483 """
483 Create the merge workspace.
484 Create the merge workspace.
484
485
485 :param workspace_id: `workspace_id` unique identifier.
486 :param workspace_id: `workspace_id` unique identifier.
486 """
487 """
487 raise NotImplementedError
488 raise NotImplementedError
488
489
489 def cleanup_merge_workspace(self, workspace_id):
490 def cleanup_merge_workspace(self, workspace_id):
490 """
491 """
491 Remove merge workspace.
492 Remove merge workspace.
492
493
493 This function MUST not fail in case there is no workspace associated to
494 This function MUST not fail in case there is no workspace associated to
494 the given `workspace_id`.
495 the given `workspace_id`.
495
496
496 :param workspace_id: `workspace_id` unique identifier.
497 :param workspace_id: `workspace_id` unique identifier.
497 """
498 """
498 raise NotImplementedError
499 raise NotImplementedError
499
500
500 # ========== #
501 # ========== #
501 # COMMIT API #
502 # COMMIT API #
502 # ========== #
503 # ========== #
503
504
504 @LazyProperty
505 @LazyProperty
505 def in_memory_commit(self):
506 def in_memory_commit(self):
506 """
507 """
507 Returns :class:`InMemoryCommit` object for this repository.
508 Returns :class:`InMemoryCommit` object for this repository.
508 """
509 """
509 raise NotImplementedError
510 raise NotImplementedError
510
511
511 # ======================== #
512 # ======================== #
512 # UTILITIES FOR SUBCLASSES #
513 # UTILITIES FOR SUBCLASSES #
513 # ======================== #
514 # ======================== #
514
515
515 def _validate_diff_commits(self, commit1, commit2):
516 def _validate_diff_commits(self, commit1, commit2):
516 """
517 """
517 Validates that the given commits are related to this repository.
518 Validates that the given commits are related to this repository.
518
519
519 Intended as a utility for sub classes to have a consistent validation
520 Intended as a utility for sub classes to have a consistent validation
520 of input parameters in methods like :meth:`get_diff`.
521 of input parameters in methods like :meth:`get_diff`.
521 """
522 """
522 self._validate_commit(commit1)
523 self._validate_commit(commit1)
523 self._validate_commit(commit2)
524 self._validate_commit(commit2)
524 if (isinstance(commit1, EmptyCommit) and
525 if (isinstance(commit1, EmptyCommit) and
525 isinstance(commit2, EmptyCommit)):
526 isinstance(commit2, EmptyCommit)):
526 raise ValueError("Cannot compare two empty commits")
527 raise ValueError("Cannot compare two empty commits")
527
528
528 def _validate_commit(self, commit):
529 def _validate_commit(self, commit):
529 if not isinstance(commit, BaseCommit):
530 if not isinstance(commit, BaseCommit):
530 raise TypeError(
531 raise TypeError(
531 "%s is not of type BaseCommit" % repr(commit))
532 "%s is not of type BaseCommit" % repr(commit))
532 if commit.repository != self and not isinstance(commit, EmptyCommit):
533 if commit.repository != self and not isinstance(commit, EmptyCommit):
533 raise ValueError(
534 raise ValueError(
534 "Commit %s must be a valid commit from this repository %s, "
535 "Commit %s must be a valid commit from this repository %s, "
535 "related to this repository instead %s." %
536 "related to this repository instead %s." %
536 (commit, self, commit.repository))
537 (commit, self, commit.repository))
537
538
538 def _validate_commit_id(self, commit_id):
539 def _validate_commit_id(self, commit_id):
539 if not isinstance(commit_id, basestring):
540 if not isinstance(commit_id, basestring):
540 raise TypeError("commit_id must be a string value")
541 raise TypeError("commit_id must be a string value")
541
542
542 def _validate_commit_idx(self, commit_idx):
543 def _validate_commit_idx(self, commit_idx):
543 if not isinstance(commit_idx, (int, long)):
544 if not isinstance(commit_idx, (int, long)):
544 raise TypeError("commit_idx must be a numeric value")
545 raise TypeError("commit_idx must be a numeric value")
545
546
546 def _validate_branch_name(self, branch_name):
547 def _validate_branch_name(self, branch_name):
547 if branch_name and branch_name not in self.branches_all:
548 if branch_name and branch_name not in self.branches_all:
548 msg = ("Branch %s not found in %s" % (branch_name, self))
549 msg = ("Branch %s not found in %s" % (branch_name, self))
549 raise BranchDoesNotExistError(msg)
550 raise BranchDoesNotExistError(msg)
550
551
551 #
552 #
552 # Supporting deprecated API parts
553 # Supporting deprecated API parts
553 # TODO: johbo: consider to move this into a mixin
554 # TODO: johbo: consider to move this into a mixin
554 #
555 #
555
556
556 @property
557 @property
557 def EMPTY_CHANGESET(self):
558 def EMPTY_CHANGESET(self):
558 warnings.warn(
559 warnings.warn(
559 "Use EMPTY_COMMIT or EMPTY_COMMIT_ID instead", DeprecationWarning)
560 "Use EMPTY_COMMIT or EMPTY_COMMIT_ID instead", DeprecationWarning)
560 return self.EMPTY_COMMIT_ID
561 return self.EMPTY_COMMIT_ID
561
562
562 @property
563 @property
563 def revisions(self):
564 def revisions(self):
564 warnings.warn("Use commits attribute instead", DeprecationWarning)
565 warnings.warn("Use commits attribute instead", DeprecationWarning)
565 return self.commit_ids
566 return self.commit_ids
566
567
567 @revisions.setter
568 @revisions.setter
568 def revisions(self, value):
569 def revisions(self, value):
569 warnings.warn("Use commits attribute instead", DeprecationWarning)
570 warnings.warn("Use commits attribute instead", DeprecationWarning)
570 self.commit_ids = value
571 self.commit_ids = value
571
572
572 def get_changeset(self, revision=None, pre_load=None):
573 def get_changeset(self, revision=None, pre_load=None):
573 warnings.warn("Use get_commit instead", DeprecationWarning)
574 warnings.warn("Use get_commit instead", DeprecationWarning)
574 commit_id = None
575 commit_id = None
575 commit_idx = None
576 commit_idx = None
576 if isinstance(revision, basestring):
577 if isinstance(revision, basestring):
577 commit_id = revision
578 commit_id = revision
578 else:
579 else:
579 commit_idx = revision
580 commit_idx = revision
580 return self.get_commit(
581 return self.get_commit(
581 commit_id=commit_id, commit_idx=commit_idx, pre_load=pre_load)
582 commit_id=commit_id, commit_idx=commit_idx, pre_load=pre_load)
582
583
583 def get_changesets(
584 def get_changesets(
584 self, start=None, end=None, start_date=None, end_date=None,
585 self, start=None, end=None, start_date=None, end_date=None,
585 branch_name=None, pre_load=None):
586 branch_name=None, pre_load=None):
586 warnings.warn("Use get_commits instead", DeprecationWarning)
587 warnings.warn("Use get_commits instead", DeprecationWarning)
587 start_id = self._revision_to_commit(start)
588 start_id = self._revision_to_commit(start)
588 end_id = self._revision_to_commit(end)
589 end_id = self._revision_to_commit(end)
589 return self.get_commits(
590 return self.get_commits(
590 start_id=start_id, end_id=end_id, start_date=start_date,
591 start_id=start_id, end_id=end_id, start_date=start_date,
591 end_date=end_date, branch_name=branch_name, pre_load=pre_load)
592 end_date=end_date, branch_name=branch_name, pre_load=pre_load)
592
593
593 def _revision_to_commit(self, revision):
594 def _revision_to_commit(self, revision):
594 """
595 """
595 Translates a revision to a commit_id
596 Translates a revision to a commit_id
596
597
597 Helps to support the old changeset based API which allows to use
598 Helps to support the old changeset based API which allows to use
598 commit ids and commit indices interchangeable.
599 commit ids and commit indices interchangeable.
599 """
600 """
600 if revision is None:
601 if revision is None:
601 return revision
602 return revision
602
603
603 if isinstance(revision, basestring):
604 if isinstance(revision, basestring):
604 commit_id = revision
605 commit_id = revision
605 else:
606 else:
606 commit_id = self.commit_ids[revision]
607 commit_id = self.commit_ids[revision]
607 return commit_id
608 return commit_id
608
609
609 @property
610 @property
610 def in_memory_changeset(self):
611 def in_memory_changeset(self):
611 warnings.warn("Use in_memory_commit instead", DeprecationWarning)
612 warnings.warn("Use in_memory_commit instead", DeprecationWarning)
612 return self.in_memory_commit
613 return self.in_memory_commit
613
614
614
615
615 class BaseCommit(object):
616 class BaseCommit(object):
616 """
617 """
617 Each backend should implement it's commit representation.
618 Each backend should implement it's commit representation.
618
619
619 **Attributes**
620 **Attributes**
620
621
621 ``repository``
622 ``repository``
622 repository object within which commit exists
623 repository object within which commit exists
623
624
624 ``id``
625 ``id``
625 The commit id, may be ``raw_id`` or i.e. for mercurial's tip
626 The commit id, may be ``raw_id`` or i.e. for mercurial's tip
626 just ``tip``.
627 just ``tip``.
627
628
628 ``raw_id``
629 ``raw_id``
629 raw commit representation (i.e. full 40 length sha for git
630 raw commit representation (i.e. full 40 length sha for git
630 backend)
631 backend)
631
632
632 ``short_id``
633 ``short_id``
633 shortened (if apply) version of ``raw_id``; it would be simple
634 shortened (if apply) version of ``raw_id``; it would be simple
634 shortcut for ``raw_id[:12]`` for git/mercurial backends or same
635 shortcut for ``raw_id[:12]`` for git/mercurial backends or same
635 as ``raw_id`` for subversion
636 as ``raw_id`` for subversion
636
637
637 ``idx``
638 ``idx``
638 commit index
639 commit index
639
640
640 ``files``
641 ``files``
641 list of ``FileNode`` (``Node`` with NodeKind.FILE) objects
642 list of ``FileNode`` (``Node`` with NodeKind.FILE) objects
642
643
643 ``dirs``
644 ``dirs``
644 list of ``DirNode`` (``Node`` with NodeKind.DIR) objects
645 list of ``DirNode`` (``Node`` with NodeKind.DIR) objects
645
646
646 ``nodes``
647 ``nodes``
647 combined list of ``Node`` objects
648 combined list of ``Node`` objects
648
649
649 ``author``
650 ``author``
650 author of the commit, as unicode
651 author of the commit, as unicode
651
652
652 ``message``
653 ``message``
653 message of the commit, as unicode
654 message of the commit, as unicode
654
655
655 ``parents``
656 ``parents``
656 list of parent commits
657 list of parent commits
657
658
658 """
659 """
659
660
660 branch = None
661 branch = None
661 """
662 """
662 Depending on the backend this should be set to the branch name of the
663 Depending on the backend this should be set to the branch name of the
663 commit. Backends not supporting branches on commits should leave this
664 commit. Backends not supporting branches on commits should leave this
664 value as ``None``.
665 value as ``None``.
665 """
666 """
666
667
667 _ARCHIVE_PREFIX_TEMPLATE = b'{repo_name}-{short_id}'
668 _ARCHIVE_PREFIX_TEMPLATE = b'{repo_name}-{short_id}'
668 """
669 """
669 This template is used to generate a default prefix for repository archives
670 This template is used to generate a default prefix for repository archives
670 if no prefix has been specified.
671 if no prefix has been specified.
671 """
672 """
672
673
673 def __str__(self):
674 def __str__(self):
674 return '<%s at %s:%s>' % (
675 return '<%s at %s:%s>' % (
675 self.__class__.__name__, self.idx, self.short_id)
676 self.__class__.__name__, self.idx, self.short_id)
676
677
677 def __repr__(self):
678 def __repr__(self):
678 return self.__str__()
679 return self.__str__()
679
680
680 def __unicode__(self):
681 def __unicode__(self):
681 return u'%s:%s' % (self.idx, self.short_id)
682 return u'%s:%s' % (self.idx, self.short_id)
682
683
683 def __eq__(self, other):
684 def __eq__(self, other):
684 same_instance = isinstance(other, self.__class__)
685 same_instance = isinstance(other, self.__class__)
685 return same_instance and self.raw_id == other.raw_id
686 return same_instance and self.raw_id == other.raw_id
686
687
687 def __json__(self):
688 def __json__(self):
688 parents = []
689 parents = []
689 try:
690 try:
690 for parent in self.parents:
691 for parent in self.parents:
691 parents.append({'raw_id': parent.raw_id})
692 parents.append({'raw_id': parent.raw_id})
692 except NotImplementedError:
693 except NotImplementedError:
693 # empty commit doesn't have parents implemented
694 # empty commit doesn't have parents implemented
694 pass
695 pass
695
696
696 return {
697 return {
697 'short_id': self.short_id,
698 'short_id': self.short_id,
698 'raw_id': self.raw_id,
699 'raw_id': self.raw_id,
699 'revision': self.idx,
700 'revision': self.idx,
700 'message': self.message,
701 'message': self.message,
701 'date': self.date,
702 'date': self.date,
702 'author': self.author,
703 'author': self.author,
703 'parents': parents,
704 'parents': parents,
704 'branch': self.branch
705 'branch': self.branch
705 }
706 }
706
707
707 @LazyProperty
708 @LazyProperty
708 def last(self):
709 def last(self):
709 """
710 """
710 ``True`` if this is last commit in repository, ``False``
711 ``True`` if this is last commit in repository, ``False``
711 otherwise; trying to access this attribute while there is no
712 otherwise; trying to access this attribute while there is no
712 commits would raise `EmptyRepositoryError`
713 commits would raise `EmptyRepositoryError`
713 """
714 """
714 if self.repository is None:
715 if self.repository is None:
715 raise CommitError("Cannot check if it's most recent commit")
716 raise CommitError("Cannot check if it's most recent commit")
716 return self.raw_id == self.repository.commit_ids[-1]
717 return self.raw_id == self.repository.commit_ids[-1]
717
718
718 @LazyProperty
719 @LazyProperty
719 def parents(self):
720 def parents(self):
720 """
721 """
721 Returns list of parent commits.
722 Returns list of parent commits.
722 """
723 """
723 raise NotImplementedError
724 raise NotImplementedError
724
725
725 @property
726 @property
726 def merge(self):
727 def merge(self):
727 """
728 """
728 Returns boolean if commit is a merge.
729 Returns boolean if commit is a merge.
729 """
730 """
730 return len(self.parents) > 1
731 return len(self.parents) > 1
731
732
732 @LazyProperty
733 @LazyProperty
733 def children(self):
734 def children(self):
734 """
735 """
735 Returns list of child commits.
736 Returns list of child commits.
736 """
737 """
737 raise NotImplementedError
738 raise NotImplementedError
738
739
739 @LazyProperty
740 @LazyProperty
740 def id(self):
741 def id(self):
741 """
742 """
742 Returns string identifying this commit.
743 Returns string identifying this commit.
743 """
744 """
744 raise NotImplementedError
745 raise NotImplementedError
745
746
746 @LazyProperty
747 @LazyProperty
747 def raw_id(self):
748 def raw_id(self):
748 """
749 """
749 Returns raw string identifying this commit.
750 Returns raw string identifying this commit.
750 """
751 """
751 raise NotImplementedError
752 raise NotImplementedError
752
753
753 @LazyProperty
754 @LazyProperty
754 def short_id(self):
755 def short_id(self):
755 """
756 """
756 Returns shortened version of ``raw_id`` attribute, as string,
757 Returns shortened version of ``raw_id`` attribute, as string,
757 identifying this commit, useful for presentation to users.
758 identifying this commit, useful for presentation to users.
758 """
759 """
759 raise NotImplementedError
760 raise NotImplementedError
760
761
761 @LazyProperty
762 @LazyProperty
762 def idx(self):
763 def idx(self):
763 """
764 """
764 Returns integer identifying this commit.
765 Returns integer identifying this commit.
765 """
766 """
766 raise NotImplementedError
767 raise NotImplementedError
767
768
768 @LazyProperty
769 @LazyProperty
769 def committer(self):
770 def committer(self):
770 """
771 """
771 Returns committer for this commit
772 Returns committer for this commit
772 """
773 """
773 raise NotImplementedError
774 raise NotImplementedError
774
775
775 @LazyProperty
776 @LazyProperty
776 def committer_name(self):
777 def committer_name(self):
777 """
778 """
778 Returns committer name for this commit
779 Returns committer name for this commit
779 """
780 """
780
781
781 return author_name(self.committer)
782 return author_name(self.committer)
782
783
783 @LazyProperty
784 @LazyProperty
784 def committer_email(self):
785 def committer_email(self):
785 """
786 """
786 Returns committer email address for this commit
787 Returns committer email address for this commit
787 """
788 """
788
789
789 return author_email(self.committer)
790 return author_email(self.committer)
790
791
791 @LazyProperty
792 @LazyProperty
792 def author(self):
793 def author(self):
793 """
794 """
794 Returns author for this commit
795 Returns author for this commit
795 """
796 """
796
797
797 raise NotImplementedError
798 raise NotImplementedError
798
799
799 @LazyProperty
800 @LazyProperty
800 def author_name(self):
801 def author_name(self):
801 """
802 """
802 Returns author name for this commit
803 Returns author name for this commit
803 """
804 """
804
805
805 return author_name(self.author)
806 return author_name(self.author)
806
807
807 @LazyProperty
808 @LazyProperty
808 def author_email(self):
809 def author_email(self):
809 """
810 """
810 Returns author email address for this commit
811 Returns author email address for this commit
811 """
812 """
812
813
813 return author_email(self.author)
814 return author_email(self.author)
814
815
815 def get_file_mode(self, path):
816 def get_file_mode(self, path):
816 """
817 """
817 Returns stat mode of the file at `path`.
818 Returns stat mode of the file at `path`.
818 """
819 """
819 raise NotImplementedError
820 raise NotImplementedError
820
821
821 def is_link(self, path):
822 def is_link(self, path):
822 """
823 """
823 Returns ``True`` if given `path` is a symlink
824 Returns ``True`` if given `path` is a symlink
824 """
825 """
825 raise NotImplementedError
826 raise NotImplementedError
826
827
827 def get_file_content(self, path):
828 def get_file_content(self, path):
828 """
829 """
829 Returns content of the file at the given `path`.
830 Returns content of the file at the given `path`.
830 """
831 """
831 raise NotImplementedError
832 raise NotImplementedError
832
833
833 def get_file_size(self, path):
834 def get_file_size(self, path):
834 """
835 """
835 Returns size of the file at the given `path`.
836 Returns size of the file at the given `path`.
836 """
837 """
837 raise NotImplementedError
838 raise NotImplementedError
838
839
839 def get_file_commit(self, path, pre_load=None):
840 def get_file_commit(self, path, pre_load=None):
840 """
841 """
841 Returns last commit of the file at the given `path`.
842 Returns last commit of the file at the given `path`.
842
843
843 :param pre_load: Optional. List of commit attributes to load.
844 :param pre_load: Optional. List of commit attributes to load.
844 """
845 """
845 commits = self.get_file_history(path, limit=1, pre_load=pre_load)
846 commits = self.get_file_history(path, limit=1, pre_load=pre_load)
846 if not commits:
847 if not commits:
847 raise RepositoryError(
848 raise RepositoryError(
848 'Failed to fetch history for path {}. '
849 'Failed to fetch history for path {}. '
849 'Please check if such path exists in your repository'.format(
850 'Please check if such path exists in your repository'.format(
850 path))
851 path))
851 return commits[0]
852 return commits[0]
852
853
853 def get_file_history(self, path, limit=None, pre_load=None):
854 def get_file_history(self, path, limit=None, pre_load=None):
854 """
855 """
855 Returns history of file as reversed list of :class:`BaseCommit`
856 Returns history of file as reversed list of :class:`BaseCommit`
856 objects for which file at given `path` has been modified.
857 objects for which file at given `path` has been modified.
857
858
858 :param limit: Optional. Allows to limit the size of the returned
859 :param limit: Optional. Allows to limit the size of the returned
859 history. This is intended as a hint to the underlying backend, so
860 history. This is intended as a hint to the underlying backend, so
860 that it can apply optimizations depending on the limit.
861 that it can apply optimizations depending on the limit.
861 :param pre_load: Optional. List of commit attributes to load.
862 :param pre_load: Optional. List of commit attributes to load.
862 """
863 """
863 raise NotImplementedError
864 raise NotImplementedError
864
865
865 def get_file_annotate(self, path, pre_load=None):
866 def get_file_annotate(self, path, pre_load=None):
866 """
867 """
867 Returns a generator of four element tuples with
868 Returns a generator of four element tuples with
868 lineno, sha, commit lazy loader and line
869 lineno, sha, commit lazy loader and line
869
870
870 :param pre_load: Optional. List of commit attributes to load.
871 :param pre_load: Optional. List of commit attributes to load.
871 """
872 """
872 raise NotImplementedError
873 raise NotImplementedError
873
874
874 def get_nodes(self, path):
875 def get_nodes(self, path):
875 """
876 """
876 Returns combined ``DirNode`` and ``FileNode`` objects list representing
877 Returns combined ``DirNode`` and ``FileNode`` objects list representing
877 state of commit at the given ``path``.
878 state of commit at the given ``path``.
878
879
879 :raises ``CommitError``: if node at the given ``path`` is not
880 :raises ``CommitError``: if node at the given ``path`` is not
880 instance of ``DirNode``
881 instance of ``DirNode``
881 """
882 """
882 raise NotImplementedError
883 raise NotImplementedError
883
884
884 def get_node(self, path):
885 def get_node(self, path):
885 """
886 """
886 Returns ``Node`` object from the given ``path``.
887 Returns ``Node`` object from the given ``path``.
887
888
888 :raises ``NodeDoesNotExistError``: if there is no node at the given
889 :raises ``NodeDoesNotExistError``: if there is no node at the given
889 ``path``
890 ``path``
890 """
891 """
891 raise NotImplementedError
892 raise NotImplementedError
892
893
893 def get_largefile_node(self, path):
894 def get_largefile_node(self, path):
894 """
895 """
895 Returns the path to largefile from Mercurial storage.
896 Returns the path to largefile from Mercurial storage.
896 """
897 """
897 raise NotImplementedError
898 raise NotImplementedError
898
899
899 def archive_repo(self, file_path, kind='tgz', subrepos=None,
900 def archive_repo(self, file_path, kind='tgz', subrepos=None,
900 prefix=None, write_metadata=False, mtime=None):
901 prefix=None, write_metadata=False, mtime=None):
901 """
902 """
902 Creates an archive containing the contents of the repository.
903 Creates an archive containing the contents of the repository.
903
904
904 :param file_path: path to the file which to create the archive.
905 :param file_path: path to the file which to create the archive.
905 :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``.
906 :param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``.
906 :param prefix: name of root directory in archive.
907 :param prefix: name of root directory in archive.
907 Default is repository name and commit's short_id joined with dash:
908 Default is repository name and commit's short_id joined with dash:
908 ``"{repo_name}-{short_id}"``.
909 ``"{repo_name}-{short_id}"``.
909 :param write_metadata: write a metadata file into archive.
910 :param write_metadata: write a metadata file into archive.
910 :param mtime: custom modification time for archive creation, defaults
911 :param mtime: custom modification time for archive creation, defaults
911 to time.time() if not given.
912 to time.time() if not given.
912
913
913 :raise VCSError: If prefix has a problem.
914 :raise VCSError: If prefix has a problem.
914 """
915 """
915 allowed_kinds = settings.ARCHIVE_SPECS.keys()
916 allowed_kinds = settings.ARCHIVE_SPECS.keys()
916 if kind not in allowed_kinds:
917 if kind not in allowed_kinds:
917 raise ImproperArchiveTypeError(
918 raise ImproperArchiveTypeError(
918 'Archive kind (%s) not supported use one of %s' %
919 'Archive kind (%s) not supported use one of %s' %
919 (kind, allowed_kinds))
920 (kind, allowed_kinds))
920
921
921 prefix = self._validate_archive_prefix(prefix)
922 prefix = self._validate_archive_prefix(prefix)
922
923
923 mtime = mtime or time.mktime(self.date.timetuple())
924 mtime = mtime or time.mktime(self.date.timetuple())
924
925
925 file_info = []
926 file_info = []
926 cur_rev = self.repository.get_commit(commit_id=self.raw_id)
927 cur_rev = self.repository.get_commit(commit_id=self.raw_id)
927 for _r, _d, files in cur_rev.walk('/'):
928 for _r, _d, files in cur_rev.walk('/'):
928 for f in files:
929 for f in files:
929 f_path = os.path.join(prefix, f.path)
930 f_path = os.path.join(prefix, f.path)
930 file_info.append(
931 file_info.append(
931 (f_path, f.mode, f.is_link(), f.raw_bytes))
932 (f_path, f.mode, f.is_link(), f.raw_bytes))
932
933
933 if write_metadata:
934 if write_metadata:
934 metadata = [
935 metadata = [
935 ('repo_name', self.repository.name),
936 ('repo_name', self.repository.name),
936 ('rev', self.raw_id),
937 ('rev', self.raw_id),
937 ('create_time', mtime),
938 ('create_time', mtime),
938 ('branch', self.branch),
939 ('branch', self.branch),
939 ('tags', ','.join(self.tags)),
940 ('tags', ','.join(self.tags)),
940 ]
941 ]
941 meta = ["%s:%s" % (f_name, value) for f_name, value in metadata]
942 meta = ["%s:%s" % (f_name, value) for f_name, value in metadata]
942 file_info.append(('.archival.txt', 0644, False, '\n'.join(meta)))
943 file_info.append(('.archival.txt', 0644, False, '\n'.join(meta)))
943
944
944 connection.Hg.archive_repo(file_path, mtime, file_info, kind)
945 connection.Hg.archive_repo(file_path, mtime, file_info, kind)
945
946
946 def _validate_archive_prefix(self, prefix):
947 def _validate_archive_prefix(self, prefix):
947 if prefix is None:
948 if prefix is None:
948 prefix = self._ARCHIVE_PREFIX_TEMPLATE.format(
949 prefix = self._ARCHIVE_PREFIX_TEMPLATE.format(
949 repo_name=safe_str(self.repository.name),
950 repo_name=safe_str(self.repository.name),
950 short_id=self.short_id)
951 short_id=self.short_id)
951 elif not isinstance(prefix, str):
952 elif not isinstance(prefix, str):
952 raise ValueError("prefix not a bytes object: %s" % repr(prefix))
953 raise ValueError("prefix not a bytes object: %s" % repr(prefix))
953 elif prefix.startswith('/'):
954 elif prefix.startswith('/'):
954 raise VCSError("Prefix cannot start with leading slash")
955 raise VCSError("Prefix cannot start with leading slash")
955 elif prefix.strip() == '':
956 elif prefix.strip() == '':
956 raise VCSError("Prefix cannot be empty")
957 raise VCSError("Prefix cannot be empty")
957 return prefix
958 return prefix
958
959
959 @LazyProperty
960 @LazyProperty
960 def root(self):
961 def root(self):
961 """
962 """
962 Returns ``RootNode`` object for this commit.
963 Returns ``RootNode`` object for this commit.
963 """
964 """
964 return self.get_node('')
965 return self.get_node('')
965
966
966 def next(self, branch=None):
967 def next(self, branch=None):
967 """
968 """
968 Returns next commit from current, if branch is gives it will return
969 Returns next commit from current, if branch is gives it will return
969 next commit belonging to this branch
970 next commit belonging to this branch
970
971
971 :param branch: show commits within the given named branch
972 :param branch: show commits within the given named branch
972 """
973 """
973 indexes = xrange(self.idx + 1, self.repository.count())
974 indexes = xrange(self.idx + 1, self.repository.count())
974 return self._find_next(indexes, branch)
975 return self._find_next(indexes, branch)
975
976
976 def prev(self, branch=None):
977 def prev(self, branch=None):
977 """
978 """
978 Returns previous commit from current, if branch is gives it will
979 Returns previous commit from current, if branch is gives it will
979 return previous commit belonging to this branch
980 return previous commit belonging to this branch
980
981
981 :param branch: show commit within the given named branch
982 :param branch: show commit within the given named branch
982 """
983 """
983 indexes = xrange(self.idx - 1, -1, -1)
984 indexes = xrange(self.idx - 1, -1, -1)
984 return self._find_next(indexes, branch)
985 return self._find_next(indexes, branch)
985
986
986 def _find_next(self, indexes, branch=None):
987 def _find_next(self, indexes, branch=None):
987 if branch and self.branch != branch:
988 if branch and self.branch != branch:
988 raise VCSError('Branch option used on commit not belonging '
989 raise VCSError('Branch option used on commit not belonging '
989 'to that branch')
990 'to that branch')
990
991
991 for next_idx in indexes:
992 for next_idx in indexes:
992 commit = self.repository.get_commit(commit_idx=next_idx)
993 commit = self.repository.get_commit(commit_idx=next_idx)
993 if branch and branch != commit.branch:
994 if branch and branch != commit.branch:
994 continue
995 continue
995 return commit
996 return commit
996 raise CommitDoesNotExistError
997 raise CommitDoesNotExistError
997
998
998 def diff(self, ignore_whitespace=True, context=3):
999 def diff(self, ignore_whitespace=True, context=3):
999 """
1000 """
1000 Returns a `Diff` object representing the change made by this commit.
1001 Returns a `Diff` object representing the change made by this commit.
1001 """
1002 """
1002 parent = (
1003 parent = (
1003 self.parents[0] if self.parents else self.repository.EMPTY_COMMIT)
1004 self.parents[0] if self.parents else self.repository.EMPTY_COMMIT)
1004 diff = self.repository.get_diff(
1005 diff = self.repository.get_diff(
1005 parent, self,
1006 parent, self,
1006 ignore_whitespace=ignore_whitespace,
1007 ignore_whitespace=ignore_whitespace,
1007 context=context)
1008 context=context)
1008 return diff
1009 return diff
1009
1010
1010 @LazyProperty
1011 @LazyProperty
1011 def added(self):
1012 def added(self):
1012 """
1013 """
1013 Returns list of added ``FileNode`` objects.
1014 Returns list of added ``FileNode`` objects.
1014 """
1015 """
1015 raise NotImplementedError
1016 raise NotImplementedError
1016
1017
1017 @LazyProperty
1018 @LazyProperty
1018 def changed(self):
1019 def changed(self):
1019 """
1020 """
1020 Returns list of modified ``FileNode`` objects.
1021 Returns list of modified ``FileNode`` objects.
1021 """
1022 """
1022 raise NotImplementedError
1023 raise NotImplementedError
1023
1024
1024 @LazyProperty
1025 @LazyProperty
1025 def removed(self):
1026 def removed(self):
1026 """
1027 """
1027 Returns list of removed ``FileNode`` objects.
1028 Returns list of removed ``FileNode`` objects.
1028 """
1029 """
1029 raise NotImplementedError
1030 raise NotImplementedError
1030
1031
1031 @LazyProperty
1032 @LazyProperty
1032 def size(self):
1033 def size(self):
1033 """
1034 """
1034 Returns total number of bytes from contents of all filenodes.
1035 Returns total number of bytes from contents of all filenodes.
1035 """
1036 """
1036 return sum((node.size for node in self.get_filenodes_generator()))
1037 return sum((node.size for node in self.get_filenodes_generator()))
1037
1038
1038 def walk(self, topurl=''):
1039 def walk(self, topurl=''):
1039 """
1040 """
1040 Similar to os.walk method. Insted of filesystem it walks through
1041 Similar to os.walk method. Insted of filesystem it walks through
1041 commit starting at given ``topurl``. Returns generator of tuples
1042 commit starting at given ``topurl``. Returns generator of tuples
1042 (topnode, dirnodes, filenodes).
1043 (topnode, dirnodes, filenodes).
1043 """
1044 """
1044 topnode = self.get_node(topurl)
1045 topnode = self.get_node(topurl)
1045 if not topnode.is_dir():
1046 if not topnode.is_dir():
1046 return
1047 return
1047 yield (topnode, topnode.dirs, topnode.files)
1048 yield (topnode, topnode.dirs, topnode.files)
1048 for dirnode in topnode.dirs:
1049 for dirnode in topnode.dirs:
1049 for tup in self.walk(dirnode.path):
1050 for tup in self.walk(dirnode.path):
1050 yield tup
1051 yield tup
1051
1052
1052 def get_filenodes_generator(self):
1053 def get_filenodes_generator(self):
1053 """
1054 """
1054 Returns generator that yields *all* file nodes.
1055 Returns generator that yields *all* file nodes.
1055 """
1056 """
1056 for topnode, dirs, files in self.walk():
1057 for topnode, dirs, files in self.walk():
1057 for node in files:
1058 for node in files:
1058 yield node
1059 yield node
1059
1060
1060 #
1061 #
1061 # Utilities for sub classes to support consistent behavior
1062 # Utilities for sub classes to support consistent behavior
1062 #
1063 #
1063
1064
1064 def no_node_at_path(self, path):
1065 def no_node_at_path(self, path):
1065 return NodeDoesNotExistError(
1066 return NodeDoesNotExistError(
1066 "There is no file nor directory at the given path: "
1067 "There is no file nor directory at the given path: "
1067 "'%s' at commit %s" % (path, self.short_id))
1068 "'%s' at commit %s" % (path, self.short_id))
1068
1069
1069 def _fix_path(self, path):
1070 def _fix_path(self, path):
1070 """
1071 """
1071 Paths are stored without trailing slash so we need to get rid off it if
1072 Paths are stored without trailing slash so we need to get rid off it if
1072 needed.
1073 needed.
1073 """
1074 """
1074 return path.rstrip('/')
1075 return path.rstrip('/')
1075
1076
1076 #
1077 #
1077 # Deprecated API based on changesets
1078 # Deprecated API based on changesets
1078 #
1079 #
1079
1080
1080 @property
1081 @property
1081 def revision(self):
1082 def revision(self):
1082 warnings.warn("Use idx instead", DeprecationWarning)
1083 warnings.warn("Use idx instead", DeprecationWarning)
1083 return self.idx
1084 return self.idx
1084
1085
1085 @revision.setter
1086 @revision.setter
1086 def revision(self, value):
1087 def revision(self, value):
1087 warnings.warn("Use idx instead", DeprecationWarning)
1088 warnings.warn("Use idx instead", DeprecationWarning)
1088 self.idx = value
1089 self.idx = value
1089
1090
1090 def get_file_changeset(self, path):
1091 def get_file_changeset(self, path):
1091 warnings.warn("Use get_file_commit instead", DeprecationWarning)
1092 warnings.warn("Use get_file_commit instead", DeprecationWarning)
1092 return self.get_file_commit(path)
1093 return self.get_file_commit(path)
1093
1094
1094
1095
1095 class BaseChangesetClass(type):
1096 class BaseChangesetClass(type):
1096
1097
1097 def __instancecheck__(self, instance):
1098 def __instancecheck__(self, instance):
1098 return isinstance(instance, BaseCommit)
1099 return isinstance(instance, BaseCommit)
1099
1100
1100
1101
1101 class BaseChangeset(BaseCommit):
1102 class BaseChangeset(BaseCommit):
1102
1103
1103 __metaclass__ = BaseChangesetClass
1104 __metaclass__ = BaseChangesetClass
1104
1105
1105 def __new__(cls, *args, **kwargs):
1106 def __new__(cls, *args, **kwargs):
1106 warnings.warn(
1107 warnings.warn(
1107 "Use BaseCommit instead of BaseChangeset", DeprecationWarning)
1108 "Use BaseCommit instead of BaseChangeset", DeprecationWarning)
1108 return super(BaseChangeset, cls).__new__(cls, *args, **kwargs)
1109 return super(BaseChangeset, cls).__new__(cls, *args, **kwargs)
1109
1110
1110
1111
1111 class BaseInMemoryCommit(object):
1112 class BaseInMemoryCommit(object):
1112 """
1113 """
1113 Represents differences between repository's state (most recent head) and
1114 Represents differences between repository's state (most recent head) and
1114 changes made *in place*.
1115 changes made *in place*.
1115
1116
1116 **Attributes**
1117 **Attributes**
1117
1118
1118 ``repository``
1119 ``repository``
1119 repository object for this in-memory-commit
1120 repository object for this in-memory-commit
1120
1121
1121 ``added``
1122 ``added``
1122 list of ``FileNode`` objects marked as *added*
1123 list of ``FileNode`` objects marked as *added*
1123
1124
1124 ``changed``
1125 ``changed``
1125 list of ``FileNode`` objects marked as *changed*
1126 list of ``FileNode`` objects marked as *changed*
1126
1127
1127 ``removed``
1128 ``removed``
1128 list of ``FileNode`` or ``RemovedFileNode`` objects marked to be
1129 list of ``FileNode`` or ``RemovedFileNode`` objects marked to be
1129 *removed*
1130 *removed*
1130
1131
1131 ``parents``
1132 ``parents``
1132 list of :class:`BaseCommit` instances representing parents of
1133 list of :class:`BaseCommit` instances representing parents of
1133 in-memory commit. Should always be 2-element sequence.
1134 in-memory commit. Should always be 2-element sequence.
1134
1135
1135 """
1136 """
1136
1137
1137 def __init__(self, repository):
1138 def __init__(self, repository):
1138 self.repository = repository
1139 self.repository = repository
1139 self.added = []
1140 self.added = []
1140 self.changed = []
1141 self.changed = []
1141 self.removed = []
1142 self.removed = []
1142 self.parents = []
1143 self.parents = []
1143
1144
1144 def add(self, *filenodes):
1145 def add(self, *filenodes):
1145 """
1146 """
1146 Marks given ``FileNode`` objects as *to be committed*.
1147 Marks given ``FileNode`` objects as *to be committed*.
1147
1148
1148 :raises ``NodeAlreadyExistsError``: if node with same path exists at
1149 :raises ``NodeAlreadyExistsError``: if node with same path exists at
1149 latest commit
1150 latest commit
1150 :raises ``NodeAlreadyAddedError``: if node with same path is already
1151 :raises ``NodeAlreadyAddedError``: if node with same path is already
1151 marked as *added*
1152 marked as *added*
1152 """
1153 """
1153 # Check if not already marked as *added* first
1154 # Check if not already marked as *added* first
1154 for node in filenodes:
1155 for node in filenodes:
1155 if node.path in (n.path for n in self.added):
1156 if node.path in (n.path for n in self.added):
1156 raise NodeAlreadyAddedError(
1157 raise NodeAlreadyAddedError(
1157 "Such FileNode %s is already marked for addition"
1158 "Such FileNode %s is already marked for addition"
1158 % node.path)
1159 % node.path)
1159 for node in filenodes:
1160 for node in filenodes:
1160 self.added.append(node)
1161 self.added.append(node)
1161
1162
1162 def change(self, *filenodes):
1163 def change(self, *filenodes):
1163 """
1164 """
1164 Marks given ``FileNode`` objects to be *changed* in next commit.
1165 Marks given ``FileNode`` objects to be *changed* in next commit.
1165
1166
1166 :raises ``EmptyRepositoryError``: if there are no commits yet
1167 :raises ``EmptyRepositoryError``: if there are no commits yet
1167 :raises ``NodeAlreadyExistsError``: if node with same path is already
1168 :raises ``NodeAlreadyExistsError``: if node with same path is already
1168 marked to be *changed*
1169 marked to be *changed*
1169 :raises ``NodeAlreadyRemovedError``: if node with same path is already
1170 :raises ``NodeAlreadyRemovedError``: if node with same path is already
1170 marked to be *removed*
1171 marked to be *removed*
1171 :raises ``NodeDoesNotExistError``: if node doesn't exist in latest
1172 :raises ``NodeDoesNotExistError``: if node doesn't exist in latest
1172 commit
1173 commit
1173 :raises ``NodeNotChangedError``: if node hasn't really be changed
1174 :raises ``NodeNotChangedError``: if node hasn't really be changed
1174 """
1175 """
1175 for node in filenodes:
1176 for node in filenodes:
1176 if node.path in (n.path for n in self.removed):
1177 if node.path in (n.path for n in self.removed):
1177 raise NodeAlreadyRemovedError(
1178 raise NodeAlreadyRemovedError(
1178 "Node at %s is already marked as removed" % node.path)
1179 "Node at %s is already marked as removed" % node.path)
1179 try:
1180 try:
1180 self.repository.get_commit()
1181 self.repository.get_commit()
1181 except EmptyRepositoryError:
1182 except EmptyRepositoryError:
1182 raise EmptyRepositoryError(
1183 raise EmptyRepositoryError(
1183 "Nothing to change - try to *add* new nodes rather than "
1184 "Nothing to change - try to *add* new nodes rather than "
1184 "changing them")
1185 "changing them")
1185 for node in filenodes:
1186 for node in filenodes:
1186 if node.path in (n.path for n in self.changed):
1187 if node.path in (n.path for n in self.changed):
1187 raise NodeAlreadyChangedError(
1188 raise NodeAlreadyChangedError(
1188 "Node at '%s' is already marked as changed" % node.path)
1189 "Node at '%s' is already marked as changed" % node.path)
1189 self.changed.append(node)
1190 self.changed.append(node)
1190
1191
1191 def remove(self, *filenodes):
1192 def remove(self, *filenodes):
1192 """
1193 """
1193 Marks given ``FileNode`` (or ``RemovedFileNode``) objects to be
1194 Marks given ``FileNode`` (or ``RemovedFileNode``) objects to be
1194 *removed* in next commit.
1195 *removed* in next commit.
1195
1196
1196 :raises ``NodeAlreadyRemovedError``: if node has been already marked to
1197 :raises ``NodeAlreadyRemovedError``: if node has been already marked to
1197 be *removed*
1198 be *removed*
1198 :raises ``NodeAlreadyChangedError``: if node has been already marked to
1199 :raises ``NodeAlreadyChangedError``: if node has been already marked to
1199 be *changed*
1200 be *changed*
1200 """
1201 """
1201 for node in filenodes:
1202 for node in filenodes:
1202 if node.path in (n.path for n in self.removed):
1203 if node.path in (n.path for n in self.removed):
1203 raise NodeAlreadyRemovedError(
1204 raise NodeAlreadyRemovedError(
1204 "Node is already marked to for removal at %s" % node.path)
1205 "Node is already marked to for removal at %s" % node.path)
1205 if node.path in (n.path for n in self.changed):
1206 if node.path in (n.path for n in self.changed):
1206 raise NodeAlreadyChangedError(
1207 raise NodeAlreadyChangedError(
1207 "Node is already marked to be changed at %s" % node.path)
1208 "Node is already marked to be changed at %s" % node.path)
1208 # We only mark node as *removed* - real removal is done by
1209 # We only mark node as *removed* - real removal is done by
1209 # commit method
1210 # commit method
1210 self.removed.append(node)
1211 self.removed.append(node)
1211
1212
1212 def reset(self):
1213 def reset(self):
1213 """
1214 """
1214 Resets this instance to initial state (cleans ``added``, ``changed``
1215 Resets this instance to initial state (cleans ``added``, ``changed``
1215 and ``removed`` lists).
1216 and ``removed`` lists).
1216 """
1217 """
1217 self.added = []
1218 self.added = []
1218 self.changed = []
1219 self.changed = []
1219 self.removed = []
1220 self.removed = []
1220 self.parents = []
1221 self.parents = []
1221
1222
1222 def get_ipaths(self):
1223 def get_ipaths(self):
1223 """
1224 """
1224 Returns generator of paths from nodes marked as added, changed or
1225 Returns generator of paths from nodes marked as added, changed or
1225 removed.
1226 removed.
1226 """
1227 """
1227 for node in itertools.chain(self.added, self.changed, self.removed):
1228 for node in itertools.chain(self.added, self.changed, self.removed):
1228 yield node.path
1229 yield node.path
1229
1230
1230 def get_paths(self):
1231 def get_paths(self):
1231 """
1232 """
1232 Returns list of paths from nodes marked as added, changed or removed.
1233 Returns list of paths from nodes marked as added, changed or removed.
1233 """
1234 """
1234 return list(self.get_ipaths())
1235 return list(self.get_ipaths())
1235
1236
1236 def check_integrity(self, parents=None):
1237 def check_integrity(self, parents=None):
1237 """
1238 """
1238 Checks in-memory commit's integrity. Also, sets parents if not
1239 Checks in-memory commit's integrity. Also, sets parents if not
1239 already set.
1240 already set.
1240
1241
1241 :raises CommitError: if any error occurs (i.e.
1242 :raises CommitError: if any error occurs (i.e.
1242 ``NodeDoesNotExistError``).
1243 ``NodeDoesNotExistError``).
1243 """
1244 """
1244 if not self.parents:
1245 if not self.parents:
1245 parents = parents or []
1246 parents = parents or []
1246 if len(parents) == 0:
1247 if len(parents) == 0:
1247 try:
1248 try:
1248 parents = [self.repository.get_commit(), None]
1249 parents = [self.repository.get_commit(), None]
1249 except EmptyRepositoryError:
1250 except EmptyRepositoryError:
1250 parents = [None, None]
1251 parents = [None, None]
1251 elif len(parents) == 1:
1252 elif len(parents) == 1:
1252 parents += [None]
1253 parents += [None]
1253 self.parents = parents
1254 self.parents = parents
1254
1255
1255 # Local parents, only if not None
1256 # Local parents, only if not None
1256 parents = [p for p in self.parents if p]
1257 parents = [p for p in self.parents if p]
1257
1258
1258 # Check nodes marked as added
1259 # Check nodes marked as added
1259 for p in parents:
1260 for p in parents:
1260 for node in self.added:
1261 for node in self.added:
1261 try:
1262 try:
1262 p.get_node(node.path)
1263 p.get_node(node.path)
1263 except NodeDoesNotExistError:
1264 except NodeDoesNotExistError:
1264 pass
1265 pass
1265 else:
1266 else:
1266 raise NodeAlreadyExistsError(
1267 raise NodeAlreadyExistsError(
1267 "Node `%s` already exists at %s" % (node.path, p))
1268 "Node `%s` already exists at %s" % (node.path, p))
1268
1269
1269 # Check nodes marked as changed
1270 # Check nodes marked as changed
1270 missing = set(self.changed)
1271 missing = set(self.changed)
1271 not_changed = set(self.changed)
1272 not_changed = set(self.changed)
1272 if self.changed and not parents:
1273 if self.changed and not parents:
1273 raise NodeDoesNotExistError(str(self.changed[0].path))
1274 raise NodeDoesNotExistError(str(self.changed[0].path))
1274 for p in parents:
1275 for p in parents:
1275 for node in self.changed:
1276 for node in self.changed:
1276 try:
1277 try:
1277 old = p.get_node(node.path)
1278 old = p.get_node(node.path)
1278 missing.remove(node)
1279 missing.remove(node)
1279 # if content actually changed, remove node from not_changed
1280 # if content actually changed, remove node from not_changed
1280 if old.content != node.content:
1281 if old.content != node.content:
1281 not_changed.remove(node)
1282 not_changed.remove(node)
1282 except NodeDoesNotExistError:
1283 except NodeDoesNotExistError:
1283 pass
1284 pass
1284 if self.changed and missing:
1285 if self.changed and missing:
1285 raise NodeDoesNotExistError(
1286 raise NodeDoesNotExistError(
1286 "Node `%s` marked as modified but missing in parents: %s"
1287 "Node `%s` marked as modified but missing in parents: %s"
1287 % (node.path, parents))
1288 % (node.path, parents))
1288
1289
1289 if self.changed and not_changed:
1290 if self.changed and not_changed:
1290 raise NodeNotChangedError(
1291 raise NodeNotChangedError(
1291 "Node `%s` wasn't actually changed (parents: %s)"
1292 "Node `%s` wasn't actually changed (parents: %s)"
1292 % (not_changed.pop().path, parents))
1293 % (not_changed.pop().path, parents))
1293
1294
1294 # Check nodes marked as removed
1295 # Check nodes marked as removed
1295 if self.removed and not parents:
1296 if self.removed and not parents:
1296 raise NodeDoesNotExistError(
1297 raise NodeDoesNotExistError(
1297 "Cannot remove node at %s as there "
1298 "Cannot remove node at %s as there "
1298 "were no parents specified" % self.removed[0].path)
1299 "were no parents specified" % self.removed[0].path)
1299 really_removed = set()
1300 really_removed = set()
1300 for p in parents:
1301 for p in parents:
1301 for node in self.removed:
1302 for node in self.removed:
1302 try:
1303 try:
1303 p.get_node(node.path)
1304 p.get_node(node.path)
1304 really_removed.add(node)
1305 really_removed.add(node)
1305 except CommitError:
1306 except CommitError:
1306 pass
1307 pass
1307 not_removed = set(self.removed) - really_removed
1308 not_removed = set(self.removed) - really_removed
1308 if not_removed:
1309 if not_removed:
1309 # TODO: johbo: This code branch does not seem to be covered
1310 # TODO: johbo: This code branch does not seem to be covered
1310 raise NodeDoesNotExistError(
1311 raise NodeDoesNotExistError(
1311 "Cannot remove node at %s from "
1312 "Cannot remove node at %s from "
1312 "following parents: %s" % (not_removed, parents))
1313 "following parents: %s" % (not_removed, parents))
1313
1314
1314 def commit(
1315 def commit(
1315 self, message, author, parents=None, branch=None, date=None,
1316 self, message, author, parents=None, branch=None, date=None,
1316 **kwargs):
1317 **kwargs):
1317 """
1318 """
1318 Performs in-memory commit (doesn't check workdir in any way) and
1319 Performs in-memory commit (doesn't check workdir in any way) and
1319 returns newly created :class:`BaseCommit`. Updates repository's
1320 returns newly created :class:`BaseCommit`. Updates repository's
1320 attribute `commits`.
1321 attribute `commits`.
1321
1322
1322 .. note::
1323 .. note::
1323
1324
1324 While overriding this method each backend's should call
1325 While overriding this method each backend's should call
1325 ``self.check_integrity(parents)`` in the first place.
1326 ``self.check_integrity(parents)`` in the first place.
1326
1327
1327 :param message: message of the commit
1328 :param message: message of the commit
1328 :param author: full username, i.e. "Joe Doe <joe.doe@example.com>"
1329 :param author: full username, i.e. "Joe Doe <joe.doe@example.com>"
1329 :param parents: single parent or sequence of parents from which commit
1330 :param parents: single parent or sequence of parents from which commit
1330 would be derived
1331 would be derived
1331 :param date: ``datetime.datetime`` instance. Defaults to
1332 :param date: ``datetime.datetime`` instance. Defaults to
1332 ``datetime.datetime.now()``.
1333 ``datetime.datetime.now()``.
1333 :param branch: branch name, as string. If none given, default backend's
1334 :param branch: branch name, as string. If none given, default backend's
1334 branch would be used.
1335 branch would be used.
1335
1336
1336 :raises ``CommitError``: if any error occurs while committing
1337 :raises ``CommitError``: if any error occurs while committing
1337 """
1338 """
1338 raise NotImplementedError
1339 raise NotImplementedError
1339
1340
1340
1341
1341 class BaseInMemoryChangesetClass(type):
1342 class BaseInMemoryChangesetClass(type):
1342
1343
1343 def __instancecheck__(self, instance):
1344 def __instancecheck__(self, instance):
1344 return isinstance(instance, BaseInMemoryCommit)
1345 return isinstance(instance, BaseInMemoryCommit)
1345
1346
1346
1347
1347 class BaseInMemoryChangeset(BaseInMemoryCommit):
1348 class BaseInMemoryChangeset(BaseInMemoryCommit):
1348
1349
1349 __metaclass__ = BaseInMemoryChangesetClass
1350 __metaclass__ = BaseInMemoryChangesetClass
1350
1351
1351 def __new__(cls, *args, **kwargs):
1352 def __new__(cls, *args, **kwargs):
1352 warnings.warn(
1353 warnings.warn(
1353 "Use BaseCommit instead of BaseInMemoryCommit", DeprecationWarning)
1354 "Use BaseCommit instead of BaseInMemoryCommit", DeprecationWarning)
1354 return super(BaseInMemoryChangeset, cls).__new__(cls, *args, **kwargs)
1355 return super(BaseInMemoryChangeset, cls).__new__(cls, *args, **kwargs)
1355
1356
1356
1357
1357 class EmptyCommit(BaseCommit):
1358 class EmptyCommit(BaseCommit):
1358 """
1359 """
1359 An dummy empty commit. It's possible to pass hash when creating
1360 An dummy empty commit. It's possible to pass hash when creating
1360 an EmptyCommit
1361 an EmptyCommit
1361 """
1362 """
1362
1363
1363 def __init__(
1364 def __init__(
1364 self, commit_id='0' * 40, repo=None, alias=None, idx=-1,
1365 self, commit_id='0' * 40, repo=None, alias=None, idx=-1,
1365 message='', author='', date=None):
1366 message='', author='', date=None):
1366 self._empty_commit_id = commit_id
1367 self._empty_commit_id = commit_id
1367 # TODO: johbo: Solve idx parameter, default value does not make
1368 # TODO: johbo: Solve idx parameter, default value does not make
1368 # too much sense
1369 # too much sense
1369 self.idx = idx
1370 self.idx = idx
1370 self.message = message
1371 self.message = message
1371 self.author = author
1372 self.author = author
1372 self.date = date or datetime.datetime.fromtimestamp(0)
1373 self.date = date or datetime.datetime.fromtimestamp(0)
1373 self.repository = repo
1374 self.repository = repo
1374 self.alias = alias
1375 self.alias = alias
1375
1376
1376 @LazyProperty
1377 @LazyProperty
1377 def raw_id(self):
1378 def raw_id(self):
1378 """
1379 """
1379 Returns raw string identifying this commit, useful for web
1380 Returns raw string identifying this commit, useful for web
1380 representation.
1381 representation.
1381 """
1382 """
1382
1383
1383 return self._empty_commit_id
1384 return self._empty_commit_id
1384
1385
1385 @LazyProperty
1386 @LazyProperty
1386 def branch(self):
1387 def branch(self):
1387 if self.alias:
1388 if self.alias:
1388 from rhodecode.lib.vcs.backends import get_backend
1389 from rhodecode.lib.vcs.backends import get_backend
1389 return get_backend(self.alias).DEFAULT_BRANCH_NAME
1390 return get_backend(self.alias).DEFAULT_BRANCH_NAME
1390
1391
1391 @LazyProperty
1392 @LazyProperty
1392 def short_id(self):
1393 def short_id(self):
1393 return self.raw_id[:12]
1394 return self.raw_id[:12]
1394
1395
1395 @LazyProperty
1396 @LazyProperty
1396 def id(self):
1397 def id(self):
1397 return self.raw_id
1398 return self.raw_id
1398
1399
1399 def get_file_commit(self, path):
1400 def get_file_commit(self, path):
1400 return self
1401 return self
1401
1402
1402 def get_file_content(self, path):
1403 def get_file_content(self, path):
1403 return u''
1404 return u''
1404
1405
1405 def get_file_size(self, path):
1406 def get_file_size(self, path):
1406 return 0
1407 return 0
1407
1408
1408
1409
1409 class EmptyChangesetClass(type):
1410 class EmptyChangesetClass(type):
1410
1411
1411 def __instancecheck__(self, instance):
1412 def __instancecheck__(self, instance):
1412 return isinstance(instance, EmptyCommit)
1413 return isinstance(instance, EmptyCommit)
1413
1414
1414
1415
1415 class EmptyChangeset(EmptyCommit):
1416 class EmptyChangeset(EmptyCommit):
1416
1417
1417 __metaclass__ = EmptyChangesetClass
1418 __metaclass__ = EmptyChangesetClass
1418
1419
1419 def __new__(cls, *args, **kwargs):
1420 def __new__(cls, *args, **kwargs):
1420 warnings.warn(
1421 warnings.warn(
1421 "Use EmptyCommit instead of EmptyChangeset", DeprecationWarning)
1422 "Use EmptyCommit instead of EmptyChangeset", DeprecationWarning)
1422 return super(EmptyCommit, cls).__new__(cls, *args, **kwargs)
1423 return super(EmptyCommit, cls).__new__(cls, *args, **kwargs)
1423
1424
1424 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
1425 def __init__(self, cs='0' * 40, repo=None, requested_revision=None,
1425 alias=None, revision=-1, message='', author='', date=None):
1426 alias=None, revision=-1, message='', author='', date=None):
1426 if requested_revision is not None:
1427 if requested_revision is not None:
1427 warnings.warn(
1428 warnings.warn(
1428 "Parameter requested_revision not supported anymore",
1429 "Parameter requested_revision not supported anymore",
1429 DeprecationWarning)
1430 DeprecationWarning)
1430 super(EmptyChangeset, self).__init__(
1431 super(EmptyChangeset, self).__init__(
1431 commit_id=cs, repo=repo, alias=alias, idx=revision,
1432 commit_id=cs, repo=repo, alias=alias, idx=revision,
1432 message=message, author=author, date=date)
1433 message=message, author=author, date=date)
1433
1434
1434 @property
1435 @property
1435 def revision(self):
1436 def revision(self):
1436 warnings.warn("Use idx instead", DeprecationWarning)
1437 warnings.warn("Use idx instead", DeprecationWarning)
1437 return self.idx
1438 return self.idx
1438
1439
1439 @revision.setter
1440 @revision.setter
1440 def revision(self, value):
1441 def revision(self, value):
1441 warnings.warn("Use idx instead", DeprecationWarning)
1442 warnings.warn("Use idx instead", DeprecationWarning)
1442 self.idx = value
1443 self.idx = value
1443
1444
1444
1445
1445 class EmptyRepository(BaseRepository):
1446 class EmptyRepository(BaseRepository):
1446 def __init__(self, repo_path=None, config=None, create=False, **kwargs):
1447 def __init__(self, repo_path=None, config=None, create=False, **kwargs):
1447 pass
1448 pass
1448
1449
1449 def get_diff(self, *args, **kwargs):
1450 def get_diff(self, *args, **kwargs):
1450 from rhodecode.lib.vcs.backends.git.diff import GitDiff
1451 from rhodecode.lib.vcs.backends.git.diff import GitDiff
1451 return GitDiff('')
1452 return GitDiff('')
1452
1453
1453
1454
1454 class CollectionGenerator(object):
1455 class CollectionGenerator(object):
1455
1456
1456 def __init__(self, repo, commit_ids, collection_size=None, pre_load=None):
1457 def __init__(self, repo, commit_ids, collection_size=None, pre_load=None):
1457 self.repo = repo
1458 self.repo = repo
1458 self.commit_ids = commit_ids
1459 self.commit_ids = commit_ids
1459 # TODO: (oliver) this isn't currently hooked up
1460 # TODO: (oliver) this isn't currently hooked up
1460 self.collection_size = None
1461 self.collection_size = None
1461 self.pre_load = pre_load
1462 self.pre_load = pre_load
1462
1463
1463 def __len__(self):
1464 def __len__(self):
1464 if self.collection_size is not None:
1465 if self.collection_size is not None:
1465 return self.collection_size
1466 return self.collection_size
1466 return self.commit_ids.__len__()
1467 return self.commit_ids.__len__()
1467
1468
1468 def __iter__(self):
1469 def __iter__(self):
1469 for commit_id in self.commit_ids:
1470 for commit_id in self.commit_ids:
1470 # TODO: johbo: Mercurial passes in commit indices or commit ids
1471 # TODO: johbo: Mercurial passes in commit indices or commit ids
1471 yield self._commit_factory(commit_id)
1472 yield self._commit_factory(commit_id)
1472
1473
1473 def _commit_factory(self, commit_id):
1474 def _commit_factory(self, commit_id):
1474 """
1475 """
1475 Allows backends to override the way commits are generated.
1476 Allows backends to override the way commits are generated.
1476 """
1477 """
1477 return self.repo.get_commit(commit_id=commit_id,
1478 return self.repo.get_commit(commit_id=commit_id,
1478 pre_load=self.pre_load)
1479 pre_load=self.pre_load)
1479
1480
1480 def __getslice__(self, i, j):
1481 def __getslice__(self, i, j):
1481 """
1482 """
1482 Returns an iterator of sliced repository
1483 Returns an iterator of sliced repository
1483 """
1484 """
1484 commit_ids = self.commit_ids[i:j]
1485 commit_ids = self.commit_ids[i:j]
1485 return self.__class__(
1486 return self.__class__(
1486 self.repo, commit_ids, pre_load=self.pre_load)
1487 self.repo, commit_ids, pre_load=self.pre_load)
1487
1488
1488 def __repr__(self):
1489 def __repr__(self):
1489 return '<CollectionGenerator[len:%s]>' % (self.__len__())
1490 return '<CollectionGenerator[len:%s]>' % (self.__len__())
1490
1491
1491
1492
1492 class Config(object):
1493 class Config(object):
1493 """
1494 """
1494 Represents the configuration for a repository.
1495 Represents the configuration for a repository.
1495
1496
1496 The API is inspired by :class:`ConfigParser.ConfigParser` from the
1497 The API is inspired by :class:`ConfigParser.ConfigParser` from the
1497 standard library. It implements only the needed subset.
1498 standard library. It implements only the needed subset.
1498 """
1499 """
1499
1500
1500 def __init__(self):
1501 def __init__(self):
1501 self._values = {}
1502 self._values = {}
1502
1503
1503 def copy(self):
1504 def copy(self):
1504 clone = Config()
1505 clone = Config()
1505 for section, values in self._values.items():
1506 for section, values in self._values.items():
1506 clone._values[section] = values.copy()
1507 clone._values[section] = values.copy()
1507 return clone
1508 return clone
1508
1509
1509 def __repr__(self):
1510 def __repr__(self):
1510 return '<Config(%s sections) at %s>' % (
1511 return '<Config(%s sections) at %s>' % (
1511 len(self._values), hex(id(self)))
1512 len(self._values), hex(id(self)))
1512
1513
1513 def items(self, section):
1514 def items(self, section):
1514 return self._values.get(section, {}).iteritems()
1515 return self._values.get(section, {}).iteritems()
1515
1516
1516 def get(self, section, option):
1517 def get(self, section, option):
1517 return self._values.get(section, {}).get(option)
1518 return self._values.get(section, {}).get(option)
1518
1519
1519 def set(self, section, option, value):
1520 def set(self, section, option, value):
1520 section_values = self._values.setdefault(section, {})
1521 section_values = self._values.setdefault(section, {})
1521 section_values[option] = value
1522 section_values[option] = value
1522
1523
1523 def clear_section(self, section):
1524 def clear_section(self, section):
1524 self._values[section] = {}
1525 self._values[section] = {}
1525
1526
1526 def serialize(self):
1527 def serialize(self):
1527 """
1528 """
1528 Creates a list of three tuples (section, key, value) representing
1529 Creates a list of three tuples (section, key, value) representing
1529 this config object.
1530 this config object.
1530 """
1531 """
1531 items = []
1532 items = []
1532 for section in self._values:
1533 for section in self._values:
1533 for option, value in self._values[section].items():
1534 for option, value in self._values[section].items():
1534 items.append(
1535 items.append(
1535 (safe_str(section), safe_str(option), safe_str(value)))
1536 (safe_str(section), safe_str(option), safe_str(value)))
1536 return items
1537 return items
1537
1538
1538
1539
1539 class Diff(object):
1540 class Diff(object):
1540 """
1541 """
1541 Represents a diff result from a repository backend.
1542 Represents a diff result from a repository backend.
1542
1543
1543 Subclasses have to provide a backend specific value for :attr:`_header_re`.
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 _header_re = None
1548 _header_re = None
1547
1549
1548 def __init__(self, raw_diff):
1550 def __init__(self, raw_diff):
1549 self.raw = raw_diff
1551 self.raw = raw_diff
1550
1552
1551 def chunks(self):
1553 def chunks(self):
1552 """
1554 """
1553 split the diff in chunks of separate --git a/file b/file chunks
1555 split the diff in chunks of separate --git a/file b/file chunks
1554 to make diffs consistent we must prepend with \n, and make sure
1556 to make diffs consistent we must prepend with \n, and make sure
1555 we can detect last chunk as this was also has special rule
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 total_chunks = len(chunks)
1567 total_chunks = len(chunks)
1559 return (DiffChunk(chunk, self, cur_chunk == total_chunks)
1568
1560 for cur_chunk, chunk in enumerate(chunks, start=1))
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 class DiffChunk(object):
1574 class DiffChunk(object):
1564
1575
1565 def __init__(self, chunk, diff, last_chunk):
1576 def __init__(self, chunk, diff, last_chunk):
1566 self._diff = diff
1577 self._diff = diff
1567
1578
1568 # since we split by \ndiff --git that part is lost from original diff
1579 # since we split by \ndiff --git that part is lost from original diff
1569 # we need to re-apply it at the end, EXCEPT ! if it's last chunk
1580 # we need to re-apply it at the end, EXCEPT ! if it's last chunk
1570 if not last_chunk:
1581 if not last_chunk:
1571 chunk += '\n'
1582 chunk += '\n'
1572
1583
1573 match = self._diff._header_re.match(chunk)
1584 match = self._diff._header_re.match(chunk)
1574 self.header = match.groupdict()
1585 self.header = match.groupdict()
1575 self.diff = chunk[match.end():]
1586 self.diff = chunk[match.end():]
1576 self.raw = chunk
1587 self.raw = chunk
@@ -1,48 +1,52 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2014-2016 RhodeCode GmbH
3 # Copyright (C) 2014-2016 RhodeCode GmbH
4 #
4 #
5 # This program is free software: you can redistribute it and/or modify
5 # This program is free software: you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License, version 3
6 # it under the terms of the GNU Affero General Public License, version 3
7 # (only), as published by the Free Software Foundation.
7 # (only), as published by the Free Software Foundation.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU Affero General Public License
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #
16 #
17 # This program is dual-licensed. If you wish to learn more about the
17 # This program is dual-licensed. If you wish to learn more about the
18 # RhodeCode Enterprise Edition, including its added features, Support services,
18 # RhodeCode Enterprise Edition, including its added features, Support services,
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
19 # and proprietary license terms, please see https://rhodecode.com/licenses/
20
20
21
21
22 """
22 """
23 SVN diff module
23 SVN diff module
24 """
24 """
25
25
26 import re
26 import re
27
27
28 from rhodecode.lib.vcs.backends import base
28 from rhodecode.lib.vcs.backends import base
29
29
30
30
31 class SubversionDiff(base.Diff):
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 _header_re = re.compile(r"""
37 _header_re = re.compile(r"""
34 #^diff[ ]--git
38 #^diff[ ]--git
35 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
39 [ ]"?a/(?P<a_path>.+?)"?[ ]"?b/(?P<b_path>.+?)"?\n
36 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
40 (?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
37 ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
41 ^rename[ ]from[ ](?P<rename_from>[^\r\n]+)\n
38 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
42 ^rename[ ]to[ ](?P<rename_to>[^\r\n]+)(?:\n|$))?
39 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
43 (?:^old[ ]mode[ ](?P<old_mode>\d+)\n
40 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
44 ^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
41 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
45 (?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
42 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
46 (?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
43 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
47 (?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
44 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
48 \.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
45 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
49 (?:^(?P<bin_patch>GIT[ ]binary[ ]patch)(?:\n|$))?
46 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
50 (?:^---[ ](a/(?P<a_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
47 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
51 (?:^\+\+\+[ ](b/(?P<b_file>.+)|/dev/null)\t\(revision[ ]\d+\)(?:\n|$))?
48 """, re.VERBOSE | re.MULTILINE)
52 """, re.VERBOSE | re.MULTILINE)
@@ -1,2216 +1,2217 b''
1 //Primary CSS
1 //Primary CSS
2
2
3 //--- IMPORTS ------------------//
3 //--- IMPORTS ------------------//
4
4
5 @import 'helpers';
5 @import 'helpers';
6 @import 'mixins';
6 @import 'mixins';
7 @import 'rcicons';
7 @import 'rcicons';
8 @import 'fonts';
8 @import 'fonts';
9 @import 'variables';
9 @import 'variables';
10 @import 'bootstrap-variables';
10 @import 'bootstrap-variables';
11 @import 'form-bootstrap';
11 @import 'form-bootstrap';
12 @import 'codemirror';
12 @import 'codemirror';
13 @import 'legacy_code_styles';
13 @import 'legacy_code_styles';
14 @import 'progress-bar';
14 @import 'progress-bar';
15
15
16 @import 'type';
16 @import 'type';
17 @import 'alerts';
17 @import 'alerts';
18 @import 'buttons';
18 @import 'buttons';
19 @import 'tags';
19 @import 'tags';
20 @import 'code-block';
20 @import 'code-block';
21 @import 'examples';
21 @import 'examples';
22 @import 'login';
22 @import 'login';
23 @import 'main-content';
23 @import 'main-content';
24 @import 'select2';
24 @import 'select2';
25 @import 'comments';
25 @import 'comments';
26 @import 'panels-bootstrap';
26 @import 'panels-bootstrap';
27 @import 'panels';
27 @import 'panels';
28 @import 'deform';
28 @import 'deform';
29
29
30 //--- BASE ------------------//
30 //--- BASE ------------------//
31 .noscript-error {
31 .noscript-error {
32 top: 0;
32 top: 0;
33 left: 0;
33 left: 0;
34 width: 100%;
34 width: 100%;
35 z-index: 101;
35 z-index: 101;
36 text-align: center;
36 text-align: center;
37 font-family: @text-semibold;
37 font-family: @text-semibold;
38 font-size: 120%;
38 font-size: 120%;
39 color: white;
39 color: white;
40 background-color: @alert2;
40 background-color: @alert2;
41 padding: 5px 0 5px 0;
41 padding: 5px 0 5px 0;
42 }
42 }
43
43
44 html {
44 html {
45 display: table;
45 display: table;
46 height: 100%;
46 height: 100%;
47 width: 100%;
47 width: 100%;
48 }
48 }
49
49
50 body {
50 body {
51 display: table-cell;
51 display: table-cell;
52 width: 100%;
52 width: 100%;
53 }
53 }
54
54
55 //--- LAYOUT ------------------//
55 //--- LAYOUT ------------------//
56
56
57 .hidden{
57 .hidden{
58 display: none !important;
58 display: none !important;
59 }
59 }
60
60
61 .box{
61 .box{
62 float: left;
62 float: left;
63 width: 100%;
63 width: 100%;
64 }
64 }
65
65
66 .browser-header {
66 .browser-header {
67 clear: both;
67 clear: both;
68 }
68 }
69 .main {
69 .main {
70 clear: both;
70 clear: both;
71 padding:0 0 @pagepadding;
71 padding:0 0 @pagepadding;
72 height: auto;
72 height: auto;
73
73
74 &:after { //clearfix
74 &:after { //clearfix
75 content:"";
75 content:"";
76 clear:both;
76 clear:both;
77 width:100%;
77 width:100%;
78 display:block;
78 display:block;
79 }
79 }
80 }
80 }
81
81
82 .action-link{
82 .action-link{
83 margin-left: @padding;
83 margin-left: @padding;
84 padding-left: @padding;
84 padding-left: @padding;
85 border-left: @border-thickness solid @border-default-color;
85 border-left: @border-thickness solid @border-default-color;
86 }
86 }
87
87
88 input + .action-link, .action-link.first{
88 input + .action-link, .action-link.first{
89 border-left: none;
89 border-left: none;
90 }
90 }
91
91
92 .action-link.last{
92 .action-link.last{
93 margin-right: @padding;
93 margin-right: @padding;
94 padding-right: @padding;
94 padding-right: @padding;
95 }
95 }
96
96
97 .action-link.active,
97 .action-link.active,
98 .action-link.active a{
98 .action-link.active a{
99 color: @grey4;
99 color: @grey4;
100 }
100 }
101
101
102 ul.simple-list{
102 ul.simple-list{
103 list-style: none;
103 list-style: none;
104 margin: 0;
104 margin: 0;
105 padding: 0;
105 padding: 0;
106 }
106 }
107
107
108 .main-content {
108 .main-content {
109 padding-bottom: @pagepadding;
109 padding-bottom: @pagepadding;
110 }
110 }
111
111
112 .wide-mode-wrapper {
112 .wide-mode-wrapper {
113 max-width:2400px !important;
113 max-width:2400px !important;
114 }
114 }
115
115
116 .wrapper {
116 .wrapper {
117 position: relative;
117 position: relative;
118 max-width: @wrapper-maxwidth;
118 max-width: @wrapper-maxwidth;
119 margin: 0 auto;
119 margin: 0 auto;
120 }
120 }
121
121
122 #content {
122 #content {
123 clear: both;
123 clear: both;
124 padding: 0 @contentpadding;
124 padding: 0 @contentpadding;
125 }
125 }
126
126
127 .advanced-settings-fields{
127 .advanced-settings-fields{
128 input{
128 input{
129 margin-left: @textmargin;
129 margin-left: @textmargin;
130 margin-right: @padding/2;
130 margin-right: @padding/2;
131 }
131 }
132 }
132 }
133
133
134 .cs_files_title {
134 .cs_files_title {
135 margin: @pagepadding 0 0;
135 margin: @pagepadding 0 0;
136 }
136 }
137
137
138 input.inline[type="file"] {
138 input.inline[type="file"] {
139 display: inline;
139 display: inline;
140 }
140 }
141
141
142 .error_page {
142 .error_page {
143 margin: 10% auto;
143 margin: 10% auto;
144
144
145 h1 {
145 h1 {
146 color: @grey2;
146 color: @grey2;
147 }
147 }
148
148
149 .alert {
149 .alert {
150 margin: @padding 0;
150 margin: @padding 0;
151 }
151 }
152
152
153 .error-branding {
153 .error-branding {
154 font-family: @text-semibold;
154 font-family: @text-semibold;
155 color: @grey4;
155 color: @grey4;
156 }
156 }
157
157
158 .error_message {
158 .error_message {
159 font-family: @text-regular;
159 font-family: @text-regular;
160 }
160 }
161
161
162 .sidebar {
162 .sidebar {
163 min-height: 275px;
163 min-height: 275px;
164 margin: 0;
164 margin: 0;
165 padding: 0 0 @sidebarpadding @sidebarpadding;
165 padding: 0 0 @sidebarpadding @sidebarpadding;
166 border: none;
166 border: none;
167 }
167 }
168
168
169 .main-content {
169 .main-content {
170 position: relative;
170 position: relative;
171 margin: 0 @sidebarpadding @sidebarpadding;
171 margin: 0 @sidebarpadding @sidebarpadding;
172 padding: 0 0 0 @sidebarpadding;
172 padding: 0 0 0 @sidebarpadding;
173 border-left: @border-thickness solid @grey5;
173 border-left: @border-thickness solid @grey5;
174
174
175 @media (max-width:767px) {
175 @media (max-width:767px) {
176 clear: both;
176 clear: both;
177 width: 100%;
177 width: 100%;
178 margin: 0;
178 margin: 0;
179 border: none;
179 border: none;
180 }
180 }
181 }
181 }
182
182
183 .inner-column {
183 .inner-column {
184 float: left;
184 float: left;
185 width: 29.75%;
185 width: 29.75%;
186 min-height: 150px;
186 min-height: 150px;
187 margin: @sidebarpadding 2% 0 0;
187 margin: @sidebarpadding 2% 0 0;
188 padding: 0 2% 0 0;
188 padding: 0 2% 0 0;
189 border-right: @border-thickness solid @grey5;
189 border-right: @border-thickness solid @grey5;
190
190
191 @media (max-width:767px) {
191 @media (max-width:767px) {
192 clear: both;
192 clear: both;
193 width: 100%;
193 width: 100%;
194 border: none;
194 border: none;
195 }
195 }
196
196
197 ul {
197 ul {
198 padding-left: 1.25em;
198 padding-left: 1.25em;
199 }
199 }
200
200
201 &:last-child {
201 &:last-child {
202 margin: @sidebarpadding 0 0;
202 margin: @sidebarpadding 0 0;
203 border: none;
203 border: none;
204 }
204 }
205
205
206 h4 {
206 h4 {
207 margin: 0 0 @padding;
207 margin: 0 0 @padding;
208 font-family: @text-semibold;
208 font-family: @text-semibold;
209 }
209 }
210 }
210 }
211 }
211 }
212 .error-page-logo {
212 .error-page-logo {
213 width: 130px;
213 width: 130px;
214 height: 160px;
214 height: 160px;
215 }
215 }
216
216
217 // HEADER
217 // HEADER
218 .header {
218 .header {
219
219
220 // TODO: johbo: Fix login pages, so that they work without a min-height
220 // TODO: johbo: Fix login pages, so that they work without a min-height
221 // for the header and then remove the min-height. I chose a smaller value
221 // for the header and then remove the min-height. I chose a smaller value
222 // intentionally here to avoid rendering issues in the main navigation.
222 // intentionally here to avoid rendering issues in the main navigation.
223 min-height: 49px;
223 min-height: 49px;
224
224
225 position: relative;
225 position: relative;
226 vertical-align: bottom;
226 vertical-align: bottom;
227 padding: 0 @header-padding;
227 padding: 0 @header-padding;
228 background-color: @grey2;
228 background-color: @grey2;
229 color: @grey5;
229 color: @grey5;
230
230
231 .title {
231 .title {
232 overflow: visible;
232 overflow: visible;
233 }
233 }
234
234
235 &:before,
235 &:before,
236 &:after {
236 &:after {
237 content: "";
237 content: "";
238 clear: both;
238 clear: both;
239 width: 100%;
239 width: 100%;
240 }
240 }
241
241
242 // TODO: johbo: Avoids breaking "Repositories" chooser
242 // TODO: johbo: Avoids breaking "Repositories" chooser
243 .select2-container .select2-choice .select2-arrow {
243 .select2-container .select2-choice .select2-arrow {
244 display: none;
244 display: none;
245 }
245 }
246 }
246 }
247
247
248 #header-inner {
248 #header-inner {
249 &.title {
249 &.title {
250 margin: 0;
250 margin: 0;
251 }
251 }
252 &:before,
252 &:before,
253 &:after {
253 &:after {
254 content: "";
254 content: "";
255 clear: both;
255 clear: both;
256 }
256 }
257 }
257 }
258
258
259 // Gists
259 // Gists
260 #files_data {
260 #files_data {
261 clear: both; //for firefox
261 clear: both; //for firefox
262 }
262 }
263 #gistid {
263 #gistid {
264 margin-right: @padding;
264 margin-right: @padding;
265 }
265 }
266
266
267 // Global Settings Editor
267 // Global Settings Editor
268 .textarea.editor {
268 .textarea.editor {
269 float: left;
269 float: left;
270 position: relative;
270 position: relative;
271 max-width: @texteditor-width;
271 max-width: @texteditor-width;
272
272
273 select {
273 select {
274 position: absolute;
274 position: absolute;
275 top:10px;
275 top:10px;
276 right:0;
276 right:0;
277 }
277 }
278
278
279 .CodeMirror {
279 .CodeMirror {
280 margin: 0;
280 margin: 0;
281 }
281 }
282
282
283 .help-block {
283 .help-block {
284 margin: 0 0 @padding;
284 margin: 0 0 @padding;
285 padding:.5em;
285 padding:.5em;
286 background-color: @grey6;
286 background-color: @grey6;
287 }
287 }
288 }
288 }
289
289
290 ul.auth_plugins {
290 ul.auth_plugins {
291 margin: @padding 0 @padding @legend-width;
291 margin: @padding 0 @padding @legend-width;
292 padding: 0;
292 padding: 0;
293
293
294 li {
294 li {
295 margin-bottom: @padding;
295 margin-bottom: @padding;
296 line-height: 1em;
296 line-height: 1em;
297 list-style-type: none;
297 list-style-type: none;
298
298
299 .auth_buttons .btn {
299 .auth_buttons .btn {
300 margin-right: @padding;
300 margin-right: @padding;
301 }
301 }
302
302
303 &:before { content: none; }
303 &:before { content: none; }
304 }
304 }
305 }
305 }
306
306
307
307
308 // My Account PR list
308 // My Account PR list
309
309
310 #show_closed {
310 #show_closed {
311 margin: 0 1em 0 0;
311 margin: 0 1em 0 0;
312 }
312 }
313
313
314 .pullrequestlist {
314 .pullrequestlist {
315 .closed {
315 .closed {
316 background-color: @grey6;
316 background-color: @grey6;
317 }
317 }
318 .td-status {
318 .td-status {
319 padding-left: .5em;
319 padding-left: .5em;
320 }
320 }
321 .log-container .truncate {
321 .log-container .truncate {
322 height: 2.75em;
322 height: 2.75em;
323 white-space: pre-line;
323 white-space: pre-line;
324 }
324 }
325 table.rctable .user {
325 table.rctable .user {
326 padding-left: 0;
326 padding-left: 0;
327 }
327 }
328 table.rctable {
328 table.rctable {
329 td.td-description,
329 td.td-description,
330 .rc-user {
330 .rc-user {
331 min-width: auto;
331 min-width: auto;
332 }
332 }
333 }
333 }
334 }
334 }
335
335
336 // Pull Requests
336 // Pull Requests
337
337
338 .pullrequests_section_head {
338 .pullrequests_section_head {
339 display: block;
339 display: block;
340 clear: both;
340 clear: both;
341 margin: @padding 0;
341 margin: @padding 0;
342 font-family: @text-bold;
342 font-family: @text-bold;
343 }
343 }
344
344
345 .pr-origininfo, .pr-targetinfo {
345 .pr-origininfo, .pr-targetinfo {
346 position: relative;
346 position: relative;
347
347
348 .tag {
348 .tag {
349 display: inline-block;
349 display: inline-block;
350 margin: 0 1em .5em 0;
350 margin: 0 1em .5em 0;
351 }
351 }
352
352
353 .clone-url {
353 .clone-url {
354 display: inline-block;
354 display: inline-block;
355 margin: 0 0 .5em 0;
355 margin: 0 0 .5em 0;
356 padding: 0;
356 padding: 0;
357 line-height: 1.2em;
357 line-height: 1.2em;
358 }
358 }
359 }
359 }
360
360
361 .pr-pullinfo {
361 .pr-pullinfo {
362 clear: both;
362 clear: both;
363 margin: .5em 0;
363 margin: .5em 0;
364 }
364 }
365
365
366 #pr-title-input {
366 #pr-title-input {
367 width: 72%;
367 width: 72%;
368 font-size: 1em;
368 font-size: 1em;
369 font-family: @text-bold;
369 font-family: @text-bold;
370 margin: 0;
370 margin: 0;
371 padding: 0 0 0 @padding/4;
371 padding: 0 0 0 @padding/4;
372 line-height: 1.7em;
372 line-height: 1.7em;
373 color: @text-color;
373 color: @text-color;
374 letter-spacing: .02em;
374 letter-spacing: .02em;
375 }
375 }
376
376
377 #pullrequest_title {
377 #pullrequest_title {
378 width: 100%;
378 width: 100%;
379 box-sizing: border-box;
379 box-sizing: border-box;
380 }
380 }
381
381
382 #pr_open_message {
382 #pr_open_message {
383 border: @border-thickness solid #fff;
383 border: @border-thickness solid #fff;
384 border-radius: @border-radius;
384 border-radius: @border-radius;
385 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
385 padding: @padding-large-vertical @padding-large-vertical @padding-large-vertical 0;
386 text-align: right;
386 text-align: right;
387 overflow: hidden;
387 overflow: hidden;
388 }
388 }
389
389
390 .pr-submit-button {
390 .pr-submit-button {
391 float: right;
391 float: right;
392 margin: 0 0 0 5px;
392 margin: 0 0 0 5px;
393 }
393 }
394
394
395 .pr-spacing-container {
395 .pr-spacing-container {
396 padding: 20px;
396 padding: 20px;
397 clear: both
397 clear: both
398 }
398 }
399
399
400 #pr-description-input {
400 #pr-description-input {
401 margin-bottom: 0;
401 margin-bottom: 0;
402 }
402 }
403
403
404 .pr-description-label {
404 .pr-description-label {
405 vertical-align: top;
405 vertical-align: top;
406 }
406 }
407
407
408 .perms_section_head {
408 .perms_section_head {
409 min-width: 625px;
409 min-width: 625px;
410
410
411 h2 {
411 h2 {
412 margin-bottom: 0;
412 margin-bottom: 0;
413 }
413 }
414
414
415 .label-checkbox {
415 .label-checkbox {
416 float: left;
416 float: left;
417 }
417 }
418
418
419 &.field {
419 &.field {
420 margin: @space 0 @padding;
420 margin: @space 0 @padding;
421 }
421 }
422
422
423 &:first-child.field {
423 &:first-child.field {
424 margin-top: 0;
424 margin-top: 0;
425
425
426 .label {
426 .label {
427 margin-top: 0;
427 margin-top: 0;
428 padding-top: 0;
428 padding-top: 0;
429 }
429 }
430
430
431 .radios {
431 .radios {
432 padding-top: 0;
432 padding-top: 0;
433 }
433 }
434 }
434 }
435
435
436 .radios {
436 .radios {
437 float: right;
437 float: right;
438 position: relative;
438 position: relative;
439 width: 405px;
439 width: 405px;
440 }
440 }
441 }
441 }
442
442
443 //--- MODULES ------------------//
443 //--- MODULES ------------------//
444
444
445
445
446 // Server Announcement
446 // Server Announcement
447 #server-announcement {
447 #server-announcement {
448 width: 95%;
448 width: 95%;
449 margin: @padding auto;
449 margin: @padding auto;
450 padding: @padding;
450 padding: @padding;
451 border-width: 2px;
451 border-width: 2px;
452 border-style: solid;
452 border-style: solid;
453 .border-radius(2px);
453 .border-radius(2px);
454 font-family: @text-bold;
454 font-family: @text-bold;
455
455
456 &.info { border-color: @alert4; background-color: @alert4-inner; }
456 &.info { border-color: @alert4; background-color: @alert4-inner; }
457 &.warning { border-color: @alert3; background-color: @alert3-inner; }
457 &.warning { border-color: @alert3; background-color: @alert3-inner; }
458 &.error { border-color: @alert2; background-color: @alert2-inner; }
458 &.error { border-color: @alert2; background-color: @alert2-inner; }
459 &.success { border-color: @alert1; background-color: @alert1-inner; }
459 &.success { border-color: @alert1; background-color: @alert1-inner; }
460 &.neutral { border-color: @grey3; background-color: @grey6; }
460 &.neutral { border-color: @grey3; background-color: @grey6; }
461 }
461 }
462
462
463 // Fixed Sidebar Column
463 // Fixed Sidebar Column
464 .sidebar-col-wrapper {
464 .sidebar-col-wrapper {
465 padding-left: @sidebar-all-width;
465 padding-left: @sidebar-all-width;
466
466
467 .sidebar {
467 .sidebar {
468 width: @sidebar-width;
468 width: @sidebar-width;
469 margin-left: -@sidebar-all-width;
469 margin-left: -@sidebar-all-width;
470 }
470 }
471 }
471 }
472
472
473 .sidebar-col-wrapper.scw-small {
473 .sidebar-col-wrapper.scw-small {
474 padding-left: @sidebar-small-all-width;
474 padding-left: @sidebar-small-all-width;
475
475
476 .sidebar {
476 .sidebar {
477 width: @sidebar-small-width;
477 width: @sidebar-small-width;
478 margin-left: -@sidebar-small-all-width;
478 margin-left: -@sidebar-small-all-width;
479 }
479 }
480 }
480 }
481
481
482
482
483 // FOOTER
483 // FOOTER
484 #footer {
484 #footer {
485 padding: 0;
485 padding: 0;
486 text-align: center;
486 text-align: center;
487 vertical-align: middle;
487 vertical-align: middle;
488 color: @grey2;
488 color: @grey2;
489 background-color: @grey6;
489 background-color: @grey6;
490
490
491 p {
491 p {
492 margin: 0;
492 margin: 0;
493 padding: 1em;
493 padding: 1em;
494 line-height: 1em;
494 line-height: 1em;
495 }
495 }
496
496
497 .server-instance { //server instance
497 .server-instance { //server instance
498 display: none;
498 display: none;
499 }
499 }
500
500
501 .title {
501 .title {
502 float: none;
502 float: none;
503 margin: 0 auto;
503 margin: 0 auto;
504 }
504 }
505 }
505 }
506
506
507 button.close {
507 button.close {
508 padding: 0;
508 padding: 0;
509 cursor: pointer;
509 cursor: pointer;
510 background: transparent;
510 background: transparent;
511 border: 0;
511 border: 0;
512 .box-shadow(none);
512 .box-shadow(none);
513 -webkit-appearance: none;
513 -webkit-appearance: none;
514 }
514 }
515
515
516 .close {
516 .close {
517 float: right;
517 float: right;
518 font-size: 21px;
518 font-size: 21px;
519 font-family: @text-bootstrap;
519 font-family: @text-bootstrap;
520 line-height: 1em;
520 line-height: 1em;
521 font-weight: bold;
521 font-weight: bold;
522 color: @grey2;
522 color: @grey2;
523
523
524 &:hover,
524 &:hover,
525 &:focus {
525 &:focus {
526 color: @grey1;
526 color: @grey1;
527 text-decoration: none;
527 text-decoration: none;
528 cursor: pointer;
528 cursor: pointer;
529 }
529 }
530 }
530 }
531
531
532 // GRID
532 // GRID
533 .sorting,
533 .sorting,
534 .sorting_desc,
534 .sorting_desc,
535 .sorting_asc {
535 .sorting_asc {
536 cursor: pointer;
536 cursor: pointer;
537 }
537 }
538 .sorting_desc:after {
538 .sorting_desc:after {
539 content: "\00A0\25B2";
539 content: "\00A0\25B2";
540 font-size: .75em;
540 font-size: .75em;
541 }
541 }
542 .sorting_asc:after {
542 .sorting_asc:after {
543 content: "\00A0\25BC";
543 content: "\00A0\25BC";
544 font-size: .68em;
544 font-size: .68em;
545 }
545 }
546
546
547
547
548 .user_auth_tokens {
548 .user_auth_tokens {
549
549
550 &.truncate {
550 &.truncate {
551 white-space: nowrap;
551 white-space: nowrap;
552 overflow: hidden;
552 overflow: hidden;
553 text-overflow: ellipsis;
553 text-overflow: ellipsis;
554 }
554 }
555
555
556 .fields .field .input {
556 .fields .field .input {
557 margin: 0;
557 margin: 0;
558 }
558 }
559
559
560 input#description {
560 input#description {
561 width: 100px;
561 width: 100px;
562 margin: 0;
562 margin: 0;
563 }
563 }
564
564
565 .drop-menu {
565 .drop-menu {
566 // TODO: johbo: Remove this, should work out of the box when
566 // TODO: johbo: Remove this, should work out of the box when
567 // having multiple inputs inline
567 // having multiple inputs inline
568 margin: 0 0 0 5px;
568 margin: 0 0 0 5px;
569 }
569 }
570 }
570 }
571 #user_list_table {
571 #user_list_table {
572 .closed {
572 .closed {
573 background-color: @grey6;
573 background-color: @grey6;
574 }
574 }
575 }
575 }
576
576
577
577
578 input {
578 input {
579 &.disabled {
579 &.disabled {
580 opacity: .5;
580 opacity: .5;
581 }
581 }
582 }
582 }
583
583
584 // remove extra padding in firefox
584 // remove extra padding in firefox
585 input::-moz-focus-inner { border:0; padding:0 }
585 input::-moz-focus-inner { border:0; padding:0 }
586
586
587 .adjacent input {
587 .adjacent input {
588 margin-bottom: @padding;
588 margin-bottom: @padding;
589 }
589 }
590
590
591 .permissions_boxes {
591 .permissions_boxes {
592 display: block;
592 display: block;
593 }
593 }
594
594
595 //TODO: lisa: this should be in tables
595 //TODO: lisa: this should be in tables
596 .show_more_col {
596 .show_more_col {
597 width: 20px;
597 width: 20px;
598 }
598 }
599
599
600 //FORMS
600 //FORMS
601
601
602 .medium-inline,
602 .medium-inline,
603 input#description.medium-inline {
603 input#description.medium-inline {
604 display: inline;
604 display: inline;
605 width: @medium-inline-input-width;
605 width: @medium-inline-input-width;
606 min-width: 100px;
606 min-width: 100px;
607 }
607 }
608
608
609 select {
609 select {
610 //reset
610 //reset
611 -webkit-appearance: none;
611 -webkit-appearance: none;
612 -moz-appearance: none;
612 -moz-appearance: none;
613
613
614 display: inline-block;
614 display: inline-block;
615 height: 28px;
615 height: 28px;
616 width: auto;
616 width: auto;
617 margin: 0 @padding @padding 0;
617 margin: 0 @padding @padding 0;
618 padding: 0 18px 0 8px;
618 padding: 0 18px 0 8px;
619 line-height:1em;
619 line-height:1em;
620 font-size: @basefontsize;
620 font-size: @basefontsize;
621 border: @border-thickness solid @rcblue;
621 border: @border-thickness solid @rcblue;
622 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
622 background:white url("../images/dt-arrow-dn.png") no-repeat 100% 50%;
623 color: @rcblue;
623 color: @rcblue;
624
624
625 &:after {
625 &:after {
626 content: "\00A0\25BE";
626 content: "\00A0\25BE";
627 }
627 }
628
628
629 &:focus {
629 &:focus {
630 outline: none;
630 outline: none;
631 }
631 }
632 }
632 }
633
633
634 option {
634 option {
635 &:focus {
635 &:focus {
636 outline: none;
636 outline: none;
637 }
637 }
638 }
638 }
639
639
640 input,
640 input,
641 textarea {
641 textarea {
642 padding: @input-padding;
642 padding: @input-padding;
643 border: @input-border-thickness solid @border-highlight-color;
643 border: @input-border-thickness solid @border-highlight-color;
644 .border-radius (@border-radius);
644 .border-radius (@border-radius);
645 font-family: @text-light;
645 font-family: @text-light;
646 font-size: @basefontsize;
646 font-size: @basefontsize;
647
647
648 &.input-sm {
648 &.input-sm {
649 padding: 5px;
649 padding: 5px;
650 }
650 }
651
651
652 &#description {
652 &#description {
653 min-width: @input-description-minwidth;
653 min-width: @input-description-minwidth;
654 min-height: 1em;
654 min-height: 1em;
655 padding: 10px;
655 padding: 10px;
656 }
656 }
657 }
657 }
658
658
659 .field-sm {
659 .field-sm {
660 input,
660 input,
661 textarea {
661 textarea {
662 padding: 5px;
662 padding: 5px;
663 }
663 }
664 }
664 }
665
665
666 textarea {
666 textarea {
667 display: block;
667 display: block;
668 clear: both;
668 clear: both;
669 width: 100%;
669 width: 100%;
670 min-height: 100px;
670 min-height: 100px;
671 margin-bottom: @padding;
671 margin-bottom: @padding;
672 .box-sizing(border-box);
672 .box-sizing(border-box);
673 overflow: auto;
673 overflow: auto;
674 }
674 }
675
675
676 label {
676 label {
677 font-family: @text-light;
677 font-family: @text-light;
678 }
678 }
679
679
680 // GRAVATARS
680 // GRAVATARS
681 // centers gravatar on username to the right
681 // centers gravatar on username to the right
682
682
683 .gravatar {
683 .gravatar {
684 display: inline;
684 display: inline;
685 min-width: 16px;
685 min-width: 16px;
686 min-height: 16px;
686 min-height: 16px;
687 margin: -5px 0;
687 margin: -5px 0;
688 padding: 0;
688 padding: 0;
689 line-height: 1em;
689 line-height: 1em;
690 border: 1px solid @grey4;
690 border: 1px solid @grey4;
691
691
692 &.gravatar-large {
692 &.gravatar-large {
693 margin: -0.5em .25em -0.5em 0;
693 margin: -0.5em .25em -0.5em 0;
694 }
694 }
695
695
696 & + .user {
696 & + .user {
697 display: inline;
697 display: inline;
698 margin: 0;
698 margin: 0;
699 padding: 0 0 0 .17em;
699 padding: 0 0 0 .17em;
700 line-height: 1em;
700 line-height: 1em;
701 }
701 }
702 }
702 }
703
703
704 .user-inline-data {
704 .user-inline-data {
705 display: inline-block;
705 display: inline-block;
706 float: left;
706 float: left;
707 padding-left: .5em;
707 padding-left: .5em;
708 line-height: 1.3em;
708 line-height: 1.3em;
709 }
709 }
710
710
711 .rc-user { // gravatar + user wrapper
711 .rc-user { // gravatar + user wrapper
712 float: left;
712 float: left;
713 position: relative;
713 position: relative;
714 min-width: 100px;
714 min-width: 100px;
715 max-width: 200px;
715 max-width: 200px;
716 min-height: (@gravatar-size + @border-thickness * 2); // account for border
716 min-height: (@gravatar-size + @border-thickness * 2); // account for border
717 display: block;
717 display: block;
718 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
718 padding: 0 0 0 (@gravatar-size + @basefontsize/2 + @border-thickness * 2);
719
719
720
720
721 .gravatar {
721 .gravatar {
722 display: block;
722 display: block;
723 position: absolute;
723 position: absolute;
724 top: 0;
724 top: 0;
725 left: 0;
725 left: 0;
726 min-width: @gravatar-size;
726 min-width: @gravatar-size;
727 min-height: @gravatar-size;
727 min-height: @gravatar-size;
728 margin: 0;
728 margin: 0;
729 }
729 }
730
730
731 .user {
731 .user {
732 display: block;
732 display: block;
733 max-width: 175px;
733 max-width: 175px;
734 padding-top: 2px;
734 padding-top: 2px;
735 overflow: hidden;
735 overflow: hidden;
736 text-overflow: ellipsis;
736 text-overflow: ellipsis;
737 }
737 }
738 }
738 }
739
739
740 .gist-gravatar,
740 .gist-gravatar,
741 .journal_container {
741 .journal_container {
742 .gravatar-large {
742 .gravatar-large {
743 margin: 0 .5em -10px 0;
743 margin: 0 .5em -10px 0;
744 }
744 }
745 }
745 }
746
746
747
747
748 // ADMIN SETTINGS
748 // ADMIN SETTINGS
749
749
750 // Tag Patterns
750 // Tag Patterns
751 .tag_patterns {
751 .tag_patterns {
752 .tag_input {
752 .tag_input {
753 margin-bottom: @padding;
753 margin-bottom: @padding;
754 }
754 }
755 }
755 }
756
756
757 .locked_input {
757 .locked_input {
758 position: relative;
758 position: relative;
759
759
760 input {
760 input {
761 display: inline;
761 display: inline;
762 margin-top: 3px;
762 margin-top: 3px;
763 }
763 }
764
764
765 br {
765 br {
766 display: none;
766 display: none;
767 }
767 }
768
768
769 .error-message {
769 .error-message {
770 float: left;
770 float: left;
771 width: 100%;
771 width: 100%;
772 }
772 }
773
773
774 .lock_input_button {
774 .lock_input_button {
775 display: inline;
775 display: inline;
776 }
776 }
777
777
778 .help-block {
778 .help-block {
779 clear: both;
779 clear: both;
780 }
780 }
781 }
781 }
782
782
783 // Notifications
783 // Notifications
784
784
785 .notifications_buttons {
785 .notifications_buttons {
786 margin: 0 0 @space 0;
786 margin: 0 0 @space 0;
787 padding: 0;
787 padding: 0;
788
788
789 .btn {
789 .btn {
790 display: inline-block;
790 display: inline-block;
791 }
791 }
792 }
792 }
793
793
794 .notification-list {
794 .notification-list {
795
795
796 div {
796 div {
797 display: inline-block;
797 display: inline-block;
798 vertical-align: middle;
798 vertical-align: middle;
799 }
799 }
800
800
801 .container {
801 .container {
802 display: block;
802 display: block;
803 margin: 0 0 @padding 0;
803 margin: 0 0 @padding 0;
804 }
804 }
805
805
806 .delete-notifications {
806 .delete-notifications {
807 margin-left: @padding;
807 margin-left: @padding;
808 text-align: right;
808 text-align: right;
809 cursor: pointer;
809 cursor: pointer;
810 }
810 }
811
811
812 .read-notifications {
812 .read-notifications {
813 margin-left: @padding/2;
813 margin-left: @padding/2;
814 text-align: right;
814 text-align: right;
815 width: 35px;
815 width: 35px;
816 cursor: pointer;
816 cursor: pointer;
817 }
817 }
818
818
819 .icon-minus-sign {
819 .icon-minus-sign {
820 color: @alert2;
820 color: @alert2;
821 }
821 }
822
822
823 .icon-ok-sign {
823 .icon-ok-sign {
824 color: @alert1;
824 color: @alert1;
825 }
825 }
826 }
826 }
827
827
828 .user_settings {
828 .user_settings {
829 float: left;
829 float: left;
830 clear: both;
830 clear: both;
831 display: block;
831 display: block;
832 width: 100%;
832 width: 100%;
833
833
834 .gravatar_box {
834 .gravatar_box {
835 margin-bottom: @padding;
835 margin-bottom: @padding;
836
836
837 &:after {
837 &:after {
838 content: " ";
838 content: " ";
839 clear: both;
839 clear: both;
840 width: 100%;
840 width: 100%;
841 }
841 }
842 }
842 }
843
843
844 .fields .field {
844 .fields .field {
845 clear: both;
845 clear: both;
846 }
846 }
847 }
847 }
848
848
849 .advanced_settings {
849 .advanced_settings {
850 margin-bottom: @space;
850 margin-bottom: @space;
851
851
852 .help-block {
852 .help-block {
853 margin-left: 0;
853 margin-left: 0;
854 }
854 }
855
855
856 button + .help-block {
856 button + .help-block {
857 margin-top: @padding;
857 margin-top: @padding;
858 }
858 }
859 }
859 }
860
860
861 // admin settings radio buttons and labels
861 // admin settings radio buttons and labels
862 .label-2 {
862 .label-2 {
863 float: left;
863 float: left;
864 width: @label2-width;
864 width: @label2-width;
865
865
866 label {
866 label {
867 color: @grey1;
867 color: @grey1;
868 }
868 }
869 }
869 }
870 .checkboxes {
870 .checkboxes {
871 float: left;
871 float: left;
872 width: @checkboxes-width;
872 width: @checkboxes-width;
873 margin-bottom: @padding;
873 margin-bottom: @padding;
874
874
875 .checkbox {
875 .checkbox {
876 width: 100%;
876 width: 100%;
877
877
878 label {
878 label {
879 margin: 0;
879 margin: 0;
880 padding: 0;
880 padding: 0;
881 }
881 }
882 }
882 }
883
883
884 .checkbox + .checkbox {
884 .checkbox + .checkbox {
885 display: inline-block;
885 display: inline-block;
886 }
886 }
887
887
888 label {
888 label {
889 margin-right: 1em;
889 margin-right: 1em;
890 }
890 }
891 }
891 }
892
892
893 // CHANGELOG
893 // CHANGELOG
894 .container_header {
894 .container_header {
895 float: left;
895 float: left;
896 display: block;
896 display: block;
897 width: 100%;
897 width: 100%;
898 margin: @padding 0 @padding;
898 margin: @padding 0 @padding;
899
899
900 #filter_changelog {
900 #filter_changelog {
901 float: left;
901 float: left;
902 margin-right: @padding;
902 margin-right: @padding;
903 }
903 }
904
904
905 .breadcrumbs_light {
905 .breadcrumbs_light {
906 display: inline-block;
906 display: inline-block;
907 }
907 }
908 }
908 }
909
909
910 .info_box {
910 .info_box {
911 float: right;
911 float: right;
912 }
912 }
913
913
914
914
915 #graph_nodes {
915 #graph_nodes {
916 padding-top: 43px;
916 padding-top: 43px;
917 }
917 }
918
918
919 #graph_content{
919 #graph_content{
920
920
921 // adjust for table headers so that graph renders properly
921 // adjust for table headers so that graph renders properly
922 // #graph_nodes padding - table cell padding
922 // #graph_nodes padding - table cell padding
923 padding-top: (@space - (@basefontsize * 2.4));
923 padding-top: (@space - (@basefontsize * 2.4));
924
924
925 &.graph_full_width {
925 &.graph_full_width {
926 width: 100%;
926 width: 100%;
927 max-width: 100%;
927 max-width: 100%;
928 }
928 }
929 }
929 }
930
930
931 #graph {
931 #graph {
932 .flag_status {
932 .flag_status {
933 margin: 0;
933 margin: 0;
934 }
934 }
935
935
936 .pagination-left {
936 .pagination-left {
937 float: left;
937 float: left;
938 clear: both;
938 clear: both;
939 }
939 }
940
940
941 .log-container {
941 .log-container {
942 max-width: 345px;
942 max-width: 345px;
943
943
944 .message{
944 .message{
945 max-width: 340px;
945 max-width: 340px;
946 }
946 }
947 }
947 }
948
948
949 .graph-col-wrapper {
949 .graph-col-wrapper {
950 padding-left: 110px;
950 padding-left: 110px;
951
951
952 #graph_nodes {
952 #graph_nodes {
953 width: 100px;
953 width: 100px;
954 margin-left: -110px;
954 margin-left: -110px;
955 float: left;
955 float: left;
956 clear: left;
956 clear: left;
957 }
957 }
958 }
958 }
959 }
959 }
960
960
961 #filter_changelog {
961 #filter_changelog {
962 float: left;
962 float: left;
963 }
963 }
964
964
965
965
966 //--- THEME ------------------//
966 //--- THEME ------------------//
967
967
968 #logo {
968 #logo {
969 float: left;
969 float: left;
970 margin: 9px 0 0 0;
970 margin: 9px 0 0 0;
971
971
972 .header {
972 .header {
973 background-color: transparent;
973 background-color: transparent;
974 }
974 }
975
975
976 a {
976 a {
977 display: inline-block;
977 display: inline-block;
978 }
978 }
979
979
980 img {
980 img {
981 height:30px;
981 height:30px;
982 }
982 }
983 }
983 }
984
984
985 .logo-wrapper {
985 .logo-wrapper {
986 float:left;
986 float:left;
987 }
987 }
988
988
989 .branding{
989 .branding{
990 float: left;
990 float: left;
991 padding: 9px 2px;
991 padding: 9px 2px;
992 line-height: 1em;
992 line-height: 1em;
993 font-size: @navigation-fontsize;
993 font-size: @navigation-fontsize;
994 }
994 }
995
995
996 img {
996 img {
997 border: none;
997 border: none;
998 outline: none;
998 outline: none;
999 }
999 }
1000 user-profile-header
1000 user-profile-header
1001 label {
1001 label {
1002
1002
1003 input[type="checkbox"] {
1003 input[type="checkbox"] {
1004 margin-right: 1em;
1004 margin-right: 1em;
1005 }
1005 }
1006 input[type="radio"] {
1006 input[type="radio"] {
1007 margin-right: 1em;
1007 margin-right: 1em;
1008 }
1008 }
1009 }
1009 }
1010
1010
1011 .flag_status {
1011 .flag_status {
1012 margin: 2px 8px 6px 2px;
1012 margin: 2px 8px 6px 2px;
1013 &.under_review {
1013 &.under_review {
1014 .circle(5px, @alert3);
1014 .circle(5px, @alert3);
1015 }
1015 }
1016 &.approved {
1016 &.approved {
1017 .circle(5px, @alert1);
1017 .circle(5px, @alert1);
1018 }
1018 }
1019 &.rejected,
1019 &.rejected,
1020 &.forced_closed{
1020 &.forced_closed{
1021 .circle(5px, @alert2);
1021 .circle(5px, @alert2);
1022 }
1022 }
1023 &.not_reviewed {
1023 &.not_reviewed {
1024 .circle(5px, @grey5);
1024 .circle(5px, @grey5);
1025 }
1025 }
1026 }
1026 }
1027
1027
1028 .flag_status_comment_box {
1028 .flag_status_comment_box {
1029 margin: 5px 6px 0px 2px;
1029 margin: 5px 6px 0px 2px;
1030 }
1030 }
1031 .test_pattern_preview {
1031 .test_pattern_preview {
1032 margin: @space 0;
1032 margin: @space 0;
1033
1033
1034 p {
1034 p {
1035 margin-bottom: 0;
1035 margin-bottom: 0;
1036 border-bottom: @border-thickness solid @border-default-color;
1036 border-bottom: @border-thickness solid @border-default-color;
1037 color: @grey3;
1037 color: @grey3;
1038 }
1038 }
1039
1039
1040 .btn {
1040 .btn {
1041 margin-bottom: @padding;
1041 margin-bottom: @padding;
1042 }
1042 }
1043 }
1043 }
1044 #test_pattern_result {
1044 #test_pattern_result {
1045 display: none;
1045 display: none;
1046 &:extend(pre);
1046 &:extend(pre);
1047 padding: .9em;
1047 padding: .9em;
1048 color: @grey3;
1048 color: @grey3;
1049 background-color: @grey7;
1049 background-color: @grey7;
1050 border-right: @border-thickness solid @border-default-color;
1050 border-right: @border-thickness solid @border-default-color;
1051 border-bottom: @border-thickness solid @border-default-color;
1051 border-bottom: @border-thickness solid @border-default-color;
1052 border-left: @border-thickness solid @border-default-color;
1052 border-left: @border-thickness solid @border-default-color;
1053 }
1053 }
1054
1054
1055 #repo_vcs_settings {
1055 #repo_vcs_settings {
1056 #inherit_overlay_vcs_default {
1056 #inherit_overlay_vcs_default {
1057 display: none;
1057 display: none;
1058 }
1058 }
1059 #inherit_overlay_vcs_custom {
1059 #inherit_overlay_vcs_custom {
1060 display: custom;
1060 display: custom;
1061 }
1061 }
1062 &.inherited {
1062 &.inherited {
1063 #inherit_overlay_vcs_default {
1063 #inherit_overlay_vcs_default {
1064 display: block;
1064 display: block;
1065 }
1065 }
1066 #inherit_overlay_vcs_custom {
1066 #inherit_overlay_vcs_custom {
1067 display: none;
1067 display: none;
1068 }
1068 }
1069 }
1069 }
1070 }
1070 }
1071
1071
1072 .issue-tracker-link {
1072 .issue-tracker-link {
1073 color: @rcblue;
1073 color: @rcblue;
1074 }
1074 }
1075
1075
1076 // Issue Tracker Table Show/Hide
1076 // Issue Tracker Table Show/Hide
1077 #repo_issue_tracker {
1077 #repo_issue_tracker {
1078 #inherit_overlay {
1078 #inherit_overlay {
1079 display: none;
1079 display: none;
1080 }
1080 }
1081 #custom_overlay {
1081 #custom_overlay {
1082 display: custom;
1082 display: custom;
1083 }
1083 }
1084 &.inherited {
1084 &.inherited {
1085 #inherit_overlay {
1085 #inherit_overlay {
1086 display: block;
1086 display: block;
1087 }
1087 }
1088 #custom_overlay {
1088 #custom_overlay {
1089 display: none;
1089 display: none;
1090 }
1090 }
1091 }
1091 }
1092 }
1092 }
1093 table.issuetracker {
1093 table.issuetracker {
1094 &.readonly {
1094 &.readonly {
1095 tr, td {
1095 tr, td {
1096 color: @grey3;
1096 color: @grey3;
1097 }
1097 }
1098 }
1098 }
1099 .edit {
1099 .edit {
1100 display: none;
1100 display: none;
1101 }
1101 }
1102 .editopen {
1102 .editopen {
1103 .edit {
1103 .edit {
1104 display: inline;
1104 display: inline;
1105 }
1105 }
1106 .entry {
1106 .entry {
1107 display: none;
1107 display: none;
1108 }
1108 }
1109 }
1109 }
1110 tr td.td-action {
1110 tr td.td-action {
1111 min-width: 117px;
1111 min-width: 117px;
1112 }
1112 }
1113 td input {
1113 td input {
1114 max-width: none;
1114 max-width: none;
1115 min-width: 30px;
1115 min-width: 30px;
1116 width: 80%;
1116 width: 80%;
1117 }
1117 }
1118 .issuetracker_pref input {
1118 .issuetracker_pref input {
1119 width: 40%;
1119 width: 40%;
1120 }
1120 }
1121 input.edit_issuetracker_update {
1121 input.edit_issuetracker_update {
1122 margin-right: 0;
1122 margin-right: 0;
1123 width: auto;
1123 width: auto;
1124 }
1124 }
1125 }
1125 }
1126
1126
1127 table.integrations {
1127 table.integrations {
1128 .td-icon {
1128 .td-icon {
1129 width: 20px;
1129 width: 20px;
1130 .integration-icon {
1130 .integration-icon {
1131 height: 20px;
1131 height: 20px;
1132 width: 20px;
1132 width: 20px;
1133 }
1133 }
1134 }
1134 }
1135 }
1135 }
1136
1136
1137 .integrations {
1137 .integrations {
1138 a.integration-box {
1138 a.integration-box {
1139 color: @text-color;
1139 color: @text-color;
1140 &:hover {
1140 &:hover {
1141 .panel {
1141 .panel {
1142 background: #fbfbfb;
1142 background: #fbfbfb;
1143 }
1143 }
1144 }
1144 }
1145 .integration-icon {
1145 .integration-icon {
1146 width: 30px;
1146 width: 30px;
1147 height: 30px;
1147 height: 30px;
1148 margin-right: 20px;
1148 margin-right: 20px;
1149 float: left;
1149 float: left;
1150 }
1150 }
1151
1151
1152 .panel-body {
1152 .panel-body {
1153 padding: 10px;
1153 padding: 10px;
1154 }
1154 }
1155 .panel {
1155 .panel {
1156 margin-bottom: 10px;
1156 margin-bottom: 10px;
1157 }
1157 }
1158 h2 {
1158 h2 {
1159 display: inline-block;
1159 display: inline-block;
1160 margin: 0;
1160 margin: 0;
1161 min-width: 140px;
1161 min-width: 140px;
1162 }
1162 }
1163 }
1163 }
1164 }
1164 }
1165
1165
1166 //Permissions Settings
1166 //Permissions Settings
1167 #add_perm {
1167 #add_perm {
1168 margin: 0 0 @padding;
1168 margin: 0 0 @padding;
1169 cursor: pointer;
1169 cursor: pointer;
1170 }
1170 }
1171
1171
1172 .perm_ac {
1172 .perm_ac {
1173 input {
1173 input {
1174 width: 95%;
1174 width: 95%;
1175 }
1175 }
1176 }
1176 }
1177
1177
1178 .autocomplete-suggestions {
1178 .autocomplete-suggestions {
1179 width: auto !important; // overrides autocomplete.js
1179 width: auto !important; // overrides autocomplete.js
1180 margin: 0;
1180 margin: 0;
1181 border: @border-thickness solid @rcblue;
1181 border: @border-thickness solid @rcblue;
1182 border-radius: @border-radius;
1182 border-radius: @border-radius;
1183 color: @rcblue;
1183 color: @rcblue;
1184 background-color: white;
1184 background-color: white;
1185 }
1185 }
1186 .autocomplete-selected {
1186 .autocomplete-selected {
1187 background: #F0F0F0;
1187 background: #F0F0F0;
1188 }
1188 }
1189 .ac-container-wrap {
1189 .ac-container-wrap {
1190 margin: 0;
1190 margin: 0;
1191 padding: 8px;
1191 padding: 8px;
1192 border-bottom: @border-thickness solid @rclightblue;
1192 border-bottom: @border-thickness solid @rclightblue;
1193 list-style-type: none;
1193 list-style-type: none;
1194 cursor: pointer;
1194 cursor: pointer;
1195
1195
1196 &:hover {
1196 &:hover {
1197 background-color: @rclightblue;
1197 background-color: @rclightblue;
1198 }
1198 }
1199
1199
1200 img {
1200 img {
1201 height: @gravatar-size;
1201 height: @gravatar-size;
1202 width: @gravatar-size;
1202 width: @gravatar-size;
1203 margin-right: 1em;
1203 margin-right: 1em;
1204 }
1204 }
1205
1205
1206 strong {
1206 strong {
1207 font-weight: normal;
1207 font-weight: normal;
1208 }
1208 }
1209 }
1209 }
1210
1210
1211 // Settings Dropdown
1211 // Settings Dropdown
1212 .user-menu .container {
1212 .user-menu .container {
1213 padding: 0 4px;
1213 padding: 0 4px;
1214 margin: 0;
1214 margin: 0;
1215 }
1215 }
1216
1216
1217 .user-menu .gravatar {
1217 .user-menu .gravatar {
1218 cursor: pointer;
1218 cursor: pointer;
1219 }
1219 }
1220
1220
1221 .codeblock {
1221 .codeblock {
1222 margin-bottom: @padding;
1222 margin-bottom: @padding;
1223 clear: both;
1223 clear: both;
1224
1224
1225 .stats{
1225 .stats{
1226 overflow: hidden;
1226 overflow: hidden;
1227 }
1227 }
1228
1228
1229 .message{
1229 .message{
1230 textarea{
1230 textarea{
1231 margin: 0;
1231 margin: 0;
1232 }
1232 }
1233 }
1233 }
1234
1234
1235 .code-header {
1235 .code-header {
1236 .stats {
1236 .stats {
1237 line-height: 2em;
1237 line-height: 2em;
1238
1238
1239 .revision_id {
1239 .revision_id {
1240 margin-left: 0;
1240 margin-left: 0;
1241 }
1241 }
1242 .buttons {
1242 .buttons {
1243 padding-right: 0;
1243 padding-right: 0;
1244 }
1244 }
1245 }
1245 }
1246
1246
1247 .item{
1247 .item{
1248 margin-right: 0.5em;
1248 margin-right: 0.5em;
1249 }
1249 }
1250 }
1250 }
1251
1251
1252 #editor_container{
1252 #editor_container{
1253 position: relative;
1253 position: relative;
1254 margin: @padding;
1254 margin: @padding;
1255 }
1255 }
1256 }
1256 }
1257
1257
1258 #file_history_container {
1258 #file_history_container {
1259 display: none;
1259 display: none;
1260 }
1260 }
1261
1261
1262 .file-history-inner {
1262 .file-history-inner {
1263 margin-bottom: 10px;
1263 margin-bottom: 10px;
1264 }
1264 }
1265
1265
1266 // Pull Requests
1266 // Pull Requests
1267 .summary-details {
1267 .summary-details {
1268 width: 72%;
1268 width: 72%;
1269 }
1269 }
1270 .pr-summary {
1270 .pr-summary {
1271 border-bottom: @border-thickness solid @grey5;
1271 border-bottom: @border-thickness solid @grey5;
1272 margin-bottom: @space;
1272 margin-bottom: @space;
1273 }
1273 }
1274 .reviewers-title {
1274 .reviewers-title {
1275 width: 25%;
1275 width: 25%;
1276 min-width: 200px;
1276 min-width: 200px;
1277 }
1277 }
1278 .reviewers {
1278 .reviewers {
1279 width: 25%;
1279 width: 25%;
1280 min-width: 200px;
1280 min-width: 200px;
1281 }
1281 }
1282 .reviewers ul li {
1282 .reviewers ul li {
1283 position: relative;
1283 position: relative;
1284 width: 100%;
1284 width: 100%;
1285 margin-bottom: 8px;
1285 margin-bottom: 8px;
1286 }
1286 }
1287 .reviewers_member {
1287 .reviewers_member {
1288 width: 100%;
1288 width: 100%;
1289 overflow: auto;
1289 overflow: auto;
1290 }
1290 }
1291 .reviewer_reason {
1291 .reviewer_reason {
1292 padding-left: 20px;
1292 padding-left: 20px;
1293 }
1293 }
1294 .reviewer_status {
1294 .reviewer_status {
1295 display: inline-block;
1295 display: inline-block;
1296 vertical-align: top;
1296 vertical-align: top;
1297 width: 7%;
1297 width: 7%;
1298 min-width: 20px;
1298 min-width: 20px;
1299 height: 1.2em;
1299 height: 1.2em;
1300 margin-top: 3px;
1300 margin-top: 3px;
1301 line-height: 1em;
1301 line-height: 1em;
1302 }
1302 }
1303
1303
1304 .reviewer_name {
1304 .reviewer_name {
1305 display: inline-block;
1305 display: inline-block;
1306 max-width: 83%;
1306 max-width: 83%;
1307 padding-right: 20px;
1307 padding-right: 20px;
1308 vertical-align: middle;
1308 vertical-align: middle;
1309 line-height: 1;
1309 line-height: 1;
1310
1310
1311 .rc-user {
1311 .rc-user {
1312 min-width: 0;
1312 min-width: 0;
1313 margin: -2px 1em 0 0;
1313 margin: -2px 1em 0 0;
1314 }
1314 }
1315
1315
1316 .reviewer {
1316 .reviewer {
1317 float: left;
1317 float: left;
1318 }
1318 }
1319
1319
1320 &.to-delete {
1320 &.to-delete {
1321 .user,
1321 .user,
1322 .reviewer {
1322 .reviewer {
1323 text-decoration: line-through;
1323 text-decoration: line-through;
1324 }
1324 }
1325 }
1325 }
1326 }
1326 }
1327
1327
1328 .reviewer_member_remove {
1328 .reviewer_member_remove {
1329 position: absolute;
1329 position: absolute;
1330 right: 0;
1330 right: 0;
1331 top: 0;
1331 top: 0;
1332 width: 16px;
1332 width: 16px;
1333 margin-bottom: 10px;
1333 margin-bottom: 10px;
1334 padding: 0;
1334 padding: 0;
1335 color: black;
1335 color: black;
1336 }
1336 }
1337 .reviewer_member_status {
1337 .reviewer_member_status {
1338 margin-top: 5px;
1338 margin-top: 5px;
1339 }
1339 }
1340 .pr-summary #summary{
1340 .pr-summary #summary{
1341 width: 100%;
1341 width: 100%;
1342 }
1342 }
1343 .pr-summary .action_button:hover {
1343 .pr-summary .action_button:hover {
1344 border: 0;
1344 border: 0;
1345 cursor: pointer;
1345 cursor: pointer;
1346 }
1346 }
1347 .pr-details-title {
1347 .pr-details-title {
1348 padding-bottom: 8px;
1348 padding-bottom: 8px;
1349 border-bottom: @border-thickness solid @grey5;
1349 border-bottom: @border-thickness solid @grey5;
1350
1350
1351 .action_button.disabled {
1351 .action_button.disabled {
1352 color: @grey4;
1352 color: @grey4;
1353 cursor: inherit;
1353 cursor: inherit;
1354 }
1354 }
1355 .action_button {
1355 .action_button {
1356 color: @rcblue;
1356 color: @rcblue;
1357 }
1357 }
1358 }
1358 }
1359 .pr-details-content {
1359 .pr-details-content {
1360 margin-top: @textmargin;
1360 margin-top: @textmargin;
1361 margin-bottom: @textmargin;
1361 margin-bottom: @textmargin;
1362 }
1362 }
1363 .pr-description {
1363 .pr-description {
1364 white-space:pre-wrap;
1364 white-space:pre-wrap;
1365 }
1365 }
1366 .group_members {
1366 .group_members {
1367 margin-top: 0;
1367 margin-top: 0;
1368 padding: 0;
1368 padding: 0;
1369 list-style: outside none none;
1369 list-style: outside none none;
1370
1370
1371 img {
1371 img {
1372 height: @gravatar-size;
1372 height: @gravatar-size;
1373 width: @gravatar-size;
1373 width: @gravatar-size;
1374 margin-right: .5em;
1374 margin-right: .5em;
1375 margin-left: 3px;
1375 margin-left: 3px;
1376 }
1376 }
1377
1377
1378 .to-delete {
1378 .to-delete {
1379 .user {
1379 .user {
1380 text-decoration: line-through;
1380 text-decoration: line-through;
1381 }
1381 }
1382 }
1382 }
1383 }
1383 }
1384
1384
1385 .compare_view_commits_title {
1385 .compare_view_commits_title {
1386 .disabled {
1386 .disabled {
1387 cursor: inherit;
1387 cursor: inherit;
1388 &:hover{
1388 &:hover{
1389 background-color: inherit;
1389 background-color: inherit;
1390 color: inherit;
1390 color: inherit;
1391 }
1391 }
1392 }
1392 }
1393 }
1393 }
1394
1394
1395 // new entry in group_members
1395 // new entry in group_members
1396 .td-author-new-entry {
1396 .td-author-new-entry {
1397 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1397 background-color: rgba(red(@alert1), green(@alert1), blue(@alert1), 0.3);
1398 }
1398 }
1399
1399
1400 .usergroup_member_remove {
1400 .usergroup_member_remove {
1401 width: 16px;
1401 width: 16px;
1402 margin-bottom: 10px;
1402 margin-bottom: 10px;
1403 padding: 0;
1403 padding: 0;
1404 color: black !important;
1404 color: black !important;
1405 cursor: pointer;
1405 cursor: pointer;
1406 }
1406 }
1407
1407
1408 .reviewer_ac .ac-input {
1408 .reviewer_ac .ac-input {
1409 width: 92%;
1409 width: 92%;
1410 margin-bottom: 1em;
1410 margin-bottom: 1em;
1411 }
1411 }
1412
1412
1413 .compare_view_commits tr{
1413 .compare_view_commits tr{
1414 height: 20px;
1414 height: 20px;
1415 }
1415 }
1416 .compare_view_commits td {
1416 .compare_view_commits td {
1417 vertical-align: top;
1417 vertical-align: top;
1418 padding-top: 10px;
1418 padding-top: 10px;
1419 }
1419 }
1420 .compare_view_commits .author {
1420 .compare_view_commits .author {
1421 margin-left: 5px;
1421 margin-left: 5px;
1422 }
1422 }
1423
1423
1424 .compare_view_files {
1424 .compare_view_files {
1425 width: 100%;
1425 width: 100%;
1426
1426
1427 td {
1427 td {
1428 vertical-align: middle;
1428 vertical-align: middle;
1429 }
1429 }
1430 }
1430 }
1431
1431
1432 .compare_view_filepath {
1432 .compare_view_filepath {
1433 color: @grey1;
1433 color: @grey1;
1434 }
1434 }
1435
1435
1436 .show_more {
1436 .show_more {
1437 display: inline-block;
1437 display: inline-block;
1438 position: relative;
1438 position: relative;
1439 vertical-align: middle;
1439 vertical-align: middle;
1440 width: 4px;
1440 width: 4px;
1441 height: @basefontsize;
1441 height: @basefontsize;
1442
1442
1443 &:after {
1443 &:after {
1444 content: "\00A0\25BE";
1444 content: "\00A0\25BE";
1445 display: inline-block;
1445 display: inline-block;
1446 width:10px;
1446 width:10px;
1447 line-height: 5px;
1447 line-height: 5px;
1448 font-size: 12px;
1448 font-size: 12px;
1449 cursor: pointer;
1449 cursor: pointer;
1450 }
1450 }
1451 }
1451 }
1452
1452
1453 .journal_more .show_more {
1453 .journal_more .show_more {
1454 display: inline;
1454 display: inline;
1455
1455
1456 &:after {
1456 &:after {
1457 content: none;
1457 content: none;
1458 }
1458 }
1459 }
1459 }
1460
1460
1461 .open .show_more:after,
1461 .open .show_more:after,
1462 .select2-dropdown-open .show_more:after {
1462 .select2-dropdown-open .show_more:after {
1463 .rotate(180deg);
1463 .rotate(180deg);
1464 margin-left: 4px;
1464 margin-left: 4px;
1465 }
1465 }
1466
1466
1467
1467
1468 .compare_view_commits .collapse_commit:after {
1468 .compare_view_commits .collapse_commit:after {
1469 cursor: pointer;
1469 cursor: pointer;
1470 content: "\00A0\25B4";
1470 content: "\00A0\25B4";
1471 margin-left: -3px;
1471 margin-left: -3px;
1472 font-size: 17px;
1472 font-size: 17px;
1473 color: @grey4;
1473 color: @grey4;
1474 }
1474 }
1475
1475
1476 .diff_links {
1476 .diff_links {
1477 margin-left: 8px;
1477 margin-left: 8px;
1478 }
1478 }
1479
1479
1480 p.ancestor {
1480 div.ancestor {
1481 margin: @padding 0;
1481 margin: @padding 0;
1482 line-height: 3.0em;
1482 }
1483 }
1483
1484
1484 .cs_icon_td input[type="checkbox"] {
1485 .cs_icon_td input[type="checkbox"] {
1485 display: none;
1486 display: none;
1486 }
1487 }
1487
1488
1488 .cs_icon_td .expand_file_icon:after {
1489 .cs_icon_td .expand_file_icon:after {
1489 cursor: pointer;
1490 cursor: pointer;
1490 content: "\00A0\25B6";
1491 content: "\00A0\25B6";
1491 font-size: 12px;
1492 font-size: 12px;
1492 color: @grey4;
1493 color: @grey4;
1493 }
1494 }
1494
1495
1495 .cs_icon_td .collapse_file_icon:after {
1496 .cs_icon_td .collapse_file_icon:after {
1496 cursor: pointer;
1497 cursor: pointer;
1497 content: "\00A0\25BC";
1498 content: "\00A0\25BC";
1498 font-size: 12px;
1499 font-size: 12px;
1499 color: @grey4;
1500 color: @grey4;
1500 }
1501 }
1501
1502
1502 /*new binary
1503 /*new binary
1503 NEW_FILENODE = 1
1504 NEW_FILENODE = 1
1504 DEL_FILENODE = 2
1505 DEL_FILENODE = 2
1505 MOD_FILENODE = 3
1506 MOD_FILENODE = 3
1506 RENAMED_FILENODE = 4
1507 RENAMED_FILENODE = 4
1507 COPIED_FILENODE = 5
1508 COPIED_FILENODE = 5
1508 CHMOD_FILENODE = 6
1509 CHMOD_FILENODE = 6
1509 BIN_FILENODE = 7
1510 BIN_FILENODE = 7
1510 */
1511 */
1511 .cs_files_expand {
1512 .cs_files_expand {
1512 font-size: @basefontsize + 5px;
1513 font-size: @basefontsize + 5px;
1513 line-height: 1.8em;
1514 line-height: 1.8em;
1514 float: right;
1515 float: right;
1515 }
1516 }
1516
1517
1517 .cs_files_expand span{
1518 .cs_files_expand span{
1518 color: @rcblue;
1519 color: @rcblue;
1519 cursor: pointer;
1520 cursor: pointer;
1520 }
1521 }
1521 .cs_files {
1522 .cs_files {
1522 clear: both;
1523 clear: both;
1523 padding-bottom: @padding;
1524 padding-bottom: @padding;
1524
1525
1525 .cur_cs {
1526 .cur_cs {
1526 margin: 10px 2px;
1527 margin: 10px 2px;
1527 font-weight: bold;
1528 font-weight: bold;
1528 }
1529 }
1529
1530
1530 .node {
1531 .node {
1531 float: left;
1532 float: left;
1532 }
1533 }
1533
1534
1534 .changes {
1535 .changes {
1535 float: right;
1536 float: right;
1536 color: white;
1537 color: white;
1537 font-size: @basefontsize - 4px;
1538 font-size: @basefontsize - 4px;
1538 margin-top: 4px;
1539 margin-top: 4px;
1539 opacity: 0.6;
1540 opacity: 0.6;
1540 filter: Alpha(opacity=60); /* IE8 and earlier */
1541 filter: Alpha(opacity=60); /* IE8 and earlier */
1541
1542
1542 .added {
1543 .added {
1543 background-color: @alert1;
1544 background-color: @alert1;
1544 float: left;
1545 float: left;
1545 text-align: center;
1546 text-align: center;
1546 }
1547 }
1547
1548
1548 .deleted {
1549 .deleted {
1549 background-color: @alert2;
1550 background-color: @alert2;
1550 float: left;
1551 float: left;
1551 text-align: center;
1552 text-align: center;
1552 }
1553 }
1553
1554
1554 .bin {
1555 .bin {
1555 background-color: @alert1;
1556 background-color: @alert1;
1556 text-align: center;
1557 text-align: center;
1557 }
1558 }
1558
1559
1559 /*new binary*/
1560 /*new binary*/
1560 .bin.bin1 {
1561 .bin.bin1 {
1561 background-color: @alert1;
1562 background-color: @alert1;
1562 text-align: center;
1563 text-align: center;
1563 }
1564 }
1564
1565
1565 /*deleted binary*/
1566 /*deleted binary*/
1566 .bin.bin2 {
1567 .bin.bin2 {
1567 background-color: @alert2;
1568 background-color: @alert2;
1568 text-align: center;
1569 text-align: center;
1569 }
1570 }
1570
1571
1571 /*mod binary*/
1572 /*mod binary*/
1572 .bin.bin3 {
1573 .bin.bin3 {
1573 background-color: @grey2;
1574 background-color: @grey2;
1574 text-align: center;
1575 text-align: center;
1575 }
1576 }
1576
1577
1577 /*rename file*/
1578 /*rename file*/
1578 .bin.bin4 {
1579 .bin.bin4 {
1579 background-color: @alert4;
1580 background-color: @alert4;
1580 text-align: center;
1581 text-align: center;
1581 }
1582 }
1582
1583
1583 /*copied file*/
1584 /*copied file*/
1584 .bin.bin5 {
1585 .bin.bin5 {
1585 background-color: @alert4;
1586 background-color: @alert4;
1586 text-align: center;
1587 text-align: center;
1587 }
1588 }
1588
1589
1589 /*chmod file*/
1590 /*chmod file*/
1590 .bin.bin6 {
1591 .bin.bin6 {
1591 background-color: @grey2;
1592 background-color: @grey2;
1592 text-align: center;
1593 text-align: center;
1593 }
1594 }
1594 }
1595 }
1595 }
1596 }
1596
1597
1597 .cs_files .cs_added, .cs_files .cs_A,
1598 .cs_files .cs_added, .cs_files .cs_A,
1598 .cs_files .cs_added, .cs_files .cs_M,
1599 .cs_files .cs_added, .cs_files .cs_M,
1599 .cs_files .cs_added, .cs_files .cs_D {
1600 .cs_files .cs_added, .cs_files .cs_D {
1600 height: 16px;
1601 height: 16px;
1601 padding-right: 10px;
1602 padding-right: 10px;
1602 margin-top: 7px;
1603 margin-top: 7px;
1603 text-align: left;
1604 text-align: left;
1604 }
1605 }
1605
1606
1606 .cs_icon_td {
1607 .cs_icon_td {
1607 min-width: 16px;
1608 min-width: 16px;
1608 width: 16px;
1609 width: 16px;
1609 }
1610 }
1610
1611
1611 .pull-request-merge {
1612 .pull-request-merge {
1612 padding: 10px 0;
1613 padding: 10px 0;
1613 margin-top: 10px;
1614 margin-top: 10px;
1614 margin-bottom: 20px;
1615 margin-bottom: 20px;
1615 }
1616 }
1616
1617
1617 .pull-request-merge .pull-request-wrap {
1618 .pull-request-merge .pull-request-wrap {
1618 height: 25px;
1619 height: 25px;
1619 padding: 5px 0;
1620 padding: 5px 0;
1620 }
1621 }
1621
1622
1622 .pull-request-merge span {
1623 .pull-request-merge span {
1623 margin-right: 10px;
1624 margin-right: 10px;
1624 }
1625 }
1625 #close_pull_request {
1626 #close_pull_request {
1626 margin-right: 0px;
1627 margin-right: 0px;
1627 }
1628 }
1628
1629
1629 .empty_data {
1630 .empty_data {
1630 color: @grey4;
1631 color: @grey4;
1631 }
1632 }
1632
1633
1633 #changeset_compare_view_content {
1634 #changeset_compare_view_content {
1634 margin-bottom: @space;
1635 margin-bottom: @space;
1635 clear: both;
1636 clear: both;
1636 width: 100%;
1637 width: 100%;
1637 box-sizing: border-box;
1638 box-sizing: border-box;
1638 .border-radius(@border-radius);
1639 .border-radius(@border-radius);
1639
1640
1640 .help-block {
1641 .help-block {
1641 margin: @padding 0;
1642 margin: @padding 0;
1642 color: @text-color;
1643 color: @text-color;
1643 }
1644 }
1644
1645
1645 .empty_data {
1646 .empty_data {
1646 margin: @padding 0;
1647 margin: @padding 0;
1647 }
1648 }
1648
1649
1649 .alert {
1650 .alert {
1650 margin-bottom: @space;
1651 margin-bottom: @space;
1651 }
1652 }
1652 }
1653 }
1653
1654
1654 .table_disp {
1655 .table_disp {
1655 .status {
1656 .status {
1656 width: auto;
1657 width: auto;
1657
1658
1658 .flag_status {
1659 .flag_status {
1659 float: left;
1660 float: left;
1660 }
1661 }
1661 }
1662 }
1662 }
1663 }
1663
1664
1664 .status_box_menu {
1665 .status_box_menu {
1665 margin: 0;
1666 margin: 0;
1666 }
1667 }
1667
1668
1668 .notification-table{
1669 .notification-table{
1669 margin-bottom: @space;
1670 margin-bottom: @space;
1670 display: table;
1671 display: table;
1671 width: 100%;
1672 width: 100%;
1672
1673
1673 .container{
1674 .container{
1674 display: table-row;
1675 display: table-row;
1675
1676
1676 .notification-header{
1677 .notification-header{
1677 border-bottom: @border-thickness solid @border-default-color;
1678 border-bottom: @border-thickness solid @border-default-color;
1678 }
1679 }
1679
1680
1680 .notification-subject{
1681 .notification-subject{
1681 display: table-cell;
1682 display: table-cell;
1682 }
1683 }
1683 }
1684 }
1684 }
1685 }
1685
1686
1686 // Notifications
1687 // Notifications
1687 .notification-header{
1688 .notification-header{
1688 display: table;
1689 display: table;
1689 width: 100%;
1690 width: 100%;
1690 padding: floor(@basefontsize/2) 0;
1691 padding: floor(@basefontsize/2) 0;
1691 line-height: 1em;
1692 line-height: 1em;
1692
1693
1693 .desc, .delete-notifications, .read-notifications{
1694 .desc, .delete-notifications, .read-notifications{
1694 display: table-cell;
1695 display: table-cell;
1695 text-align: left;
1696 text-align: left;
1696 }
1697 }
1697
1698
1698 .desc{
1699 .desc{
1699 width: 1163px;
1700 width: 1163px;
1700 }
1701 }
1701
1702
1702 .delete-notifications, .read-notifications{
1703 .delete-notifications, .read-notifications{
1703 width: 35px;
1704 width: 35px;
1704 min-width: 35px; //fixes when only one button is displayed
1705 min-width: 35px; //fixes when only one button is displayed
1705 }
1706 }
1706 }
1707 }
1707
1708
1708 .notification-body {
1709 .notification-body {
1709 .markdown-block,
1710 .markdown-block,
1710 .rst-block {
1711 .rst-block {
1711 padding: @padding 0;
1712 padding: @padding 0;
1712 }
1713 }
1713
1714
1714 .notification-subject {
1715 .notification-subject {
1715 padding: @textmargin 0;
1716 padding: @textmargin 0;
1716 border-bottom: @border-thickness solid @border-default-color;
1717 border-bottom: @border-thickness solid @border-default-color;
1717 }
1718 }
1718 }
1719 }
1719
1720
1720
1721
1721 .notifications_buttons{
1722 .notifications_buttons{
1722 float: right;
1723 float: right;
1723 }
1724 }
1724
1725
1725 #notification-status{
1726 #notification-status{
1726 display: inline;
1727 display: inline;
1727 }
1728 }
1728
1729
1729 // Repositories
1730 // Repositories
1730
1731
1731 #summary.fields{
1732 #summary.fields{
1732 display: table;
1733 display: table;
1733
1734
1734 .field{
1735 .field{
1735 display: table-row;
1736 display: table-row;
1736
1737
1737 .label-summary{
1738 .label-summary{
1738 display: table-cell;
1739 display: table-cell;
1739 min-width: @label-summary-minwidth;
1740 min-width: @label-summary-minwidth;
1740 padding-top: @padding/2;
1741 padding-top: @padding/2;
1741 padding-bottom: @padding/2;
1742 padding-bottom: @padding/2;
1742 padding-right: @padding/2;
1743 padding-right: @padding/2;
1743 }
1744 }
1744
1745
1745 .input{
1746 .input{
1746 display: table-cell;
1747 display: table-cell;
1747 padding: @padding/2;
1748 padding: @padding/2;
1748
1749
1749 input{
1750 input{
1750 min-width: 29em;
1751 min-width: 29em;
1751 padding: @padding/4;
1752 padding: @padding/4;
1752 }
1753 }
1753 }
1754 }
1754 .statistics, .downloads{
1755 .statistics, .downloads{
1755 .disabled{
1756 .disabled{
1756 color: @grey4;
1757 color: @grey4;
1757 }
1758 }
1758 }
1759 }
1759 }
1760 }
1760 }
1761 }
1761
1762
1762 #summary{
1763 #summary{
1763 width: 70%;
1764 width: 70%;
1764 }
1765 }
1765
1766
1766
1767
1767 // Journal
1768 // Journal
1768 .journal.title {
1769 .journal.title {
1769 h5 {
1770 h5 {
1770 float: left;
1771 float: left;
1771 margin: 0;
1772 margin: 0;
1772 width: 70%;
1773 width: 70%;
1773 }
1774 }
1774
1775
1775 ul {
1776 ul {
1776 float: right;
1777 float: right;
1777 display: inline-block;
1778 display: inline-block;
1778 margin: 0;
1779 margin: 0;
1779 width: 30%;
1780 width: 30%;
1780 text-align: right;
1781 text-align: right;
1781
1782
1782 li {
1783 li {
1783 display: inline;
1784 display: inline;
1784 font-size: @journal-fontsize;
1785 font-size: @journal-fontsize;
1785 line-height: 1em;
1786 line-height: 1em;
1786
1787
1787 &:before { content: none; }
1788 &:before { content: none; }
1788 }
1789 }
1789 }
1790 }
1790 }
1791 }
1791
1792
1792 .filterexample {
1793 .filterexample {
1793 position: absolute;
1794 position: absolute;
1794 top: 95px;
1795 top: 95px;
1795 left: @contentpadding;
1796 left: @contentpadding;
1796 color: @rcblue;
1797 color: @rcblue;
1797 font-size: 11px;
1798 font-size: 11px;
1798 font-family: @text-regular;
1799 font-family: @text-regular;
1799 cursor: help;
1800 cursor: help;
1800
1801
1801 &:hover {
1802 &:hover {
1802 color: @rcdarkblue;
1803 color: @rcdarkblue;
1803 }
1804 }
1804
1805
1805 @media (max-width:768px) {
1806 @media (max-width:768px) {
1806 position: relative;
1807 position: relative;
1807 top: auto;
1808 top: auto;
1808 left: auto;
1809 left: auto;
1809 display: block;
1810 display: block;
1810 }
1811 }
1811 }
1812 }
1812
1813
1813
1814
1814 #journal{
1815 #journal{
1815 margin-bottom: @space;
1816 margin-bottom: @space;
1816
1817
1817 .journal_day{
1818 .journal_day{
1818 margin-bottom: @textmargin/2;
1819 margin-bottom: @textmargin/2;
1819 padding-bottom: @textmargin/2;
1820 padding-bottom: @textmargin/2;
1820 font-size: @journal-fontsize;
1821 font-size: @journal-fontsize;
1821 border-bottom: @border-thickness solid @border-default-color;
1822 border-bottom: @border-thickness solid @border-default-color;
1822 }
1823 }
1823
1824
1824 .journal_container{
1825 .journal_container{
1825 margin-bottom: @space;
1826 margin-bottom: @space;
1826
1827
1827 .journal_user{
1828 .journal_user{
1828 display: inline-block;
1829 display: inline-block;
1829 }
1830 }
1830 .journal_action_container{
1831 .journal_action_container{
1831 display: block;
1832 display: block;
1832 margin-top: @textmargin;
1833 margin-top: @textmargin;
1833
1834
1834 div{
1835 div{
1835 display: inline;
1836 display: inline;
1836 }
1837 }
1837
1838
1838 div.journal_action_params{
1839 div.journal_action_params{
1839 display: block;
1840 display: block;
1840 }
1841 }
1841
1842
1842 div.journal_repo:after{
1843 div.journal_repo:after{
1843 content: "\A";
1844 content: "\A";
1844 white-space: pre;
1845 white-space: pre;
1845 }
1846 }
1846
1847
1847 div.date{
1848 div.date{
1848 display: block;
1849 display: block;
1849 margin-bottom: @textmargin;
1850 margin-bottom: @textmargin;
1850 }
1851 }
1851 }
1852 }
1852 }
1853 }
1853 }
1854 }
1854
1855
1855 // Files
1856 // Files
1856 .edit-file-title {
1857 .edit-file-title {
1857 border-bottom: @border-thickness solid @border-default-color;
1858 border-bottom: @border-thickness solid @border-default-color;
1858
1859
1859 .breadcrumbs {
1860 .breadcrumbs {
1860 margin-bottom: 0;
1861 margin-bottom: 0;
1861 }
1862 }
1862 }
1863 }
1863
1864
1864 .edit-file-fieldset {
1865 .edit-file-fieldset {
1865 margin-top: @sidebarpadding;
1866 margin-top: @sidebarpadding;
1866
1867
1867 .fieldset {
1868 .fieldset {
1868 .left-label {
1869 .left-label {
1869 width: 13%;
1870 width: 13%;
1870 }
1871 }
1871 .right-content {
1872 .right-content {
1872 width: 87%;
1873 width: 87%;
1873 max-width: 100%;
1874 max-width: 100%;
1874 }
1875 }
1875 .filename-label {
1876 .filename-label {
1876 margin-top: 13px;
1877 margin-top: 13px;
1877 }
1878 }
1878 .commit-message-label {
1879 .commit-message-label {
1879 margin-top: 4px;
1880 margin-top: 4px;
1880 }
1881 }
1881 .file-upload-input {
1882 .file-upload-input {
1882 input {
1883 input {
1883 display: none;
1884 display: none;
1884 }
1885 }
1885 }
1886 }
1886 p {
1887 p {
1887 margin-top: 5px;
1888 margin-top: 5px;
1888 }
1889 }
1889
1890
1890 }
1891 }
1891 .custom-path-link {
1892 .custom-path-link {
1892 margin-left: 5px;
1893 margin-left: 5px;
1893 }
1894 }
1894 #commit {
1895 #commit {
1895 resize: vertical;
1896 resize: vertical;
1896 }
1897 }
1897 }
1898 }
1898
1899
1899 .delete-file-preview {
1900 .delete-file-preview {
1900 max-height: 250px;
1901 max-height: 250px;
1901 }
1902 }
1902
1903
1903 .new-file,
1904 .new-file,
1904 #filter_activate,
1905 #filter_activate,
1905 #filter_deactivate {
1906 #filter_deactivate {
1906 float: left;
1907 float: left;
1907 margin: 0 0 0 15px;
1908 margin: 0 0 0 15px;
1908 }
1909 }
1909
1910
1910 h3.files_location{
1911 h3.files_location{
1911 line-height: 2.4em;
1912 line-height: 2.4em;
1912 }
1913 }
1913
1914
1914 .browser-nav {
1915 .browser-nav {
1915 display: table;
1916 display: table;
1916 margin-bottom: @space;
1917 margin-bottom: @space;
1917
1918
1918
1919
1919 .info_box {
1920 .info_box {
1920 display: inline-table;
1921 display: inline-table;
1921 height: 2.5em;
1922 height: 2.5em;
1922
1923
1923 .browser-cur-rev, .info_box_elem {
1924 .browser-cur-rev, .info_box_elem {
1924 display: table-cell;
1925 display: table-cell;
1925 vertical-align: middle;
1926 vertical-align: middle;
1926 }
1927 }
1927
1928
1928 .info_box_elem {
1929 .info_box_elem {
1929 border-top: @border-thickness solid @rcblue;
1930 border-top: @border-thickness solid @rcblue;
1930 border-bottom: @border-thickness solid @rcblue;
1931 border-bottom: @border-thickness solid @rcblue;
1931
1932
1932 #at_rev, a {
1933 #at_rev, a {
1933 padding: 0.6em 0.9em;
1934 padding: 0.6em 0.9em;
1934 margin: 0;
1935 margin: 0;
1935 .box-shadow(none);
1936 .box-shadow(none);
1936 border: 0;
1937 border: 0;
1937 height: 12px;
1938 height: 12px;
1938 }
1939 }
1939
1940
1940 input#at_rev {
1941 input#at_rev {
1941 max-width: 50px;
1942 max-width: 50px;
1942 text-align: right;
1943 text-align: right;
1943 }
1944 }
1944
1945
1945 &.previous {
1946 &.previous {
1946 border: @border-thickness solid @rcblue;
1947 border: @border-thickness solid @rcblue;
1947 .disabled {
1948 .disabled {
1948 color: @grey4;
1949 color: @grey4;
1949 cursor: not-allowed;
1950 cursor: not-allowed;
1950 }
1951 }
1951 }
1952 }
1952
1953
1953 &.next {
1954 &.next {
1954 border: @border-thickness solid @rcblue;
1955 border: @border-thickness solid @rcblue;
1955 .disabled {
1956 .disabled {
1956 color: @grey4;
1957 color: @grey4;
1957 cursor: not-allowed;
1958 cursor: not-allowed;
1958 }
1959 }
1959 }
1960 }
1960 }
1961 }
1961
1962
1962 .browser-cur-rev {
1963 .browser-cur-rev {
1963
1964
1964 span{
1965 span{
1965 margin: 0;
1966 margin: 0;
1966 color: @rcblue;
1967 color: @rcblue;
1967 height: 12px;
1968 height: 12px;
1968 display: inline-block;
1969 display: inline-block;
1969 padding: 0.7em 1em ;
1970 padding: 0.7em 1em ;
1970 border: @border-thickness solid @rcblue;
1971 border: @border-thickness solid @rcblue;
1971 margin-right: @padding;
1972 margin-right: @padding;
1972 }
1973 }
1973 }
1974 }
1974 }
1975 }
1975
1976
1976 .search_activate {
1977 .search_activate {
1977 display: table-cell;
1978 display: table-cell;
1978 vertical-align: middle;
1979 vertical-align: middle;
1979
1980
1980 input, label{
1981 input, label{
1981 margin: 0;
1982 margin: 0;
1982 padding: 0;
1983 padding: 0;
1983 }
1984 }
1984
1985
1985 input{
1986 input{
1986 margin-left: @textmargin;
1987 margin-left: @textmargin;
1987 }
1988 }
1988
1989
1989 }
1990 }
1990 }
1991 }
1991
1992
1992 .browser-cur-rev{
1993 .browser-cur-rev{
1993 margin-bottom: @textmargin;
1994 margin-bottom: @textmargin;
1994 }
1995 }
1995
1996
1996 #node_filter_box_loading{
1997 #node_filter_box_loading{
1997 .info_text;
1998 .info_text;
1998 }
1999 }
1999
2000
2000 .browser-search {
2001 .browser-search {
2001 margin: -25px 0px 5px 0px;
2002 margin: -25px 0px 5px 0px;
2002 }
2003 }
2003
2004
2004 .node-filter {
2005 .node-filter {
2005 font-size: @repo-title-fontsize;
2006 font-size: @repo-title-fontsize;
2006 padding: 4px 0px 0px 0px;
2007 padding: 4px 0px 0px 0px;
2007
2008
2008 .node-filter-path {
2009 .node-filter-path {
2009 float: left;
2010 float: left;
2010 color: @grey4;
2011 color: @grey4;
2011 }
2012 }
2012 .node-filter-input {
2013 .node-filter-input {
2013 float: left;
2014 float: left;
2014 margin: -2px 0px 0px 2px;
2015 margin: -2px 0px 0px 2px;
2015 input {
2016 input {
2016 padding: 2px;
2017 padding: 2px;
2017 border: none;
2018 border: none;
2018 font-size: @repo-title-fontsize;
2019 font-size: @repo-title-fontsize;
2019 }
2020 }
2020 }
2021 }
2021 }
2022 }
2022
2023
2023
2024
2024 .browser-result{
2025 .browser-result{
2025 td a{
2026 td a{
2026 margin-left: 0.5em;
2027 margin-left: 0.5em;
2027 display: inline-block;
2028 display: inline-block;
2028
2029
2029 em{
2030 em{
2030 font-family: @text-bold;
2031 font-family: @text-bold;
2031 }
2032 }
2032 }
2033 }
2033 }
2034 }
2034
2035
2035 .browser-highlight{
2036 .browser-highlight{
2036 background-color: @grey5-alpha;
2037 background-color: @grey5-alpha;
2037 }
2038 }
2038
2039
2039
2040
2040 // Search
2041 // Search
2041
2042
2042 .search-form{
2043 .search-form{
2043 #q {
2044 #q {
2044 width: @search-form-width;
2045 width: @search-form-width;
2045 }
2046 }
2046 .fields{
2047 .fields{
2047 margin: 0 0 @space;
2048 margin: 0 0 @space;
2048 }
2049 }
2049
2050
2050 label{
2051 label{
2051 display: inline-block;
2052 display: inline-block;
2052 margin-right: @textmargin;
2053 margin-right: @textmargin;
2053 padding-top: 0.25em;
2054 padding-top: 0.25em;
2054 }
2055 }
2055
2056
2056
2057
2057 .results{
2058 .results{
2058 clear: both;
2059 clear: both;
2059 margin: 0 0 @padding;
2060 margin: 0 0 @padding;
2060 }
2061 }
2061 }
2062 }
2062
2063
2063 div.search-feedback-items {
2064 div.search-feedback-items {
2064 display: inline-block;
2065 display: inline-block;
2065 padding:0px 0px 0px 96px;
2066 padding:0px 0px 0px 96px;
2066 }
2067 }
2067
2068
2068 div.search-code-body {
2069 div.search-code-body {
2069 background-color: #ffffff; padding: 5px 0 5px 10px;
2070 background-color: #ffffff; padding: 5px 0 5px 10px;
2070 pre {
2071 pre {
2071 .match { background-color: #faffa6;}
2072 .match { background-color: #faffa6;}
2072 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2073 .break { display: block; width: 100%; background-color: #DDE7EF; color: #747474; }
2073 }
2074 }
2074 }
2075 }
2075
2076
2076 .expand_commit.search {
2077 .expand_commit.search {
2077 .show_more.open {
2078 .show_more.open {
2078 height: auto;
2079 height: auto;
2079 max-height: none;
2080 max-height: none;
2080 }
2081 }
2081 }
2082 }
2082
2083
2083 .search-results {
2084 .search-results {
2084
2085
2085 h2 {
2086 h2 {
2086 margin-bottom: 0;
2087 margin-bottom: 0;
2087 }
2088 }
2088 .codeblock {
2089 .codeblock {
2089 border: none;
2090 border: none;
2090 background: transparent;
2091 background: transparent;
2091 }
2092 }
2092
2093
2093 .codeblock-header {
2094 .codeblock-header {
2094 border: none;
2095 border: none;
2095 background: transparent;
2096 background: transparent;
2096 }
2097 }
2097
2098
2098 .code-body {
2099 .code-body {
2099 border: @border-thickness solid @border-default-color;
2100 border: @border-thickness solid @border-default-color;
2100 .border-radius(@border-radius);
2101 .border-radius(@border-radius);
2101 }
2102 }
2102
2103
2103 .td-commit {
2104 .td-commit {
2104 &:extend(pre);
2105 &:extend(pre);
2105 border-bottom: @border-thickness solid @border-default-color;
2106 border-bottom: @border-thickness solid @border-default-color;
2106 }
2107 }
2107
2108
2108 .message {
2109 .message {
2109 height: auto;
2110 height: auto;
2110 max-width: 350px;
2111 max-width: 350px;
2111 white-space: normal;
2112 white-space: normal;
2112 text-overflow: initial;
2113 text-overflow: initial;
2113 overflow: visible;
2114 overflow: visible;
2114
2115
2115 .match { background-color: #faffa6;}
2116 .match { background-color: #faffa6;}
2116 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2117 .break { background-color: #DDE7EF; width: 100%; color: #747474; display: block; }
2117 }
2118 }
2118
2119
2119 }
2120 }
2120
2121
2121 table.rctable td.td-search-results div {
2122 table.rctable td.td-search-results div {
2122 max-width: 100%;
2123 max-width: 100%;
2123 }
2124 }
2124
2125
2125 #tip-box, .tip-box{
2126 #tip-box, .tip-box{
2126 padding: @menupadding/2;
2127 padding: @menupadding/2;
2127 display: block;
2128 display: block;
2128 border: @border-thickness solid @border-highlight-color;
2129 border: @border-thickness solid @border-highlight-color;
2129 .border-radius(@border-radius);
2130 .border-radius(@border-radius);
2130 background-color: white;
2131 background-color: white;
2131 z-index: 99;
2132 z-index: 99;
2132 white-space: pre-wrap;
2133 white-space: pre-wrap;
2133 }
2134 }
2134
2135
2135 #linktt {
2136 #linktt {
2136 width: 79px;
2137 width: 79px;
2137 }
2138 }
2138
2139
2139 #help_kb .modal-content{
2140 #help_kb .modal-content{
2140 max-width: 750px;
2141 max-width: 750px;
2141 margin: 10% auto;
2142 margin: 10% auto;
2142
2143
2143 table{
2144 table{
2144 td,th{
2145 td,th{
2145 border-bottom: none;
2146 border-bottom: none;
2146 line-height: 2.5em;
2147 line-height: 2.5em;
2147 }
2148 }
2148 th{
2149 th{
2149 padding-bottom: @textmargin/2;
2150 padding-bottom: @textmargin/2;
2150 }
2151 }
2151 td.keys{
2152 td.keys{
2152 text-align: center;
2153 text-align: center;
2153 }
2154 }
2154 }
2155 }
2155
2156
2156 .block-left{
2157 .block-left{
2157 width: 45%;
2158 width: 45%;
2158 margin-right: 5%;
2159 margin-right: 5%;
2159 }
2160 }
2160 .modal-footer{
2161 .modal-footer{
2161 clear: both;
2162 clear: both;
2162 }
2163 }
2163 .key.tag{
2164 .key.tag{
2164 padding: 0.5em;
2165 padding: 0.5em;
2165 background-color: @rcblue;
2166 background-color: @rcblue;
2166 color: white;
2167 color: white;
2167 border-color: @rcblue;
2168 border-color: @rcblue;
2168 .box-shadow(none);
2169 .box-shadow(none);
2169 }
2170 }
2170 }
2171 }
2171
2172
2172
2173
2173
2174
2174 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2175 //--- IMPORTS FOR REFACTORED STYLES ------------------//
2175
2176
2176 @import 'statistics-graph';
2177 @import 'statistics-graph';
2177 @import 'tables';
2178 @import 'tables';
2178 @import 'forms';
2179 @import 'forms';
2179 @import 'diff';
2180 @import 'diff';
2180 @import 'summary';
2181 @import 'summary';
2181 @import 'navigation';
2182 @import 'navigation';
2182
2183
2183 //--- SHOW/HIDE SECTIONS --//
2184 //--- SHOW/HIDE SECTIONS --//
2184
2185
2185 .btn-collapse {
2186 .btn-collapse {
2186 float: right;
2187 float: right;
2187 text-align: right;
2188 text-align: right;
2188 font-family: @text-light;
2189 font-family: @text-light;
2189 font-size: @basefontsize;
2190 font-size: @basefontsize;
2190 cursor: pointer;
2191 cursor: pointer;
2191 border: none;
2192 border: none;
2192 color: @rcblue;
2193 color: @rcblue;
2193 }
2194 }
2194
2195
2195 table.rctable,
2196 table.rctable,
2196 table.dataTable {
2197 table.dataTable {
2197 .btn-collapse {
2198 .btn-collapse {
2198 float: right;
2199 float: right;
2199 text-align: right;
2200 text-align: right;
2200 }
2201 }
2201 }
2202 }
2202
2203
2203
2204
2204 // TODO: johbo: Fix for IE10, this avoids that we see a border
2205 // TODO: johbo: Fix for IE10, this avoids that we see a border
2205 // and padding around checkboxes and radio boxes. Move to the right place,
2206 // and padding around checkboxes and radio boxes. Move to the right place,
2206 // or better: Remove this once we did the form refactoring.
2207 // or better: Remove this once we did the form refactoring.
2207 input[type=checkbox],
2208 input[type=checkbox],
2208 input[type=radio] {
2209 input[type=radio] {
2209 padding: 0;
2210 padding: 0;
2210 border: none;
2211 border: none;
2211 }
2212 }
2212
2213
2213 .toggle-ajax-spinner{
2214 .toggle-ajax-spinner{
2214 height: 16px;
2215 height: 16px;
2215 width: 16px;
2216 width: 16px;
2216 }
2217 }
@@ -1,264 +1,265 b''
1 // summary.less
1 // summary.less
2 // For use in RhodeCode applications;
2 // For use in RhodeCode applications;
3 // Used for headers and file detail summary screens.
3 // Used for headers and file detail summary screens.
4
4
5 .summary {
5 .summary {
6 float: left;
6 float: left;
7 position: relative;
7 position: relative;
8 width: 100%;
8 width: 100%;
9 margin: 0;
9 margin: 0;
10 padding: 0;
10 padding: 0;
11
11
12 .summary-detail-header {
12 .summary-detail-header {
13 float: left;
13 float: left;
14 display: block;
14 display: block;
15 width: 100%;
15 width: 100%;
16 margin-bottom: @textmargin;
16 margin-bottom: @textmargin;
17 padding: 0 0 .5em 0;
17 padding: 0 0 .5em 0;
18 border-bottom: @border-thickness solid @border-default-color;
18 border-bottom: @border-thickness solid @border-default-color;
19
19
20 .breadcrumbs {
20 .breadcrumbs {
21 float: left;
21 float: left;
22 display: inline;
22 display: inline;
23 margin: 0;
23 margin: 0;
24 padding: 0;
24 padding: 0;
25 }
25 }
26 h4 {
26 h4 {
27 float: left;
27 float: left;
28 margin: 0 1em 0 0;
28 margin: 0 1em 0 0;
29 padding: 0;
29 padding: 0;
30 line-height: 1.2em;
30 line-height: 1.2em;
31 font-size: @basefontsize;
31 font-size: @basefontsize;
32 }
32 }
33
33
34 .action_link {
34 .action_link {
35 float: right;
35 float: right;
36 }
36 }
37
37
38 .new-file {
38 .new-file {
39 float: right;
39 float: right;
40 margin-top: -1.5em;
40 margin-top: -1.5em;
41 }
41 }
42 }
42 }
43
43
44 .summary-detail {
44 .summary-detail {
45 float: left;
45 float: left;
46 position: relative;
46 position: relative;
47 width: 73%;
47 width: 73%;
48 margin: 0 3% @space 0;
48 margin: 0 3% @space 0;
49 padding: 0;
49 padding: 0;
50
50
51 .file_diff_buttons {
51 .file_diff_buttons {
52 margin-top: @space;
52 margin-top: @space;
53 }
53 }
54
54
55 // commit message
55 // commit message
56 .commit {
56 .commit {
57 white-space: pre-wrap;
57 white-space: pre-wrap;
58 }
58 }
59
59
60 #clone_url,
60 #clone_url,
61 #clone_url_id {
61 #clone_url_id {
62 min-width: 29em;
62 min-width: 29em;
63 padding: @padding/4;
63 padding: @padding/4;
64 }
64 }
65
65
66 &.directory {
66 &.directory {
67 margin-bottom: 0;
67 margin-bottom: 0;
68 }
68 }
69
69
70 .desc {
70 .desc {
71 white-space: pre-wrap;
71 white-space: pre-wrap;
72 }
72 }
73 .disabled {
73 .disabled {
74 opacity: .5;
74 opacity: .5;
75 cursor: inherit;
75 }
76 }
76 .help-block {
77 .help-block {
77 color: inherit;
78 color: inherit;
78 margin: 0;
79 margin: 0;
79 }
80 }
80 }
81 }
81
82
82 .sidebar-right {
83 .sidebar-right {
83 float: left;
84 float: left;
84 width: 24%;
85 width: 24%;
85 margin: 0;
86 margin: 0;
86 padding: 0;
87 padding: 0;
87
88
88 ul {
89 ul {
89 margin-left: 0;
90 margin-left: 0;
90 padding-left: 0;
91 padding-left: 0;
91
92
92 li {
93 li {
93
94
94 &:before {
95 &:before {
95 content: none;
96 content: none;
96 width: 0;
97 width: 0;
97 }
98 }
98 }
99 }
99 }
100 }
100 }
101 }
101
102
102 #clone_by_name, #clone_by_id{
103 #clone_by_name, #clone_by_id{
103 display: inline-block;
104 display: inline-block;
104 margin-left: @padding;
105 margin-left: @padding;
105 }
106 }
106
107
107 .codeblock {
108 .codeblock {
108 border: none;
109 border: none;
109 background-color: transparent;
110 background-color: transparent;
110 }
111 }
111
112
112 .code-body {
113 .code-body {
113 border: @border-thickness solid @border-default-color;
114 border: @border-thickness solid @border-default-color;
114 .border-radius(@border-radius);
115 .border-radius(@border-radius);
115 }
116 }
116 }
117 }
117
118
118 // this is used outside of just the summary
119 // this is used outside of just the summary
119 .fieldset, // similar to form fieldset
120 .fieldset, // similar to form fieldset
120 .summary .sidebar-right-content { // these have to match
121 .summary .sidebar-right-content { // these have to match
121 clear: both;
122 clear: both;
122 float: left;
123 float: left;
123 position: relative;
124 position: relative;
124 display:block;
125 display:block;
125 width: 100%;
126 width: 100%;
126 min-height: 1em;
127 min-height: 1em;
127 margin-bottom: @textmargin;
128 margin-bottom: @textmargin;
128 padding: 0;
129 padding: 0;
129 line-height: 1.2em;
130 line-height: 1.2em;
130
131
131 &:after { // clearfix
132 &:after { // clearfix
132 content: "";
133 content: "";
133 clear: both;
134 clear: both;
134 width: 100%;
135 width: 100%;
135 height: 1em;
136 height: 1em;
136 }
137 }
137 }
138 }
138
139
139 .summary .sidebar-right-content {
140 .summary .sidebar-right-content {
140 margin-bottom: @space;
141 margin-bottom: @space;
141
142
142 .rc-user {
143 .rc-user {
143 min-width: 0;
144 min-width: 0;
144 }
145 }
145 }
146 }
146
147
147 .fieldset {
148 .fieldset {
148
149
149 .left-label { // similar to form legend
150 .left-label { // similar to form legend
150 float: left;
151 float: left;
151 display: block;
152 display: block;
152 width: 25%;
153 width: 25%;
153 margin: 0;
154 margin: 0;
154 padding: 0;
155 padding: 0;
155 font-family: @text-semibold;
156 font-family: @text-semibold;
156 }
157 }
157
158
158 .right-content { // similar to form fields
159 .right-content { // similar to form fields
159 float: left;
160 float: left;
160 display: block;
161 display: block;
161 width: 75%;
162 width: 75%;
162 margin: 0 0 0 -15%;
163 margin: 0 0 0 -15%;
163 padding: 0 0 0 15%;
164 padding: 0 0 0 15%;
164
165
165 .truncate-wrap,
166 .truncate-wrap,
166 .truncate {
167 .truncate {
167 max-width: 100%;
168 max-width: 100%;
168 width: 100%;
169 width: 100%;
169 }
170 }
170
171
171 .commit-long {
172 .commit-long {
172 overflow-x: auto;
173 overflow-x: auto;
173 }
174 }
174 }
175 }
175 .commit.truncate-wrap {
176 .commit.truncate-wrap {
176 overflow:hidden;
177 overflow:hidden;
177 text-overflow: ellipsis;
178 text-overflow: ellipsis;
178 }
179 }
179 }
180 }
180
181
181 // expand commit message
182 // expand commit message
182 #message_expand {
183 #message_expand {
183 clear: both;
184 clear: both;
184 display: block;
185 display: block;
185 color: @rcblue;
186 color: @rcblue;
186 cursor: pointer;
187 cursor: pointer;
187 }
188 }
188
189
189 #trimmed_message_box {
190 #trimmed_message_box {
190 max-height: floor(2 * @basefontsize * 1.2); // 2 lines * line-height
191 max-height: floor(2 * @basefontsize * 1.2); // 2 lines * line-height
191 overflow: hidden;
192 overflow: hidden;
192 }
193 }
193
194
194 // show/hide comments button
195 // show/hide comments button
195 .show-inline-comments {
196 .show-inline-comments {
196 display: inline;
197 display: inline;
197 cursor: pointer;
198 cursor: pointer;
198
199
199 .comments-show { display: inline; }
200 .comments-show { display: inline; }
200 .comments-hide { display: none; }
201 .comments-hide { display: none; }
201
202
202 &.comments-visible {
203 &.comments-visible {
203 .comments-show { display: none; }
204 .comments-show { display: none; }
204 .comments-hide { display: inline; }
205 .comments-hide { display: inline; }
205 }
206 }
206 }
207 }
207
208
208 // Quick Start section
209 // Quick Start section
209 .quick_start {
210 .quick_start {
210 float: left;
211 float: left;
211 display: block;
212 display: block;
212 position: relative;
213 position: relative;
213
214
214 // adds some space to make copy and paste easier
215 // adds some space to make copy and paste easier
215 .left-label,
216 .left-label,
216 .right-content {
217 .right-content {
217 line-height: 1.6em;
218 line-height: 1.6em;
218 }
219 }
219 }
220 }
220
221
221 .submodule {
222 .submodule {
222 .summary-detail {
223 .summary-detail {
223 width: 100%;
224 width: 100%;
224
225
225 .btn-collapse {
226 .btn-collapse {
226 display: none;
227 display: none;
227 }
228 }
228 }
229 }
229 }
230 }
230
231
231 .codeblock-header {
232 .codeblock-header {
232 float: left;
233 float: left;
233 display: block;
234 display: block;
234 width: 100%;
235 width: 100%;
235 margin: 0;
236 margin: 0;
236 padding: @space 0 @padding 0;
237 padding: @space 0 @padding 0;
237 border-top: @border-thickness solid @border-default-color;
238 border-top: @border-thickness solid @border-default-color;
238
239
239 .stats {
240 .stats {
240 float: left;
241 float: left;
241 width: 50%;
242 width: 50%;
242 }
243 }
243
244
244 .buttons {
245 .buttons {
245 float: right;
246 float: right;
246 width: 50%;
247 width: 50%;
247 text-align: right;
248 text-align: right;
248 color: @grey4;
249 color: @grey4;
249 }
250 }
250 }
251 }
251
252
252 #summary-menu-stats {
253 #summary-menu-stats {
253
254
254 .stats-bullet {
255 .stats-bullet {
255 color: @grey3;
256 color: @grey3;
256 min-width: 3em;
257 min-width: 3em;
257 }
258 }
258
259
259 .repo-size {
260 .repo-size {
260 margin-bottom: .5em;
261 margin-bottom: .5em;
261 }
262 }
262
263
263 }
264 }
264
265
@@ -1,174 +1,184 b''
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
1 // # Copyright (C) 2010-2016 RhodeCode GmbH
2 // #
2 // #
3 // # This program is free software: you can redistribute it and/or modify
3 // # This program is free software: you can redistribute it and/or modify
4 // # it under the terms of the GNU Affero General Public License, version 3
4 // # it under the terms of the GNU Affero General Public License, version 3
5 // # (only), as published by the Free Software Foundation.
5 // # (only), as published by the Free Software Foundation.
6 // #
6 // #
7 // # This program is distributed in the hope that it will be useful,
7 // # This program is distributed in the hope that it will be useful,
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // # GNU General Public License for more details.
10 // # GNU General Public License for more details.
11 // #
11 // #
12 // # You should have received a copy of the GNU Affero General Public License
12 // # You should have received a copy of the GNU Affero General Public License
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
13 // # along with this program. If not, see <http://www.gnu.org/licenses/>.
14 // #
14 // #
15 // # This program is dual-licensed. If you wish to learn more about the
15 // # This program is dual-licensed. If you wish to learn more about the
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
16 // # RhodeCode Enterprise Edition, including its added features, Support services,
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
17 // # and proprietary license terms, please see https://rhodecode.com/licenses/
18
18
19 /**
19 /**
20 * INJECT .format function into String
20 * INJECT .format function into String
21 * Usage: "My name is {0} {1}".format("Johny","Bravo")
21 * Usage: "My name is {0} {1}".format("Johny","Bravo")
22 * Return "My name is Johny Bravo"
22 * Return "My name is Johny Bravo"
23 * Inspired by https://gist.github.com/1049426
23 * Inspired by https://gist.github.com/1049426
24 */
24 */
25 String.prototype.format = function() {
25 String.prototype.format = function() {
26
26
27 function format() {
27 function format() {
28 var str = this;
28 var str = this;
29 var len = arguments.length+1;
29 var len = arguments.length+1;
30 var safe = undefined;
30 var safe = undefined;
31 var arg = undefined;
31 var arg = undefined;
32
32
33 // For each {0} {1} {n...} replace with the argument in that position. If
33 // For each {0} {1} {n...} replace with the argument in that position. If
34 // the argument is an object or an array it will be stringified to JSON.
34 // the argument is an object or an array it will be stringified to JSON.
35 for (var i=0; i < len; arg = arguments[i++]) {
35 for (var i=0; i < len; arg = arguments[i++]) {
36 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
36 safe = typeof arg === 'object' ? JSON.stringify(arg) : arg;
37 str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
37 str = str.replace(new RegExp('\\{'+(i-1)+'\\}', 'g'), safe);
38 }
38 }
39 return str;
39 return str;
40 }
40 }
41
41
42 // Save a reference of what may already exist under the property native.
42 // Save a reference of what may already exist under the property native.
43 // Allows for doing something like: if("".format.native) { /* use native */ }
43 // Allows for doing something like: if("".format.native) { /* use native */ }
44 format.native = String.prototype.format;
44 format.native = String.prototype.format;
45
45
46 // Replace the prototype property
46 // Replace the prototype property
47 return format;
47 return format;
48 }();
48 }();
49
49
50 String.prototype.strip = function(char) {
50 String.prototype.strip = function(char) {
51 if(char === undefined){
51 if(char === undefined){
52 char = '\\s';
52 char = '\\s';
53 }
53 }
54 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
54 return this.replace(new RegExp('^'+char+'+|'+char+'+$','g'), '');
55 };
55 };
56
56
57 String.prototype.lstrip = function(char) {
57 String.prototype.lstrip = function(char) {
58 if(char === undefined){
58 if(char === undefined){
59 char = '\\s';
59 char = '\\s';
60 }
60 }
61 return this.replace(new RegExp('^'+char+'+'),'');
61 return this.replace(new RegExp('^'+char+'+'),'');
62 };
62 };
63
63
64 String.prototype.rstrip = function(char) {
64 String.prototype.rstrip = function(char) {
65 if(char === undefined){
65 if(char === undefined){
66 char = '\\s';
66 char = '\\s';
67 }
67 }
68 return this.replace(new RegExp(''+char+'+$'),'');
68 return this.replace(new RegExp(''+char+'+$'),'');
69 };
69 };
70
70
71 String.prototype.capitalizeFirstLetter = function() {
71 String.prototype.capitalizeFirstLetter = function() {
72 return this.charAt(0).toUpperCase() + this.slice(1);
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 * Splits remainder
87 * Splits remainder
78 *
88 *
79 * @param input
89 * @param input
80 */
90 */
81 function splitDelimitedHash(input){
91 function splitDelimitedHash(input){
82 var splitIx = input.indexOf('/?/');
92 var splitIx = input.indexOf('/?/');
83 if (splitIx !== -1){
93 if (splitIx !== -1){
84 var loc = input.slice(0, splitIx);
94 var loc = input.slice(0, splitIx);
85 var remainder = input.slice(splitIx + 2);
95 var remainder = input.slice(splitIx + 2);
86 }
96 }
87 else{
97 else{
88 var loc = input;
98 var loc = input;
89 var remainder = null;
99 var remainder = null;
90 }
100 }
91 //fixes for some urls generated incorrectly
101 //fixes for some urls generated incorrectly
92 var result = loc.match('#+(.*)');
102 var result = loc.match('#+(.*)');
93 if (result !== null){
103 if (result !== null){
94 loc = '#' + result[1];
104 loc = '#' + result[1];
95 }
105 }
96 return {loc:loc, remainder: remainder}
106 return {loc:loc, remainder: remainder}
97 }
107 }
98
108
99 /**
109 /**
100 * Escape html characters in string
110 * Escape html characters in string
101 */
111 */
102 var entityMap = {
112 var entityMap = {
103 "&": "&amp;",
113 "&": "&amp;",
104 "<": "&lt;",
114 "<": "&lt;",
105 ">": "&gt;",
115 ">": "&gt;",
106 '"': '&quot;',
116 '"': '&quot;',
107 "'": '&#39;',
117 "'": '&#39;',
108 "/": '&#x2F;'
118 "/": '&#x2F;'
109 };
119 };
110
120
111 function escapeHtml(string) {
121 function escapeHtml(string) {
112 return String(string).replace(/[&<>"'\/]/g, function (s) {
122 return String(string).replace(/[&<>"'\/]/g, function (s) {
113 return entityMap[s];
123 return entityMap[s];
114 });
124 });
115 }
125 }
116
126
117 /** encode/decode html special chars**/
127 /** encode/decode html special chars**/
118 var htmlEnDeCode = (function() {
128 var htmlEnDeCode = (function() {
119 var charToEntityRegex,
129 var charToEntityRegex,
120 entityToCharRegex,
130 entityToCharRegex,
121 charToEntity,
131 charToEntity,
122 entityToChar;
132 entityToChar;
123
133
124 function resetCharacterEntities() {
134 function resetCharacterEntities() {
125 charToEntity = {};
135 charToEntity = {};
126 entityToChar = {};
136 entityToChar = {};
127 // add the default set
137 // add the default set
128 addCharacterEntities({
138 addCharacterEntities({
129 '&amp;' : '&',
139 '&amp;' : '&',
130 '&gt;' : '>',
140 '&gt;' : '>',
131 '&lt;' : '<',
141 '&lt;' : '<',
132 '&quot;' : '"',
142 '&quot;' : '"',
133 '&#39;' : "'"
143 '&#39;' : "'"
134 });
144 });
135 }
145 }
136
146
137 function addCharacterEntities(newEntities) {
147 function addCharacterEntities(newEntities) {
138 var charKeys = [],
148 var charKeys = [],
139 entityKeys = [],
149 entityKeys = [],
140 key, echar;
150 key, echar;
141 for (key in newEntities) {
151 for (key in newEntities) {
142 echar = newEntities[key];
152 echar = newEntities[key];
143 entityToChar[key] = echar;
153 entityToChar[key] = echar;
144 charToEntity[echar] = key;
154 charToEntity[echar] = key;
145 charKeys.push(echar);
155 charKeys.push(echar);
146 entityKeys.push(key);
156 entityKeys.push(key);
147 }
157 }
148 charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
158 charToEntityRegex = new RegExp('(' + charKeys.join('|') + ')', 'g');
149 entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
159 entityToCharRegex = new RegExp('(' + entityKeys.join('|') + '|&#[0-9]{1,5};' + ')', 'g');
150 }
160 }
151
161
152 function htmlEncode(value){
162 function htmlEncode(value){
153 var htmlEncodeReplaceFn = function(match, capture) {
163 var htmlEncodeReplaceFn = function(match, capture) {
154 return charToEntity[capture];
164 return charToEntity[capture];
155 };
165 };
156
166
157 return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
167 return (!value) ? value : String(value).replace(charToEntityRegex, htmlEncodeReplaceFn);
158 }
168 }
159
169
160 function htmlDecode(value) {
170 function htmlDecode(value) {
161 var htmlDecodeReplaceFn = function(match, capture) {
171 var htmlDecodeReplaceFn = function(match, capture) {
162 return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
172 return (capture in entityToChar) ? entityToChar[capture] : String.fromCharCode(parseInt(capture.substr(2), 10));
163 };
173 };
164
174
165 return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
175 return (!value) ? value : String(value).replace(entityToCharRegex, htmlDecodeReplaceFn);
166 }
176 }
167
177
168 resetCharacterEntities();
178 resetCharacterEntities();
169
179
170 return {
180 return {
171 htmlEncode: htmlEncode,
181 htmlEncode: htmlEncode,
172 htmlDecode: htmlDecode
182 htmlDecode: htmlDecode
173 };
183 };
174 })();
184 })();
@@ -1,314 +1,314 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 <%inherit file="/base/base.html"/>
3 <%inherit file="/base/base.html"/>
4 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
4 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
5
5
6 <%def name="title()">
6 <%def name="title()">
7 ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)}
7 ${_('%s Commit') % c.repo_name} - ${h.show_id(c.commit)}
8 %if c.rhodecode_name:
8 %if c.rhodecode_name:
9 &middot; ${h.branding(c.rhodecode_name)}
9 &middot; ${h.branding(c.rhodecode_name)}
10 %endif
10 %endif
11 </%def>
11 </%def>
12
12
13 <%def name="menu_bar_nav()">
13 <%def name="menu_bar_nav()">
14 ${self.menu_items(active='repositories')}
14 ${self.menu_items(active='repositories')}
15 </%def>
15 </%def>
16
16
17 <%def name="menu_bar_subnav()">
17 <%def name="menu_bar_subnav()">
18 ${self.repo_menu(active='changelog')}
18 ${self.repo_menu(active='changelog')}
19 </%def>
19 </%def>
20
20
21 <%def name="main()">
21 <%def name="main()">
22 <script>
22 <script>
23 // TODO: marcink switch this to pyroutes
23 // TODO: marcink switch this to pyroutes
24 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
24 AJAX_COMMENT_DELETE_URL = "${url('changeset_comment_delete',repo_name=c.repo_name,comment_id='__COMMENT_ID__')}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
25 templateContext.commit_data.commit_id = "${c.commit.raw_id}";
26 </script>
26 </script>
27 <div class="box">
27 <div class="box">
28 <div class="title">
28 <div class="title">
29 ${self.repo_page_title(c.rhodecode_db_repo)}
29 ${self.repo_page_title(c.rhodecode_db_repo)}
30 </div>
30 </div>
31
31
32 <div id="changeset_compare_view_content" class="summary changeset">
32 <div id="changeset_compare_view_content" class="summary changeset">
33 <div class="summary-detail">
33 <div class="summary-detail">
34 <div class="summary-detail-header">
34 <div class="summary-detail-header">
35 <span class="breadcrumbs files_location">
35 <span class="breadcrumbs files_location">
36 <h4>${_('Commit')}
36 <h4>${_('Commit')}
37 <code>
37 <code>
38 ${h.show_id(c.commit)}
38 ${h.show_id(c.commit)}
39 </code>
39 </code>
40 </h4>
40 </h4>
41 </span>
41 </span>
42 <span id="parent_link">
42 <span id="parent_link">
43 <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a>
43 <a href="#" title="${_('Parent Commit')}">${_('Parent')}</a>
44 </span>
44 </span>
45 |
45 |
46 <span id="child_link">
46 <span id="child_link">
47 <a href="#" title="${_('Child Commit')}">${_('Child')}</a>
47 <a href="#" title="${_('Child Commit')}">${_('Child')}</a>
48 </span>
48 </span>
49 </div>
49 </div>
50
50
51 <div class="fieldset">
51 <div class="fieldset">
52 <div class="left-label">
52 <div class="left-label">
53 ${_('Description')}:
53 ${_('Description')}:
54 </div>
54 </div>
55 <div class="right-content">
55 <div class="right-content">
56 <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
56 <div id="trimmed_message_box" class="commit">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
57 <div id="message_expand" style="display:none;">
57 <div id="message_expand" style="display:none;">
58 ${_('Expand')}
58 ${_('Expand')}
59 </div>
59 </div>
60 </div>
60 </div>
61 </div>
61 </div>
62
62
63 %if c.statuses:
63 %if c.statuses:
64 <div class="fieldset">
64 <div class="fieldset">
65 <div class="left-label">
65 <div class="left-label">
66 ${_('Commit status')}:
66 ${_('Commit status')}:
67 </div>
67 </div>
68 <div class="right-content">
68 <div class="right-content">
69 <div class="changeset-status-ico">
69 <div class="changeset-status-ico">
70 <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div>
70 <div class="${'flag_status %s' % c.statuses[0]} pull-left"></div>
71 </div>
71 </div>
72 <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div>
72 <div title="${_('Commit status')}" class="changeset-status-lbl">[${h.commit_status_lbl(c.statuses[0])}]</div>
73 </div>
73 </div>
74 </div>
74 </div>
75 %endif
75 %endif
76
76
77 <div class="fieldset">
77 <div class="fieldset">
78 <div class="left-label">
78 <div class="left-label">
79 ${_('References')}:
79 ${_('References')}:
80 </div>
80 </div>
81 <div class="right-content">
81 <div class="right-content">
82 <div class="tags">
82 <div class="tags">
83
83
84 %if c.commit.merge:
84 %if c.commit.merge:
85 <span class="mergetag tag">
85 <span class="mergetag tag">
86 <i class="icon-merge"></i>${_('merge')}
86 <i class="icon-merge"></i>${_('merge')}
87 </span>
87 </span>
88 %endif
88 %endif
89
89
90 %if h.is_hg(c.rhodecode_repo):
90 %if h.is_hg(c.rhodecode_repo):
91 %for book in c.commit.bookmarks:
91 %for book in c.commit.bookmarks:
92 <span class="booktag tag" title="${_('Bookmark %s') % book}">
92 <span class="booktag tag" title="${_('Bookmark %s') % book}">
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>
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 </span>
94 </span>
95 %endfor
95 %endfor
96 %endif
96 %endif
97
97
98 %for tag in c.commit.tags:
98 %for tag in c.commit.tags:
99 <span class="tagtag tag" title="${_('Tag %s') % tag}">
99 <span class="tagtag tag" title="${_('Tag %s') % tag}">
100 <a href="${h.url('files_home',repo_name=c.repo_name,revision=c.commit.raw_id)}"><i class="icon-tag"></i>${tag}</a>
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 </span>
101 </span>
102 %endfor
102 %endfor
103
103
104 %if c.commit.branch:
104 %if c.commit.branch:
105 <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}">
105 <span class="branchtag tag" title="${_('Branch %s') % c.commit.branch}">
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>
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 </span>
107 </span>
108 %endif
108 %endif
109 </div>
109 </div>
110 </div>
110 </div>
111 </div>
111 </div>
112
112
113 <div class="fieldset">
113 <div class="fieldset">
114 <div class="left-label">
114 <div class="left-label">
115 ${_('Diffs')}:
115 ${_('Diff options')}:
116 </div>
116 </div>
117 <div class="right-content">
117 <div class="right-content">
118 <div class="diff-actions">
118 <div class="diff-actions">
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'))}">
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 ${_('Raw Diff')}
120 ${_('Raw Diff')}
121 </a>
121 </a>
122 |
122 |
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'))}">
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 ${_('Patch Diff')}
124 ${_('Patch Diff')}
125 </a>
125 </a>
126 |
126 |
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'))}">
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 ${_('Download Diff')}
128 ${_('Download Diff')}
129 </a>
129 </a>
130 |
130 |
131 ${c.ignorews_url(request.GET)}
131 ${c.ignorews_url(request.GET)}
132 |
132 |
133 ${c.context_url(request.GET)}
133 ${c.context_url(request.GET)}
134 </div>
134 </div>
135 </div>
135 </div>
136 </div>
136 </div>
137
137
138 <div class="fieldset">
138 <div class="fieldset">
139 <div class="left-label">
139 <div class="left-label">
140 ${_('Comments')}:
140 ${_('Comments')}:
141 </div>
141 </div>
142 <div class="right-content">
142 <div class="right-content">
143 <div class="comments-number">
143 <div class="comments-number">
144 %if c.comments:
144 %if c.comments:
145 <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>,
145 <a href="#comments">${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}</a>,
146 %else:
146 %else:
147 ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}
147 ${ungettext("%d Commit comment", "%d Commit comments", len(c.comments)) % len(c.comments)}
148 %endif
148 %endif
149 %if c.inline_cnt:
149 %if c.inline_cnt:
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>
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 %else:
151 %else:
152 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
152 ${ungettext("%d Inline Comment", "%d Inline Comments", c.inline_cnt) % c.inline_cnt}
153 %endif
153 %endif
154 </div>
154 </div>
155 </div>
155 </div>
156 </div>
156 </div>
157
157
158 </div> <!-- end summary-detail -->
158 </div> <!-- end summary-detail -->
159
159
160 <div id="commit-stats" class="sidebar-right">
160 <div id="commit-stats" class="sidebar-right">
161 <div class="summary-detail-header">
161 <div class="summary-detail-header">
162 <h4 class="item">
162 <h4 class="item">
163 ${_('Author')}
163 ${_('Author')}
164 </h4>
164 </h4>
165 </div>
165 </div>
166 <div class="sidebar-right-content">
166 <div class="sidebar-right-content">
167 ${self.gravatar_with_user(c.commit.author)}
167 ${self.gravatar_with_user(c.commit.author)}
168 <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div>
168 <div class="user-inline-data">- ${h.age_component(c.commit.date)}</div>
169 </div>
169 </div>
170 </div><!-- end sidebar -->
170 </div><!-- end sidebar -->
171 </div> <!-- end summary -->
171 </div> <!-- end summary -->
172 <div class="cs_files">
172 <div class="cs_files">
173 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
173 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
174 ${cbdiffs.render_diffset_menu()}
174 ${cbdiffs.render_diffset_menu()}
175 ${cbdiffs.render_diffset(
175 ${cbdiffs.render_diffset(
176 c.changes[c.commit.raw_id], commit=c.commit, use_comments=True)}
176 c.changes[c.commit.raw_id], commit=c.commit, use_comments=True)}
177 </div>
177 </div>
178
178
179 ## template for inline comment form
179 ## template for inline comment form
180 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
180 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
181
181
182 ## render comments
182 ## render comments
183 ${comment.generate_comments()}
183 ${comment.generate_comments()}
184
184
185 ## main comment form and it status
185 ## main comment form and it status
186 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id),
186 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision=c.commit.raw_id),
187 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
187 h.commit_status(c.rhodecode_db_repo, c.commit.raw_id))}
188 </div>
188 </div>
189
189
190 ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
190 ## FORM FOR MAKING JS ACTION AS CHANGESET COMMENTS
191 <script type="text/javascript">
191 <script type="text/javascript">
192
192
193 $(document).ready(function() {
193 $(document).ready(function() {
194
194
195 var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
195 var boxmax = parseInt($('#trimmed_message_box').css('max-height'), 10);
196 if($('#trimmed_message_box').height() === boxmax){
196 if($('#trimmed_message_box').height() === boxmax){
197 $('#message_expand').show();
197 $('#message_expand').show();
198 }
198 }
199
199
200 $('#message_expand').on('click', function(e){
200 $('#message_expand').on('click', function(e){
201 $('#trimmed_message_box').css('max-height', 'none');
201 $('#trimmed_message_box').css('max-height', 'none');
202 $(this).hide();
202 $(this).hide();
203 });
203 });
204
204
205 $('.show-inline-comments').on('click', function(e){
205 $('.show-inline-comments').on('click', function(e){
206 var boxid = $(this).attr('data-comment-id');
206 var boxid = $(this).attr('data-comment-id');
207 var button = $(this);
207 var button = $(this);
208
208
209 if(button.hasClass("comments-visible")) {
209 if(button.hasClass("comments-visible")) {
210 $('#{0} .inline-comments'.format(boxid)).each(function(index){
210 $('#{0} .inline-comments'.format(boxid)).each(function(index){
211 $(this).hide();
211 $(this).hide();
212 });
212 });
213 button.removeClass("comments-visible");
213 button.removeClass("comments-visible");
214 } else {
214 } else {
215 $('#{0} .inline-comments'.format(boxid)).each(function(index){
215 $('#{0} .inline-comments'.format(boxid)).each(function(index){
216 $(this).show();
216 $(this).show();
217 });
217 });
218 button.addClass("comments-visible");
218 button.addClass("comments-visible");
219 }
219 }
220 });
220 });
221
221
222
222
223 // next links
223 // next links
224 $('#child_link').on('click', function(e){
224 $('#child_link').on('click', function(e){
225 // fetch via ajax what is going to be the next link, if we have
225 // fetch via ajax what is going to be the next link, if we have
226 // >1 links show them to user to choose
226 // >1 links show them to user to choose
227 if(!$('#child_link').hasClass('disabled')){
227 if(!$('#child_link').hasClass('disabled')){
228 $.ajax({
228 $.ajax({
229 url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}',
229 url: '${h.url('changeset_children',repo_name=c.repo_name, revision=c.commit.raw_id)}',
230 success: function(data) {
230 success: function(data) {
231 if(data.results.length === 0){
231 if(data.results.length === 0){
232 $('#child_link').html("${_('No Child Commits')}").addClass('disabled');
232 $('#child_link').html("${_('No Child Commits')}").addClass('disabled');
233 }
233 }
234 if(data.results.length === 1){
234 if(data.results.length === 1){
235 var commit = data.results[0];
235 var commit = data.results[0];
236 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
236 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
237 }
237 }
238 else if(data.results.length === 2){
238 else if(data.results.length === 2){
239 $('#child_link').addClass('disabled');
239 $('#child_link').addClass('disabled');
240 $('#child_link').addClass('double');
240 $('#child_link').addClass('double');
241 var _html = '';
241 var _html = '';
242 _html +='<a title="__title__" href="__url__">__rev__</a> '
242 _html +='<a title="__title__" href="__url__">__rev__</a> '
243 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
243 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
244 .replace('__title__', data.results[0].message)
244 .replace('__title__', data.results[0].message)
245 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
245 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
246 _html +=' | '
246 _html +=' | '
247 _html +='<a title="__title__" href="__url__">__rev__</a> '
247 _html +='<a title="__title__" href="__url__">__rev__</a> '
248 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
248 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
249 .replace('__title__', data.results[1].message)
249 .replace('__title__', data.results[1].message)
250 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
250 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
251 $('#child_link').html(_html);
251 $('#child_link').html(_html);
252 }
252 }
253 }
253 }
254 });
254 });
255 e.preventDefault();
255 e.preventDefault();
256 }
256 }
257 });
257 });
258
258
259 // prev links
259 // prev links
260 $('#parent_link').on('click', function(e){
260 $('#parent_link').on('click', function(e){
261 // fetch via ajax what is going to be the next link, if we have
261 // fetch via ajax what is going to be the next link, if we have
262 // >1 links show them to user to choose
262 // >1 links show them to user to choose
263 if(!$('#parent_link').hasClass('disabled')){
263 if(!$('#parent_link').hasClass('disabled')){
264 $.ajax({
264 $.ajax({
265 url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}',
265 url: '${h.url("changeset_parents",repo_name=c.repo_name, revision=c.commit.raw_id)}',
266 success: function(data) {
266 success: function(data) {
267 if(data.results.length === 0){
267 if(data.results.length === 0){
268 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
268 $('#parent_link').html('${_('No Parent Commits')}').addClass('disabled');
269 }
269 }
270 if(data.results.length === 1){
270 if(data.results.length === 1){
271 var commit = data.results[0];
271 var commit = data.results[0];
272 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
272 window.location = pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': commit.raw_id});
273 }
273 }
274 else if(data.results.length === 2){
274 else if(data.results.length === 2){
275 $('#parent_link').addClass('disabled');
275 $('#parent_link').addClass('disabled');
276 $('#parent_link').addClass('double');
276 $('#parent_link').addClass('double');
277 var _html = '';
277 var _html = '';
278 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
278 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
279 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
279 .replace('__rev__','r{0}:{1}'.format(data.results[0].revision, data.results[0].raw_id.substr(0,6)))
280 .replace('__title__', data.results[0].message)
280 .replace('__title__', data.results[0].message)
281 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
281 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[0].raw_id}));
282 _html +=' | '
282 _html +=' | '
283 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
283 _html +='<a title="__title__" href="__url__">Parent __rev__</a>'
284 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
284 .replace('__rev__','r{0}:{1}'.format(data.results[1].revision, data.results[1].raw_id.substr(0,6)))
285 .replace('__title__', data.results[1].message)
285 .replace('__title__', data.results[1].message)
286 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
286 .replace('__url__', pyroutes.url('changeset_home', {'repo_name': '${c.repo_name}','revision': data.results[1].raw_id}));
287 $('#parent_link').html(_html);
287 $('#parent_link').html(_html);
288 }
288 }
289 }
289 }
290 });
290 });
291 e.preventDefault();
291 e.preventDefault();
292 }
292 }
293 });
293 });
294
294
295 if (location.hash) {
295 if (location.hash) {
296 var result = splitDelimitedHash(location.hash);
296 var result = splitDelimitedHash(location.hash);
297 var line = $('html').find(result.loc);
297 var line = $('html').find(result.loc);
298 if (line.length > 0){
298 if (line.length > 0){
299 offsetScroll(line, 70);
299 offsetScroll(line, 70);
300 }
300 }
301 }
301 }
302
302
303 // browse tree @ revision
303 // browse tree @ revision
304 $('#files_link').on('click', function(e){
304 $('#files_link').on('click', function(e){
305 window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}';
305 window.location = '${h.url('files_home',repo_name=c.repo_name, revision=c.commit.raw_id, f_path='')}';
306 e.preventDefault();
306 e.preventDefault();
307 });
307 });
308
308
309 // inject comments into their proper positions
309 // inject comments into their proper positions
310 var file_comments = $('.inline-comment-placeholder');
310 var file_comments = $('.inline-comment-placeholder');
311 })
311 })
312 </script>
312 </script>
313
313
314 </%def>
314 </%def>
@@ -1,71 +1,125 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3
3
4 <%def name="title()">
4 <%def name="title()">
5 ${_('%s Commits') % c.repo_name} -
5 ${_('%s Commits') % c.repo_name} -
6 r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}
6 r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}
7 ...
7 ...
8 r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)}
8 r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)}
9 ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)}
9 ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)}
10 %if c.rhodecode_name:
10 %if c.rhodecode_name:
11 &middot; ${h.branding(c.rhodecode_name)}
11 &middot; ${h.branding(c.rhodecode_name)}
12 %endif
12 %endif
13 </%def>
13 </%def>
14
14
15 <%def name="breadcrumbs_links()">
15 <%def name="breadcrumbs_links()">
16 ${_('Commits')} -
16 ${_('Commits')} -
17 r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}
17 r${c.commit_ranges[0].revision}:${h.short_id(c.commit_ranges[0].raw_id)}
18 ...
18 ...
19 r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)}
19 r${c.commit_ranges[-1].revision}:${h.short_id(c.commit_ranges[-1].raw_id)}
20 ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)}
20 ${ungettext('(%s commit)','(%s commits)', len(c.commit_ranges)) % len(c.commit_ranges)}
21 </%def>
21 </%def>
22
22
23 <%def name="menu_bar_nav()">
23 <%def name="menu_bar_nav()">
24 ${self.menu_items(active='repositories')}
24 ${self.menu_items(active='repositories')}
25 </%def>
25 </%def>
26
26
27 <%def name="menu_bar_subnav()">
27 <%def name="menu_bar_subnav()">
28 ${self.repo_menu(active='changelog')}
28 ${self.repo_menu(active='changelog')}
29 </%def>
29 </%def>
30
30
31 <%def name="main()">
31 <%def name="main()">
32 <div class="summary-header">
32 <div class="summary-header">
33 <div class="title">
33 <div class="title">
34 <div class="title-content">
35 ${self.repo_page_title(c.rhodecode_db_repo)}
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 </div>
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">
65 <%doc>
47 <div class="title">
66 ##TODO(marcink): implement this and diff menus
48 <h2>
67 <div class="fieldset">
49 ${self.breadcrumbs_links()}
68 <div class="left-label">
50 </h2>
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 </div>
108 </div>
52 </div>
109 ## Commit range generated below
53 <div id="changeset_compare_view_content">
54 ##CS
55 <%include file="../compare/compare_commits.html"/>
110 <%include file="../compare/compare_commits.html"/>
56 <div class="cs_files">
111 <div class="cs_files">
57 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
112 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
58 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
113 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
59 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
114 <%namespace name="diff_block" file="/changeset/diff_block.html"/>
60 ${cbdiffs.render_diffset_menu()}
115 ${cbdiffs.render_diffset_menu()}
61 %for commit in c.commit_ranges:
116 %for commit in c.commit_ranges:
62 ${cbdiffs.render_diffset(
117 ${cbdiffs.render_diffset(
63 diffset=c.changes[commit.raw_id],
118 diffset=c.changes[commit.raw_id],
64 collapse_when_files_over=5,
119 collapse_when_files_over=5,
65 commit=commit,
120 commit=commit,
66 )}
121 )}
67 %endfor
122 %endfor
68 </table>
69 </div>
123 </div>
70 </div>
124 </div>
71 </%def>
125 </%def>
@@ -1,103 +1,64 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 ##usage:
2 ##usage:
3 ## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
3 ## <%namespace name="diff_block" file="/changeset/diff_block.html"/>
4 ## ${diff_block.diff_block_changeset_table(change)}
4 ## ${diff_block.diff_block_changeset_table(change)}
5 ##
5 ##
6 <%def name="changeset_message()">
6 <%def name="changeset_message()">
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>
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 </%def>
8 </%def>
9 <%def name="file_message()">
9 <%def name="file_message()">
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>
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 </%def>
11 </%def>
12
12
13 <%def name="diff_block_changeset_table(change)">
13 <%def name="diff_block_changeset_table(change)">
14 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
14 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
15 %for FID,(cs1, cs2, change, filenode_path, diff, stats, file) in change.iteritems():
15 %for FID,(cs1, cs2, change, filenode_path, diff, stats, file) in change.iteritems():
16 <div id="${h.FID('',filenode_path)}_target" ></div>
16 <div id="${h.FID('',filenode_path)}_target" ></div>
17 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm">
17 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm">
18 <div class="code-body">
18 <div class="code-body">
19 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none"></div>
19 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none"></div>
20 ${diff|n}
20 ${diff|n}
21 % if file["is_limited_diff"]:
21 % if file["is_limited_diff"]:
22 % if file["exceeds_limit"]:
22 % if file["exceeds_limit"]:
23 ${self.file_message()}
23 ${self.file_message()}
24 % else:
24 % else:
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>
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 % endif
26 % endif
27 % endif
27 % endif
28 </div>
28 </div>
29 </div>
29 </div>
30 %endfor
30 %endfor
31 </div>
31 </div>
32 </%def>
32 </%def>
33
33
34 <%def name="diff_block_simple(change)">
34 <%def name="diff_block_simple(change)">
35 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
35 <div class="diff-container" id="${'diff-container-%s' % (id(change))}">
36 %for op,filenode_path,diff,file in change:
36 %for op,filenode_path,diff,file in change:
37 <div id="${h.FID('',filenode_path)}_target" ></div>
37 <div id="${h.FID('',filenode_path)}_target" ></div>
38 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm" >
38 <div id="${h.FID('',filenode_path)}" class="diffblock margined comm" >
39 <div class="code-body">
39 <div class="code-body">
40 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none;"></div>
40 <div class="full_f_path" path="${h.safe_unicode(filenode_path)}" style="display: none;"></div>
41 ${diff|n}
41 ${diff|n}
42 % if file["is_limited_diff"]:
42 % if file["is_limited_diff"]:
43 % if file["exceeds_limit"]:
43 % if file["exceeds_limit"]:
44 ${self.file_message()}
44 ${self.file_message()}
45 % else:
45 % else:
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>
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 % endif
47 % endif
48 % endif
48 % endif
49 </div>
49 </div>
50 </div>
50 </div>
51 %endfor
51 %endfor
52 </div>
52 </div>
53 </%def>
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 <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)">
56 <%def name="diff_summary_text(changed_files, lines_added, lines_deleted, limited_diff=False)">
96 % if limited_diff:
57 % if limited_diff:
97 ${ungettext('%(num)s file changed', '%(num)s files changed', changed_files) % {'num': changed_files}}
58 ${ungettext('%(num)s file changed', '%(num)s files changed', changed_files) % {'num': changed_files}}
98 % else:
59 % else:
99 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
60 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
100 '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', changed_files) % {'num': changed_files, 'linesadd': lines_added, 'linesdel': lines_deleted}}
61 '%(num)s files changed: %(linesadd)s inserted, %(linesdel)s deleted', changed_files) % {'num': changed_files, 'linesadd': lines_added, 'linesdel': lines_deleted}}
101 %endif
62 %endif
102 </%def>
63 </%def>
103
64
@@ -1,577 +1,581 b''
1 <%def name="diff_line_anchor(filename, line, type)"><%
1 <%def name="diff_line_anchor(filename, line, type)"><%
2 return '%s_%s_%i' % (h.safeid(filename), type, line)
2 return '%s_%s_%i' % (h.safeid(filename), type, line)
3 %></%def>
3 %></%def>
4
4
5 <%def name="action_class(action)"><%
5 <%def name="action_class(action)"><%
6 return {
6 return {
7 '-': 'cb-deletion',
7 '-': 'cb-deletion',
8 '+': 'cb-addition',
8 '+': 'cb-addition',
9 ' ': 'cb-context',
9 ' ': 'cb-context',
10 }.get(action, 'cb-empty')
10 }.get(action, 'cb-empty')
11 %></%def>
11 %></%def>
12
12
13 <%def name="op_class(op_id)"><%
13 <%def name="op_class(op_id)"><%
14 return {
14 return {
15 DEL_FILENODE: 'deletion', # file deleted
15 DEL_FILENODE: 'deletion', # file deleted
16 BIN_FILENODE: 'warning' # binary diff hidden
16 BIN_FILENODE: 'warning' # binary diff hidden
17 }.get(op_id, 'addition')
17 }.get(op_id, 'addition')
18 %></%def>
18 %></%def>
19
19
20 <%def name="link_for(**kw)"><%
20 <%def name="link_for(**kw)"><%
21 new_args = request.GET.mixed()
21 new_args = request.GET.mixed()
22 new_args.update(kw)
22 new_args.update(kw)
23 return h.url('', **new_args)
23 return h.url('', **new_args)
24 %></%def>
24 %></%def>
25
25
26 <%def name="render_diffset(diffset, commit=None,
26 <%def name="render_diffset(diffset, commit=None,
27
27
28 # collapse all file diff entries when there are more than this amount of files in the diff
28 # collapse all file diff entries when there are more than this amount of files in the diff
29 collapse_when_files_over=20,
29 collapse_when_files_over=20,
30
30
31 # collapse lines in the diff when more than this amount of lines changed in the file diff
31 # collapse lines in the diff when more than this amount of lines changed in the file diff
32 lines_changed_limit=500,
32 lines_changed_limit=500,
33
33
34 # add a ruler at to the output
34 # add a ruler at to the output
35 ruler_at_chars=0,
35 ruler_at_chars=0,
36
36
37 # show inline comments
37 # show inline comments
38 use_comments=False,
38 use_comments=False,
39
39
40 # disable new comments
40 # disable new comments
41 disable_new_comments=False,
41 disable_new_comments=False,
42
42
43 )">
43 )">
44
44
45 %if use_comments:
45 %if use_comments:
46 <div id="cb-comments-inline-container-template" class="js-template">
46 <div id="cb-comments-inline-container-template" class="js-template">
47 ${inline_comments_container([])}
47 ${inline_comments_container([])}
48 </div>
48 </div>
49 <div class="js-template" id="cb-comment-inline-form-template">
49 <div class="js-template" id="cb-comment-inline-form-template">
50 <div class="comment-inline-form ac">
50 <div class="comment-inline-form ac">
51 %if c.rhodecode_user.username != h.DEFAULT_USER:
51 %if c.rhodecode_user.username != h.DEFAULT_USER:
52 ${h.form('#', method='get')}
52 ${h.form('#', method='get')}
53 <div id="edit-container_{1}" class="clearfix">
53 <div id="edit-container_{1}" class="clearfix">
54 <div class="comment-title pull-left">
54 <div class="comment-title pull-left">
55 ${_('Create a comment on line {1}.')}
55 ${_('Create a comment on line {1}.')}
56 </div>
56 </div>
57 <div class="comment-help pull-right">
57 <div class="comment-help pull-right">
58 ${(_('Comments parsed using %s syntax with %s support.') % (
58 ${(_('Comments parsed using %s syntax with %s support.') % (
59 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
59 ('<a href="%s">%s</a>' % (h.url('%s_help' % c.visual.default_renderer), c.visual.default_renderer.upper())),
60 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
60 ('<span class="tooltip" title="%s">@mention</span>' % _('Use @username inside this text to send notification to this RhodeCode user'))
61 )
61 )
62 )|n
62 )|n
63 }
63 }
64 </div>
64 </div>
65 <div style="clear: both"></div>
65 <div style="clear: both"></div>
66 <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea>
66 <textarea id="text_{1}" name="text" class="comment-block-ta ac-input"></textarea>
67 </div>
67 </div>
68 <div id="preview-container_{1}" class="clearfix" style="display: none;">
68 <div id="preview-container_{1}" class="clearfix" style="display: none;">
69 <div class="comment-help">
69 <div class="comment-help">
70 ${_('Comment preview')}
70 ${_('Comment preview')}
71 </div>
71 </div>
72 <div id="preview-box_{1}" class="preview-box"></div>
72 <div id="preview-box_{1}" class="preview-box"></div>
73 </div>
73 </div>
74 <div class="comment-footer">
74 <div class="comment-footer">
75 <div class="action-buttons">
75 <div class="action-buttons">
76 <input type="hidden" name="f_path" value="{0}">
76 <input type="hidden" name="f_path" value="{0}">
77 <input type="hidden" name="line" value="{1}">
77 <input type="hidden" name="line" value="{1}">
78 <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button>
78 <button id="preview-btn_{1}" class="btn btn-secondary">${_('Preview')}</button>
79 <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button>
79 <button id="edit-btn_{1}" class="btn btn-secondary" style="display: none;">${_('Edit')}</button>
80 ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')}
80 ${h.submit('save', _('Comment'), class_='btn btn-success save-inline-form')}
81 </div>
81 </div>
82 <div class="comment-button">
82 <div class="comment-button">
83 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
83 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
84 ${_('Cancel')}
84 ${_('Cancel')}
85 </button>
85 </button>
86 </div>
86 </div>
87 ${h.end_form()}
87 ${h.end_form()}
88 </div>
88 </div>
89 %else:
89 %else:
90 ${h.form('', class_='inline-form comment-form-login', method='get')}
90 ${h.form('', class_='inline-form comment-form-login', method='get')}
91 <div class="pull-left">
91 <div class="pull-left">
92 <div class="comment-help pull-right">
92 <div class="comment-help pull-right">
93 ${_('You need to be logged in to comment.')} <a href="${h.route_path('login', _query={'came_from': h.url.current()})}">${_('Login now')}</a>
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 </div>
94 </div>
95 </div>
95 </div>
96 <div class="comment-button pull-right">
96 <div class="comment-button pull-right">
97 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
97 <button type="button" class="cb-comment-cancel" onclick="return Rhodecode.comments.cancelComment(this);">
98 ${_('Cancel')}
98 ${_('Cancel')}
99 </button>
99 </button>
100 </div>
100 </div>
101 <div class="clearfix"></div>
101 <div class="clearfix"></div>
102 ${h.end_form()}
102 ${h.end_form()}
103 %endif
103 %endif
104 </div>
104 </div>
105 </div>
105 </div>
106
106
107 %endif
107 %endif
108 <%
108 <%
109 collapse_all = len(diffset.files) > collapse_when_files_over
109 collapse_all = len(diffset.files) > collapse_when_files_over
110 %>
110 %>
111
111
112 %if c.diffmode == 'sideside':
112 %if c.diffmode == 'sideside':
113 <style>
113 <style>
114 .wrapper {
114 .wrapper {
115 max-width: 1600px !important;
115 max-width: 1600px !important;
116 }
116 }
117 </style>
117 </style>
118 %endif
118 %endif
119 %if ruler_at_chars:
119 %if ruler_at_chars:
120 <style>
120 <style>
121 .diff table.cb .cb-content:after {
121 .diff table.cb .cb-content:after {
122 content: "";
122 content: "";
123 border-left: 1px solid blue;
123 border-left: 1px solid blue;
124 position: absolute;
124 position: absolute;
125 top: 0;
125 top: 0;
126 height: 18px;
126 height: 18px;
127 opacity: .2;
127 opacity: .2;
128 z-index: 10;
128 z-index: 10;
129 ## +5 to account for diff action (+/-)
129 ## +5 to account for diff action (+/-)
130 left: ${ruler_at_chars + 5}ch;
130 left: ${ruler_at_chars + 5}ch;
131 </style>
131 </style>
132 %endif
132 %endif
133 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
133 <div class="diffset ${disable_new_comments and 'diffset-comments-disabled'}">
134 <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}">
134 <div class="diffset-heading ${diffset.limited_diff and 'diffset-heading-warning' or ''}">
135 %if commit:
135 %if commit:
136 <div class="pull-right">
136 <div class="pull-right">
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='')}">
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 ${_('Browse Files')}
138 ${_('Browse Files')}
139 </a>
139 </a>
140 </div>
140 </div>
141 %endif
141 %endif
142 <h2 class="clearinner">
142 <h2 class="clearinner">
143 %if commit:
143 %if commit:
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> -
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 ${h.age_component(commit.date)} -
145 ${h.age_component(commit.date)} -
146 %endif
146 %endif
147 %if diffset.limited_diff:
147 %if diffset.limited_diff:
148 ${_('The requested commit is too big and content was truncated.')}
148 ${_('The requested commit is too big and content was truncated.')}
149
149
150 ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}}
150 ${ungettext('%(num)s file changed.', '%(num)s files changed.', diffset.changed_files) % {'num': diffset.changed_files}}
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>
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 %else:
152 %else:
153 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
153 ${ungettext('%(num)s file changed: %(linesadd)s inserted, ''%(linesdel)s deleted',
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}}
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 %endif
155 %endif
156 </h2>
156 </h2>
157 </div>
157 </div>
158
158
159 %if not diffset.files:
159 %if not diffset.files:
160 <p class="empty_data">${_('No files')}</p>
160 <p class="empty_data">${_('No files')}</p>
161 %endif
161 %endif
162
162
163 <div class="filediffs">
163 <div class="filediffs">
164 %for i, filediff in enumerate(diffset.files):
164 %for i, filediff in enumerate(diffset.files):
165 <%
165
166 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
166 <%
167 over_lines_changed_limit = lines_changed > lines_changed_limit
167 lines_changed = filediff['patch']['stats']['added'] + filediff['patch']['stats']['deleted']
168 %>
168 over_lines_changed_limit = lines_changed > lines_changed_limit
169 %>
169 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
170 <input ${collapse_all and 'checked' or ''} class="filediff-collapse-state" id="filediff-collapse-${id(filediff)}" type="checkbox">
170 <div
171 <div
171 class="filediff"
172 class="filediff"
172 data-f-path="${filediff['patch']['filename']}"
173 data-f-path="${filediff['patch']['filename']}"
173 id="a_${h.FID('', filediff['patch']['filename'])}">
174 id="a_${h.FID('', filediff['patch']['filename'])}">
174 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
175 <label for="filediff-collapse-${id(filediff)}" class="filediff-heading">
175 <div class="filediff-collapse-indicator"></div>
176 <div class="filediff-collapse-indicator"></div>
176 ${diff_ops(filediff)}
177 ${diff_ops(filediff)}
177 </label>
178 </label>
178 ${diff_menu(filediff, use_comments=use_comments)}
179 ${diff_menu(filediff, use_comments=use_comments)}
179 <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}">
180 <table class="cb cb-diff-${c.diffmode} code-highlight ${over_lines_changed_limit and 'cb-collapsed' or ''}">
180 %if not filediff.hunks:
181 %if not filediff.hunks:
181 %for op_id, op_text in filediff['patch']['stats']['ops'].items():
182 %for op_id, op_text in filediff['patch']['stats']['ops'].items():
182 <tr>
183 <tr>
183 <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
184 <td class="cb-text cb-${op_class(op_id)}" ${c.diffmode == 'unified' and 'colspan=3' or 'colspan=4'}>
184 %if op_id == DEL_FILENODE:
185 %if op_id == DEL_FILENODE:
185 ${_('File was deleted')}
186 ${_('File was deleted')}
186 %elif op_id == BIN_FILENODE:
187 %elif op_id == BIN_FILENODE:
187 ${_('Binary file hidden')}
188 ${_('Binary file hidden')}
188 %else:
189 %else:
189 ${op_text}
190 ${op_text}
190 %endif
191 %endif
191 </td>
192 </td>
192 </tr>
193 </tr>
193 %endfor
194 %endfor
194 %endif
195 %endif
195 %if over_lines_changed_limit:
196 %if over_lines_changed_limit:
196 <tr class="cb-warning cb-collapser">
197 <tr class="cb-warning cb-collapser">
197 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}>
198 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}>
198 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
199 ${_('This diff has been collapsed as it changes many lines, (%i lines changed)' % lines_changed)}
199 <a href="#" class="cb-expand"
200 <a href="#" class="cb-expand"
200 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
201 onclick="$(this).closest('table').removeClass('cb-collapsed'); return false;">${_('Show them')}
201 </a>
202 </a>
202 <a href="#" class="cb-collapse"
203 <a href="#" class="cb-collapse"
203 onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')}
204 onclick="$(this).closest('table').addClass('cb-collapsed'); return false;">${_('Hide them')}
204 </a>
205 </a>
205 </td>
206 </td>
206 </tr>
207 </tr>
207 %endif
208 %endif
208 %if filediff.patch['is_limited_diff']:
209 %if filediff.patch['is_limited_diff']:
209 <tr class="cb-warning cb-collapser">
210 <tr class="cb-warning cb-collapser">
210 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}>
211 <td class="cb-text" ${c.diffmode == 'unified' and 'colspan=4' or 'colspan=6'}>
211 ${_('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 ${_('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 </td>
213 </td>
213 </tr>
214 </tr>
214 %endif
215 %endif
215 %for hunk in filediff.hunks:
216 %for hunk in filediff.hunks:
216 <tr class="cb-hunk">
217 <tr class="cb-hunk">
217 <td ${c.diffmode == 'unified' and 'colspan=3' or ''}>
218 <td ${c.diffmode == 'unified' and 'colspan=3' or ''}>
218 ## TODO: dan: add ajax loading of more context here
219 ## TODO: dan: add ajax loading of more context here
219 ## <a href="#">
220 ## <a href="#">
220 <i class="icon-more"></i>
221 <i class="icon-more"></i>
221 ## </a>
222 ## </a>
222 </td>
223 </td>
223 <td ${c.diffmode == 'sideside' and 'colspan=5' or ''}>
224 <td ${c.diffmode == 'sideside' and 'colspan=5' or ''}>
224 @@
225 @@
225 -${hunk.source_start},${hunk.source_length}
226 -${hunk.source_start},${hunk.source_length}
226 +${hunk.target_start},${hunk.target_length}
227 +${hunk.target_start},${hunk.target_length}
227 ${hunk.section_header}
228 ${hunk.section_header}
228 </td>
229 </td>
229 </tr>
230 </tr>
230 %if c.diffmode == 'unified':
231 %if c.diffmode == 'unified':
231 ${render_hunk_lines_unified(hunk, use_comments=use_comments)}
232 ${render_hunk_lines_unified(hunk, use_comments=use_comments)}
232 %elif c.diffmode == 'sideside':
233 %elif c.diffmode == 'sideside':
233 ${render_hunk_lines_sideside(hunk, use_comments=use_comments)}
234 ${render_hunk_lines_sideside(hunk, use_comments=use_comments)}
234 %else:
235 %else:
235 <tr class="cb-line">
236 <tr class="cb-line">
236 <td>unknown diff mode</td>
237 <td>unknown diff mode</td>
237 </tr>
238 </tr>
238 %endif
239 %endif
239 %endfor
240 %endfor
240 </table>
241 </table>
241 </div>
242 </div>
242 %endfor
243 %endfor
243 </div>
244 </div>
244 </div>
245 </div>
245 </%def>
246 </%def>
246
247
247 <%def name="diff_ops(filediff)">
248 <%def name="diff_ops(filediff)">
248 <%
249 <%
249 stats = filediff['patch']['stats']
250 stats = filediff['patch']['stats']
250 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
251 from rhodecode.lib.diffs import NEW_FILENODE, DEL_FILENODE, \
251 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
252 MOD_FILENODE, RENAMED_FILENODE, CHMOD_FILENODE, BIN_FILENODE
252 %>
253 %>
253 <span class="pill">
254 <span class="pill">
254 %if filediff.source_file_path and filediff.target_file_path:
255 %if filediff.source_file_path and filediff.target_file_path:
255 %if filediff.source_file_path != filediff.target_file_path: # file was renamed
256 %if filediff.source_file_path != filediff.target_file_path: # file was renamed
256 <strong>${filediff.target_file_path}</strong><del>${filediff.source_file_path}</del>
257 <strong>${filediff.target_file_path}</strong><del>${filediff.source_file_path}</del>
257 %else:
258 %else:
258 ## file was modified
259 ## file was modified
259 <strong>${filediff.source_file_path}</strong>
260 <strong>${filediff.source_file_path}</strong>
260 %endif
261 %endif
261 %else:
262 %else:
262 %if filediff.source_file_path:
263 %if filediff.source_file_path:
263 ## file was deleted
264 ## file was deleted
264 <strong>${filediff.source_file_path}</strong>
265 <strong>${filediff.source_file_path}</strong>
265 %else:
266 %else:
266 ## file was added
267 ## file was added
267 <strong>${filediff.target_file_path}</strong>
268 <strong>${filediff.target_file_path}</strong>
268 %endif
269 %endif
269 %endif
270 %endif
270 </span>
271 </span>
271 <span class="pill-group" style="float: left">
272 <span class="pill-group" style="float: left">
272 %if filediff.patch['is_limited_diff']:
273 %if filediff.patch['is_limited_diff']:
273 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
274 <span class="pill tooltip" op="limited" title="The stats for this diff are not complete">limited diff</span>
274 %endif
275 %endif
275 %if RENAMED_FILENODE in stats['ops']:
276 %if RENAMED_FILENODE in stats['ops']:
276 <span class="pill" op="renamed">renamed</span>
277 <span class="pill" op="renamed">renamed</span>
277 %endif
278 %endif
278
279
279 %if NEW_FILENODE in stats['ops']:
280 %if NEW_FILENODE in stats['ops']:
280 <span class="pill" op="created">created</span>
281 <span class="pill" op="created">created</span>
281 %if filediff['target_mode'].startswith('120'):
282 %if filediff['target_mode'].startswith('120'):
282 <span class="pill" op="symlink">symlink</span>
283 <span class="pill" op="symlink">symlink</span>
283 %else:
284 %else:
284 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
285 <span class="pill" op="mode">${nice_mode(filediff['target_mode'])}</span>
285 %endif
286 %endif
286 %endif
287 %endif
287
288
288 %if DEL_FILENODE in stats['ops']:
289 %if DEL_FILENODE in stats['ops']:
289 <span class="pill" op="removed">removed</span>
290 <span class="pill" op="removed">removed</span>
290 %endif
291 %endif
291
292
292 %if CHMOD_FILENODE in stats['ops']:
293 %if CHMOD_FILENODE in stats['ops']:
293 <span class="pill" op="mode">
294 <span class="pill" op="mode">
294 ${nice_mode(filediff['source_mode'])} ➡ ${nice_mode(filediff['target_mode'])}
295 ${nice_mode(filediff['source_mode'])} ➡ ${nice_mode(filediff['target_mode'])}
295 </span>
296 </span>
296 %endif
297 %endif
297 </span>
298 </span>
298
299
299 <a class="pill filediff-anchor" href="#a_${h.FID('', filediff.patch['filename'])}"></a>
300 <a class="pill filediff-anchor" href="#a_${h.FID('', filediff.patch['filename'])}"></a>
300
301
301 <span class="pill-group" style="float: right">
302 <span class="pill-group" style="float: right">
302 %if BIN_FILENODE in stats['ops']:
303 %if BIN_FILENODE in stats['ops']:
303 <span class="pill" op="binary">binary</span>
304 <span class="pill" op="binary">binary</span>
304 %if MOD_FILENODE in stats['ops']:
305 %if MOD_FILENODE in stats['ops']:
305 <span class="pill" op="modified">modified</span>
306 <span class="pill" op="modified">modified</span>
306 %endif
307 %endif
307 %endif
308 %endif
308 %if stats['added']:
309 %if stats['added']:
309 <span class="pill" op="added">+${stats['added']}</span>
310 <span class="pill" op="added">+${stats['added']}</span>
310 %endif
311 %endif
311 %if stats['deleted']:
312 %if stats['deleted']:
312 <span class="pill" op="deleted">-${stats['deleted']}</span>
313 <span class="pill" op="deleted">-${stats['deleted']}</span>
313 %endif
314 %endif
314 </span>
315 </span>
315
316
316 </%def>
317 </%def>
317
318
318 <%def name="nice_mode(filemode)">
319 <%def name="nice_mode(filemode)">
319 ${filemode.startswith('100') and filemode[3:] or filemode}
320 ${filemode.startswith('100') and filemode[3:] or filemode}
320 </%def>
321 </%def>
321
322
322 <%def name="diff_menu(filediff, use_comments=False)">
323 <%def name="diff_menu(filediff, use_comments=False)">
323 <div class="filediff-menu">
324 <div class="filediff-menu">
324 %if filediff.diffset.source_ref:
325 %if filediff.diffset.source_ref:
325 %if filediff.patch['operation'] in ['D', 'M']:
326 %if filediff.patch['operation'] in ['D', 'M']:
326 <a
327 <a
327 class="tooltip"
328 class="tooltip"
328 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}"
329 href="${h.url('files_home',repo_name=filediff.diffset.repo_name,f_path=filediff.source_file_path,revision=filediff.diffset.source_ref)}"
329 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
330 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
330 >
331 >
331 ${_('Show file before')}
332 ${_('Show file before')}
332 </a>
333 </a>
333 %else:
334 %else:
334 <span
335 <span
335 class="tooltip"
336 class="tooltip"
336 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
337 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.source_ref[:12]})}"
337 >
338 >
338 ${_('Show file before')}
339 ${_('Show file before')}
339 </span>
340 </span>
340 %endif
341 %endif
341 %if filediff.patch['operation'] in ['A', 'M']:
342 %if filediff.patch['operation'] in ['A', 'M']:
342 <a
343 <a
343 class="tooltip"
344 class="tooltip"
344 href="${h.url('files_home',repo_name=filediff.diffset.source_repo_name,f_path=filediff.target_file_path,revision=filediff.diffset.target_ref)}"
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 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
346 title="${h.tooltip(_('Show file at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
346 >
347 >
347 ${_('Show file after')}
348 ${_('Show file after')}
348 </a>
349 </a>
349 %else:
350 %else:
350 <span
351 <span
351 class="tooltip"
352 class="tooltip"
352 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
353 title="${h.tooltip(_('File no longer present at commit: %(commit_id)s') % {'commit_id': filediff.diffset.target_ref[:12]})}"
353 >
354 >
354 ${_('Show file after')}
355 ${_('Show file after')}
355 </span>
356 </span>
356 %endif
357 %endif
357 <a
358 <a
358 class="tooltip"
359 class="tooltip"
359 title="${h.tooltip(_('Raw diff'))}"
360 title="${h.tooltip(_('Raw diff'))}"
360 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 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 ${_('Raw diff')}
363 ${_('Raw diff')}
363 </a>
364 </a>
364 <a
365 <a
365 class="tooltip"
366 class="tooltip"
366 title="${h.tooltip(_('Download diff'))}"
367 title="${h.tooltip(_('Download diff'))}"
367 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 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 ${_('Download diff')}
370 ${_('Download diff')}
370 </a>
371 </a>
371
372
372 ## 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 ## 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 %if hasattr(c, 'ignorews_url'):
374 %if hasattr(c, 'ignorews_url'):
374 ${c.ignorews_url(request.GET, h.FID('', filediff['patch']['filename']))}
375 ${c.ignorews_url(request.GET, h.FID('', filediff['patch']['filename']))}
375 %endif
376 %endif
376 %if hasattr(c, 'context_url'):
377 %if hasattr(c, 'context_url'):
377 ${c.context_url(request.GET, h.FID('', filediff['patch']['filename']))}
378 ${c.context_url(request.GET, h.FID('', filediff['patch']['filename']))}
378 %endif
379 %endif
379
380
380
381
381 %if use_comments:
382 %if use_comments:
382 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
383 <a href="#" onclick="return Rhodecode.comments.toggleComments(this);">
383 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
384 <span class="show-comment-button">${_('Show comments')}</span><span class="hide-comment-button">${_('Hide comments')}</span>
384 </a>
385 </a>
385 %endif
386 %endif
386 %endif
387 %endif
387 </div>
388 </div>
388 </%def>
389 </%def>
389
390
390
391
391 <%namespace name="commentblock" file="/changeset/changeset_file_comment.html"/>
392 <%namespace name="commentblock" file="/changeset/changeset_file_comment.html"/>
392 <%def name="inline_comments_container(comments)">
393 <%def name="inline_comments_container(comments)">
393 <div class="inline-comments">
394 <div class="inline-comments">
394 %for comment in comments:
395 %for comment in comments:
395 ${commentblock.comment_block(comment, inline=True)}
396 ${commentblock.comment_block(comment, inline=True)}
396 %endfor
397 %endfor
397
398
398 <span onclick="return Rhodecode.comments.createComment(this)"
399 <span onclick="return Rhodecode.comments.createComment(this)"
399 class="btn btn-secondary cb-comment-add-button ${'comment-outdated' if comments and comments[-1].outdated else ''}"
400 class="btn btn-secondary cb-comment-add-button ${'comment-outdated' if comments and comments[-1].outdated else ''}"
400 style="${'display: none;' if comments and comments[-1].outdated else ''}">
401 style="${'display: none;' if comments and comments[-1].outdated else ''}">
401 ${_('Add another comment')}
402 ${_('Add another comment')}
402 </span>
403 </span>
403
404
404 </div>
405 </div>
405 </%def>
406 </%def>
406
407
407
408
408 <%def name="render_hunk_lines_sideside(hunk, use_comments=False)">
409 <%def name="render_hunk_lines_sideside(hunk, use_comments=False)">
409 %for i, line in enumerate(hunk.sideside):
410 %for i, line in enumerate(hunk.sideside):
410 <%
411 <%
411 old_line_anchor, new_line_anchor = None, None
412 old_line_anchor, new_line_anchor = None, None
412 if line.original.lineno:
413 if line.original.lineno:
413 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o')
414 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, line.original.lineno, 'o')
414 if line.modified.lineno:
415 if line.modified.lineno:
415 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
416 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, line.modified.lineno, 'n')
416 %>
417 %>
418
417 <tr class="cb-line">
419 <tr class="cb-line">
418 <td class="cb-data ${action_class(line.original.action)}"
420 <td class="cb-data ${action_class(line.original.action)}"
419 data-line-number="${line.original.lineno}"
421 data-line-number="${line.original.lineno}"
420 >
422 >
421 <div>
423 <div>
422 %if line.original.comments:
424 %if line.original.comments:
423 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
425 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
424 %endif
426 %endif
425 </div>
427 </div>
426 </td>
428 </td>
427 <td class="cb-lineno ${action_class(line.original.action)}"
429 <td class="cb-lineno ${action_class(line.original.action)}"
428 data-line-number="${line.original.lineno}"
430 data-line-number="${line.original.lineno}"
429 %if old_line_anchor:
431 %if old_line_anchor:
430 id="${old_line_anchor}"
432 id="${old_line_anchor}"
431 %endif
433 %endif
432 >
434 >
433 %if line.original.lineno:
435 %if line.original.lineno:
434 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
436 <a name="${old_line_anchor}" href="#${old_line_anchor}">${line.original.lineno}</a>
435 %endif
437 %endif
436 </td>
438 </td>
437 <td class="cb-content ${action_class(line.original.action)}"
439 <td class="cb-content ${action_class(line.original.action)}"
438 data-line-number="o${line.original.lineno}"
440 data-line-number="o${line.original.lineno}"
439 >
441 >
440 %if use_comments and line.original.lineno:
442 %if use_comments and line.original.lineno:
441 ${render_add_comment_button()}
443 ${render_add_comment_button()}
442 %endif
444 %endif
443 <span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span>
445 <span class="cb-code">${line.original.action} ${line.original.content or '' | n}</span>
444 %if use_comments and line.original.lineno and line.original.comments:
446 %if use_comments and line.original.lineno and line.original.comments:
445 ${inline_comments_container(line.original.comments)}
447 ${inline_comments_container(line.original.comments)}
446 %endif
448 %endif
447 </td>
449 </td>
448 <td class="cb-data ${action_class(line.modified.action)}"
450 <td class="cb-data ${action_class(line.modified.action)}"
449 data-line-number="${line.modified.lineno}"
451 data-line-number="${line.modified.lineno}"
450 >
452 >
451 <div>
453 <div>
452 %if line.modified.comments:
454 %if line.modified.comments:
453 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
455 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
454 %endif
456 %endif
455 </div>
457 </div>
456 </td>
458 </td>
457 <td class="cb-lineno ${action_class(line.modified.action)}"
459 <td class="cb-lineno ${action_class(line.modified.action)}"
458 data-line-number="${line.modified.lineno}"
460 data-line-number="${line.modified.lineno}"
459 %if new_line_anchor:
461 %if new_line_anchor:
460 id="${new_line_anchor}"
462 id="${new_line_anchor}"
461 %endif
463 %endif
462 >
464 >
463 %if line.modified.lineno:
465 %if line.modified.lineno:
464 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
466 <a name="${new_line_anchor}" href="#${new_line_anchor}">${line.modified.lineno}</a>
465 %endif
467 %endif
466 </td>
468 </td>
467 <td class="cb-content ${action_class(line.modified.action)}"
469 <td class="cb-content ${action_class(line.modified.action)}"
468 data-line-number="n${line.modified.lineno}"
470 data-line-number="n${line.modified.lineno}"
469 >
471 >
470 %if use_comments and line.modified.lineno:
472 %if use_comments and line.modified.lineno:
471 ${render_add_comment_button()}
473 ${render_add_comment_button()}
472 %endif
474 %endif
473 <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span>
475 <span class="cb-code">${line.modified.action} ${line.modified.content or '' | n}</span>
474 %if use_comments and line.modified.lineno and line.modified.comments:
476 %if use_comments and line.modified.lineno and line.modified.comments:
475 ${inline_comments_container(line.modified.comments)}
477 ${inline_comments_container(line.modified.comments)}
476 %endif
478 %endif
477 </td>
479 </td>
478 </tr>
480 </tr>
479 %endfor
481 %endfor
480 </%def>
482 </%def>
481
483
482
484
483 <%def name="render_hunk_lines_unified(hunk, use_comments=False)">
485 <%def name="render_hunk_lines_unified(hunk, use_comments=False)">
484 %for old_line_no, new_line_no, action, content, comments in hunk.unified:
486 %for old_line_no, new_line_no, action, content, comments in hunk.unified:
485 <%
487 <%
486 old_line_anchor, new_line_anchor = None, None
488 old_line_anchor, new_line_anchor = None, None
487 if old_line_no:
489 if old_line_no:
488 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o')
490 old_line_anchor = diff_line_anchor(hunk.filediff.source_file_path, old_line_no, 'o')
489 if new_line_no:
491 if new_line_no:
490 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
492 new_line_anchor = diff_line_anchor(hunk.filediff.target_file_path, new_line_no, 'n')
491 %>
493 %>
492 <tr class="cb-line">
494 <tr class="cb-line">
493 <td class="cb-data ${action_class(action)}">
495 <td class="cb-data ${action_class(action)}">
494 <div>
496 <div>
495 %if comments:
497 %if comments:
496 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
498 <i class="icon-comment" onclick="return Rhodecode.comments.toggleLineComments(this)"></i>
497 %endif
499 %endif
498 </div>
500 </div>
499 </td>
501 </td>
500 <td class="cb-lineno ${action_class(action)}"
502 <td class="cb-lineno ${action_class(action)}"
501 data-line-number="${old_line_no}"
503 data-line-number="${old_line_no}"
502 %if old_line_anchor:
504 %if old_line_anchor:
503 id="${old_line_anchor}"
505 id="${old_line_anchor}"
504 %endif
506 %endif
505 >
507 >
506 %if old_line_anchor:
508 %if old_line_anchor:
507 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
509 <a name="${old_line_anchor}" href="#${old_line_anchor}">${old_line_no}</a>
508 %endif
510 %endif
509 </td>
511 </td>
510 <td class="cb-lineno ${action_class(action)}"
512 <td class="cb-lineno ${action_class(action)}"
511 data-line-number="${new_line_no}"
513 data-line-number="${new_line_no}"
512 %if new_line_anchor:
514 %if new_line_anchor:
513 id="${new_line_anchor}"
515 id="${new_line_anchor}"
514 %endif
516 %endif
515 >
517 >
516 %if new_line_anchor:
518 %if new_line_anchor:
517 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
519 <a name="${new_line_anchor}" href="#${new_line_anchor}">${new_line_no}</a>
518 %endif
520 %endif
519 </td>
521 </td>
520 <td class="cb-content ${action_class(action)}"
522 <td class="cb-content ${action_class(action)}"
521 data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}"
523 data-line-number="${new_line_no and 'n' or 'o'}${new_line_no or old_line_no}"
522 >
524 >
523 %if use_comments:
525 %if use_comments:
524 ${render_add_comment_button()}
526 ${render_add_comment_button()}
525 %endif
527 %endif
526 <span class="cb-code">${action} ${content or '' | n}</span>
528 <span class="cb-code">${action} ${content or '' | n}</span>
527 %if use_comments and comments:
529 %if use_comments and comments:
528 ${inline_comments_container(comments)}
530 ${inline_comments_container(comments)}
529 %endif
531 %endif
530 </td>
532 </td>
531 </tr>
533 </tr>
532 %endfor
534 %endfor
533 </%def>
535 </%def>
534
536
535 <%def name="render_add_comment_button()">
537 <%def name="render_add_comment_button()">
536 <button
538 <button
537 class="btn btn-small btn-primary cb-comment-box-opener"
539 class="btn btn-small btn-primary cb-comment-box-opener"
538 onclick="return Rhodecode.comments.createComment(this)"
540 onclick="return Rhodecode.comments.createComment(this)"
539 ><span>+</span></button>
541 ><span>+</span></button>
540 </%def>
542 </%def>
541
543
542 <%def name="render_diffset_menu()">
544 <%def name="render_diffset_menu()">
543
545
544 <div class="diffset-menu clearinner">
546 <div class="diffset-menu clearinner">
545 <div class="pull-right">
547 <div class="pull-right">
546 <div class="btn-group">
548 <div class="btn-group">
549
547 <a
550 <a
548 class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip"
551 class="btn ${c.diffmode == 'sideside' and 'btn-primary'} tooltip"
549 title="${_('View side by side')}"
552 title="${_('View side by side')}"
550 href="${h.url_replace(diffmode='sideside')}">
553 href="${h.url_replace(diffmode='sideside')}">
551 <span>${_('Side by Side')}</span>
554 <span>${_('Side by Side')}</span>
552 </a>
555 </a>
553 <a
556 <a
554 class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip"
557 class="btn ${c.diffmode == 'unified' and 'btn-primary'} tooltip"
555 title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}">
558 title="${_('View unified')}" href="${h.url_replace(diffmode='unified')}">
556 <span>${_('Unified')}</span>
559 <span>${_('Unified')}</span>
557 </a>
560 </a>
558 </div>
561 </div>
559 </div>
562 </div>
563
560 <div class="pull-left">
564 <div class="pull-left">
561 <div class="btn-group">
565 <div class="btn-group">
562 <a
566 <a
563 class="btn"
567 class="btn"
564 href="#"
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 <a
570 <a
567 class="btn"
571 class="btn"
568 href="#"
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 <a
574 <a
571 class="btn"
575 class="btn"
572 href="#"
576 href="#"
573 onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode')}</a>
577 onclick="return Rhodecode.comments.toggleWideMode(this)">${_('Wide Mode Diff')}</a>
574 </div>
578 </div>
575 </div>
579 </div>
576 </div>
580 </div>
577 </%def>
581 </%def>
@@ -1,104 +1,113 b''
1 ## Changesets table !
1 ## Changesets table !
2 <%namespace name="base" file="/base/base.html"/>
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 %if c.ancestor:
4 %if c.ancestor:
9 <p class="ancestor">${_('Common Ancestor Commit')}:
5 <div class="ancestor">${_('Common Ancestor Commit')}:
10 <a href="${h.url('changeset_home',
6 <a href="${h.url('changeset_home',
11 repo_name=c.repo_name,
7 repo_name=c.repo_name,
12 revision=c.ancestor)}">
8 revision=c.ancestor)}">
13 ${h.short_id(c.ancestor)}
9 ${h.short_id(c.ancestor)}
14 </a>
10 </a>
15 </p>
11 </div>
16 %endif
12 %endif
17
13
14 <div class="container">
18 <input type="hidden" name="__start__" value="revisions:sequence">
15 <input type="hidden" name="__start__" value="revisions:sequence">
19 <table class="rctable compare_view_commits">
16 <table class="rctable compare_view_commits">
20 <tr>
17 <tr>
21 <th>${_('Time')}</th>
18 <th>${_('Time')}</th>
22 <th>${_('Author')}</th>
19 <th>${_('Author')}</th>
23 <th>${_('Commit')}</th>
20 <th>${_('Commit')}</th>
24 <th></th>
21 <th></th>
25 <th>${_('Description')}</th>
22 <th>${_('Description')}</th>
26 </tr>
23 </tr>
27 %for commit in c.commit_ranges:
24 %for commit in c.commit_ranges:
28 <tr id="row-${commit.raw_id}"
25 <tr id="row-${commit.raw_id}"
29 commit_id="${commit.raw_id}"
26 commit_id="${commit.raw_id}"
30 class="compare_select"
27 class="compare_select"
31 >
28 >
32 <td class="td-time">
29 <td class="td-time">
33 ${h.age_component(commit.date)}
30 ${h.age_component(commit.date)}
34 </td>
31 </td>
35 <td class="td-user">
32 <td class="td-user">
36 ${base.gravatar_with_user(commit.author, 16)}
33 ${base.gravatar_with_user(commit.author, 16)}
37 </td>
34 </td>
38 <td class="td-hash">
35 <td class="td-hash">
39 <code>
36 <code>
40 <a href="${h.url('changeset_home',
37 <a href="${h.url('changeset_home',
41 repo_name=c.target_repo.repo_name,
38 repo_name=c.target_repo.repo_name,
42 revision=commit.raw_id)}">
39 revision=commit.raw_id)}">
43 r${commit.revision}:${h.short_id(commit.raw_id)}
40 r${commit.revision}:${h.short_id(commit.raw_id)}
44 </a>
41 </a>
45 ${h.hidden('revisions',commit.raw_id)}
42 ${h.hidden('revisions',commit.raw_id)}
46 </code>
43 </code>
47 </td>
44 </td>
48 <td class="expand_commit"
45 <td class="expand_commit"
49 data-commit-id="${commit.raw_id}"
46 data-commit-id="${commit.raw_id}"
50 title="${_( 'Expand commit message')}"
47 title="${_( 'Expand commit message')}"
51 >
48 >
52 <div class="show_more_col">
49 <div class="show_more_col">
53 <i class="show_more"></i>
50 <i class="show_more"></i>
54 </div>
51 </div>
55 </td>
52 </td>
56 <td class="mid td-description">
53 <td class="mid td-description">
57 <div class="log-container truncate-wrap">
54 <div class="log-container truncate-wrap">
58 <div
55 <div
59 id="c-${commit.raw_id}"
56 id="c-${commit.raw_id}"
60 class="message truncate"
57 class="message truncate"
61 data-message-raw="${commit.message}"
58 data-message-raw="${commit.message}"
62 >
59 >
63 ${h.urlify_commit_message(commit.message, c.repo_name)}
60 ${h.urlify_commit_message(commit.message, c.repo_name)}
64 </div>
61 </div>
65 </div>
62 </div>
66 </td>
63 </td>
67 </tr>
64 </tr>
68 %endfor
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 </table>
78 </table>
70 <input type="hidden" name="__end__" value="revisions:sequence">
79 <input type="hidden" name="__end__" value="revisions:sequence">
71 %endif
80
72 </div>
81 </div>
73
82
74 <script>
83 <script>
75 $('.expand_commit').on('click',function(e){
84 $('.expand_commit').on('click',function(e){
76 var target_expand = $(this);
85 var target_expand = $(this);
77 var cid = target_expand.data('commitId');
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 if (target_expand.hasClass('open')){
89 if (target_expand.hasClass('open')){
81 $('#c-'+cid).css({
90 $('#c-'+cid).css({
82 'height': '1.5em',
91 'height': '1.5em',
83 'white-space': 'nowrap',
92 'white-space': 'nowrap',
84 'text-overflow': 'ellipsis',
93 'text-overflow': 'ellipsis',
85 'overflow':'hidden'
94 'overflow':'hidden'
86 });
95 });
87 target_expand.removeClass('open');
96 target_expand.removeClass('open');
88 }
97 }
89 else {
98 else {
90 $('#c-'+cid).css({
99 $('#c-'+cid).css({
91 'height': 'auto',
100 'height': 'auto',
92 'white-space': 'pre-line',
101 'white-space': 'pre-line',
93 'text-overflow': 'initial',
102 'text-overflow': 'initial',
94 'overflow':'visible'
103 'overflow':'visible'
95 });
104 });
96 target_expand.addClass('open');
105 target_expand.addClass('open');
97 }
106 }
98 });
107 });
99
108
100 $('.compare_select').on('click',function(e){
109 $('.compare_select').on('click',function(e){
101 var cid = $(this).attr('commit_id');
110 var cid = $(this).attr('commit_id');
102 $('#row-'+cid).toggleClass('hl', !$('#row-'+cid).hasClass('hl'));
111 $('#row-'+cid).toggleClass('hl', !$('#row-'+cid).hasClass('hl'));
103 });
112 });
104 </script>
113 </script>
@@ -1,259 +1,370 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%inherit file="/base/base.html"/>
2 <%inherit file="/base/base.html"/>
3 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
3 <%namespace name="cbdiffs" file="/codeblocks/diffs.html"/>
4
4
5 <%def name="title()">
5 <%def name="title()">
6 %if c.compare_home:
6 %if c.compare_home:
7 ${_('%s Compare') % c.repo_name}
7 ${_('%s Compare') % c.repo_name}
8 %else:
8 %else:
9 ${_('%s Compare') % c.repo_name} - ${'%s@%s' % (c.source_repo.repo_name, c.source_ref)} &gt; ${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}
9 ${_('%s Compare') % c.repo_name} - ${'%s@%s' % (c.source_repo.repo_name, c.source_ref)} &gt; ${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}
10 %endif
10 %endif
11 %if c.rhodecode_name:
11 %if c.rhodecode_name:
12 &middot; ${h.branding(c.rhodecode_name)}
12 &middot; ${h.branding(c.rhodecode_name)}
13 %endif
13 %endif
14 </%def>
14 </%def>
15
15
16 <%def name="breadcrumbs_links()">
16 <%def name="breadcrumbs_links()">
17 ${ungettext('%s commit','%s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
17 ${ungettext('%s commit','%s commits', len(c.commit_ranges)) % len(c.commit_ranges)}
18 </%def>
18 </%def>
19
19
20 <%def name="menu_bar_nav()">
20 <%def name="menu_bar_nav()">
21 ${self.menu_items(active='repositories')}
21 ${self.menu_items(active='repositories')}
22 </%def>
22 </%def>
23
23
24 <%def name="menu_bar_subnav()">
24 <%def name="menu_bar_subnav()">
25 ${self.repo_menu(active='compare')}
25 ${self.repo_menu(active='compare')}
26 </%def>
26 </%def>
27
27
28 <%def name="main()">
28 <%def name="main()">
29 <script type="text/javascript">
29 <script type="text/javascript">
30 // set fake commitId on this commit-range page
30 // set fake commitId on this commit-range page
31 templateContext.commit_data.commit_id = "${h.EmptyCommit().raw_id}";
31 templateContext.commit_data.commit_id = "${h.EmptyCommit().raw_id}";
32 </script>
32 </script>
33
33
34 <div class="box">
34 <div class="box">
35 <div class="title">
35 <div class="title">
36 ${self.repo_page_title(c.rhodecode_db_repo)}
36 ${self.repo_page_title(c.rhodecode_db_repo)}
37 <div class="breadcrumbs">
38 ${_('Compare Commits')}
39 </div>
40 </div>
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 <div class="table">
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 ## use JS script to load it quickly before potentially large diffs render long time
163 ## use JS script to load it quickly before potentially large diffs render long time
66 ## this prevents from situation when large diffs block rendering of select2 fields
164 ## this prevents from situation when large diffs block rendering of select2 fields
67 <script type="text/javascript">
165 <script type="text/javascript">
68
166
69 var cache = {};
167 var cache = {};
70
168
71 var formatSelection = function(repoName){
169 var formatSelection = function(repoName){
72 return function(data, container, escapeMarkup) {
170 return function(data, container, escapeMarkup) {
73 var selection = data ? this.text(data) : "";
171 var selection = data ? this.text(data) : "";
74 return escapeMarkup('{0}@{1}'.format(repoName, selection));
172 return escapeMarkup('{0}@{1}'.format(repoName, selection));
75 }
173 }
76 };
174 };
77
175
78 var feedCompareData = function(query, cachedValue){
176 var feedCompareData = function(query, cachedValue){
79 var data = {results: []};
177 var data = {results: []};
80 //filter results
178 //filter results
81 $.each(cachedValue.results, function() {
179 $.each(cachedValue.results, function() {
82 var section = this.text;
180 var section = this.text;
83 var children = [];
181 var children = [];
84 $.each(this.children, function() {
182 $.each(this.children, function() {
85 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
183 if (query.term.length === 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0) {
86 children.push({
184 children.push({
87 'id': this.id,
185 'id': this.id,
88 'text': this.text,
186 'text': this.text,
89 'type': this.type
187 'type': this.type
90 })
188 })
91 }
189 }
92 });
190 });
93 data.results.push({
191 data.results.push({
94 'text': section,
192 'text': section,
95 'children': children
193 'children': children
96 })
194 })
97 });
195 });
98 //push the typed in changeset
196 //push the typed in changeset
99 data.results.push({
197 data.results.push({
100 'text': _gettext('specify commit'),
198 'text': _gettext('specify commit'),
101 'children': [{
199 'children': [{
102 'id': query.term,
200 'id': query.term,
103 'text': query.term,
201 'text': query.term,
104 'type': 'rev'
202 'type': 'rev'
105 }]
203 }]
106 });
204 });
107 query.callback(data);
205 query.callback(data);
108 };
206 };
109
207
110 var loadCompareData = function(repoName, query, cache){
208 var loadCompareData = function(repoName, query, cache){
111 $.ajax({
209 $.ajax({
112 url: pyroutes.url('repo_refs_data', {'repo_name': repoName}),
210 url: pyroutes.url('repo_refs_data', {'repo_name': repoName}),
113 data: {},
211 data: {},
114 dataType: 'json',
212 dataType: 'json',
115 type: 'GET',
213 type: 'GET',
116 success: function(data) {
214 success: function(data) {
117 cache[repoName] = data;
215 cache[repoName] = data;
118 query.callback({results: data.results});
216 query.callback({results: data.results});
119 }
217 }
120 })
218 })
121 };
219 };
122
220
123 var enable_fields = ${"false" if c.preview_mode else "true"};
221 var enable_fields = ${"false" if c.preview_mode else "true"};
124 $("#compare_source").select2({
222 $("#compare_source").select2({
125 placeholder: "${'%s@%s' % (c.source_repo.repo_name, c.source_ref)}",
223 placeholder: "${'%s@%s' % (c.source_repo.repo_name, c.source_ref)}",
126 containerCssClass: "drop-menu",
224 containerCssClass: "drop-menu",
127 dropdownCssClass: "drop-menu-dropdown",
225 dropdownCssClass: "drop-menu-dropdown",
128 formatSelection: formatSelection("${c.source_repo.repo_name}"),
226 formatSelection: formatSelection("${c.source_repo.repo_name}"),
129 dropdownAutoWidth: true,
227 dropdownAutoWidth: true,
130 query: function(query) {
228 query: function(query) {
131 var repoName = '${c.source_repo.repo_name}';
229 var repoName = '${c.source_repo.repo_name}';
132 var cachedValue = cache[repoName];
230 var cachedValue = cache[repoName];
133
231
134 if (cachedValue){
232 if (cachedValue){
135 feedCompareData(query, cachedValue);
233 feedCompareData(query, cachedValue);
136 }
234 }
137 else {
235 else {
138 loadCompareData(repoName, query, cache);
236 loadCompareData(repoName, query, cache);
139 }
237 }
140 }
238 }
141 }).select2("enable", enable_fields);
239 }).select2("enable", enable_fields);
142
240
143 $("#compare_target").select2({
241 $("#compare_target").select2({
144 placeholder: "${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}",
242 placeholder: "${'%s@%s' % (c.target_repo.repo_name, c.target_ref)}",
145 dropdownAutoWidth: true,
243 dropdownAutoWidth: true,
146 containerCssClass: "drop-menu",
244 containerCssClass: "drop-menu",
147 dropdownCssClass: "drop-menu-dropdown",
245 dropdownCssClass: "drop-menu-dropdown",
148 formatSelection: formatSelection("${c.target_repo.repo_name}"),
246 formatSelection: formatSelection("${c.target_repo.repo_name}"),
149 query: function(query) {
247 query: function(query) {
150 var repoName = '${c.target_repo.repo_name}';
248 var repoName = '${c.target_repo.repo_name}';
151 var cachedValue = cache[repoName];
249 var cachedValue = cache[repoName];
152
250
153 if (cachedValue){
251 if (cachedValue){
154 feedCompareData(query, cachedValue);
252 feedCompareData(query, cachedValue);
155 }
253 }
156 else {
254 else {
157 loadCompareData(repoName, query, cache);
255 loadCompareData(repoName, query, cache);
158 }
256 }
159 }
257 }
160 }).select2("enable", enable_fields);
258 }).select2("enable", enable_fields);
161 var initial_compare_source = {id: "${c.source_ref}", type:"${c.source_ref_type}"};
259 var initial_compare_source = {id: "${c.source_ref}", type:"${c.source_ref_type}"};
162 var initial_compare_target = {id: "${c.target_ref}", type:"${c.target_ref_type}"};
260 var initial_compare_target = {id: "${c.target_ref}", type:"${c.target_ref_type}"};
163
261
164 $('#compare_revs').on('click', function(e) {
262 $('#compare_revs').on('click', function(e) {
165 var source = $('#compare_source').select2('data') || initial_compare_source;
263 var source = $('#compare_source').select2('data') || initial_compare_source;
166 var target = $('#compare_target').select2('data') || initial_compare_target;
264 var target = $('#compare_target').select2('data') || initial_compare_target;
167 if (source && target) {
265 if (source && target) {
168 var url_data = {
266 var url_data = {
169 repo_name: "${c.repo_name}",
267 repo_name: "${c.repo_name}",
170 source_ref: source.id,
268 source_ref: source.id,
171 source_ref_type: source.type,
269 source_ref_type: source.type,
172 target_ref: target.id,
270 target_ref: target.id,
173 target_ref_type: target.type
271 target_ref_type: target.type
174 };
272 };
175 window.location = pyroutes.url('compare_url', url_data);
273 window.location = pyroutes.url('compare_url', url_data);
176 }
274 }
177 });
275 });
178 $('#compare_changeset_status_toggle').on('click', function(e) {
276 $('#compare_changeset_status_toggle').on('click', function(e) {
179 $('#compare_changeset_status').toggle();
277 $('#compare_changeset_status').toggle();
180 });
278 });
181
279
182 </script>
280 </script>
183
281
184 ## changeset status form
282 ## changeset status form
185 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
283 <%namespace name="comment" file="/changeset/changeset_file_comment.html"/>
186 ## main comment form and it status
284 ## main comment form and it status
187 <%
285 <%
188 def revs(_revs):
286 def revs(_revs):
189 form_inputs = []
287 form_inputs = []
190 for cs in _revs:
288 for cs in _revs:
191 tmpl = '<input type="hidden" data-commit-id="%(cid)s" name="commit_ids" value="%(cid)s">' % {'cid': cs.raw_id}
289 tmpl = '<input type="hidden" data-commit-id="%(cid)s" name="commit_ids" value="%(cid)s">' % {'cid': cs.raw_id}
192 form_inputs.append(tmpl)
290 form_inputs.append(tmpl)
193 return form_inputs
291 return form_inputs
194 %>
292 %>
195 <div id="compare_changeset_status" style="display: none;">
293 <div id="compare_changeset_status" style="display: none;">
196 ${comment.comments(h.url('changeset_comment', repo_name=c.repo_name, revision='0'*16), None, is_compare=True, form_extras=revs(c.commit_ranges))}
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 <script type="text/javascript">
295 <script type="text/javascript">
198
296
199 mainCommentForm.setHandleFormSubmit(function(o) {
297 mainCommentForm.setHandleFormSubmit(function(o) {
200 var text = mainCommentForm.cm.getValue();
298 var text = mainCommentForm.cm.getValue();
201 var status = mainCommentForm.getCommentStatus();
299 var status = mainCommentForm.getCommentStatus();
202
300
203 if (text === "" && !status) {
301 if (text === "" && !status) {
204 return;
302 return;
205 }
303 }
206
304
207 // we can pick which commits we want to make the comment by
305 // we can pick which commits we want to make the comment by
208 // selecting them via click on preview pane, this will alter the hidden inputs
306 // selecting them via click on preview pane, this will alter the hidden inputs
209 var cherryPicked = $('#changeset_compare_view_content .compare_select.hl').length > 0;
307 var cherryPicked = $('#changeset_compare_view_content .compare_select.hl').length > 0;
210
308
211 var commitIds = [];
309 var commitIds = [];
212 $('#changeset_compare_view_content .compare_select').each(function(el) {
310 $('#changeset_compare_view_content .compare_select').each(function(el) {
213 var commitId = this.id.replace('row-', '');
311 var commitId = this.id.replace('row-', '');
214 if ($(this).hasClass('hl') || !cherryPicked) {
312 if ($(this).hasClass('hl') || !cherryPicked) {
215 $("input[data-commit-id='{0}']".format(commitId)).val(commitId)
313 $("input[data-commit-id='{0}']".format(commitId)).val(commitId)
216 commitIds.push(commitId);
314 commitIds.push(commitId);
217 } else {
315 } else {
218 $("input[data-commit-id='{0}']".format(commitId)).val('')
316 $("input[data-commit-id='{0}']".format(commitId)).val('')
219 }
317 }
220 });
318 });
221
319
222 mainCommentForm.setActionButtonsDisabled(true);
320 mainCommentForm.setActionButtonsDisabled(true);
223 mainCommentForm.cm.setOption("readOnly", true);
321 mainCommentForm.cm.setOption("readOnly", true);
224 var postData = {
322 var postData = {
225 'text': text,
323 'text': text,
226 'changeset_status': status,
324 'changeset_status': status,
227 'commit_ids': commitIds,
325 'commit_ids': commitIds,
228 'csrf_token': CSRF_TOKEN
326 'csrf_token': CSRF_TOKEN
229 };
327 };
230
328
231 var submitSuccessCallback = function(o) {
329 var submitSuccessCallback = function(o) {
232 location.reload(true);
330 location.reload(true);
233 };
331 };
234 var submitFailCallback = function(){
332 var submitFailCallback = function(){
235 mainCommentForm.resetCommentFormState(text)
333 mainCommentForm.resetCommentFormState(text)
236 };
334 };
237 mainCommentForm.submitAjaxPOST(
335 mainCommentForm.submitAjaxPOST(
238 mainCommentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
336 mainCommentForm.submitUrl, postData, submitSuccessCallback, submitFailCallback);
239 });
337 });
240 </script>
338 </script>
241
339
242 </div>
340 </div>
243
341
244 %if c.compare_home:
342 %if not c.compare_home:
245 <div id="changeset_compare_view_content">
343 <div id="changeset_compare_view_content">
246 <div class="help-block">${_('Compare commits, branches, bookmarks or tags.')}</div>
344 <div class="pull-left">
247 </div>
345 <div class="btn-group">
248 %else:
346 <a
249 <div id="changeset_compare_view_content">
347 class="btn"
250 ##CS
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 <%include file="compare_commits.html"/>
362 <%include file="compare_commits.html"/>
252 ${cbdiffs.render_diffset_menu()}
363 ${cbdiffs.render_diffset_menu()}
253 ${cbdiffs.render_diffset(c.diffset)}
364 ${cbdiffs.render_diffset(c.diffset)}
254 </div>
365 </div>
255 %endif
366 %endif
256 </div>
367 </div>
257 </div>
368 </div>
258 </div>
369 </div>
259 </%def>
370 </%def>
@@ -1,1162 +1,1160 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.html"/>
2 <%namespace name="base" file="/base/base.html"/>
3 <%inherit file="/debug_style/index.html"/>
3 <%inherit file="/debug_style/index.html"/>
4
4
5 <%def name="breadcrumbs_links()">
5 <%def name="breadcrumbs_links()">
6 ${h.link_to(_('Style'), h.url('debug_style_home'))}
6 ${h.link_to(_('Style'), h.url('debug_style_home'))}
7 &raquo;
7 &raquo;
8 ${c.active}
8 ${c.active}
9 </%def>
9 </%def>
10
10
11 <%def name="js_extra()">
11 <%def name="js_extra()">
12 <script type="text/javascript" src="${h.asset('js/mergerly.js', ver=c.rhodecode_version_hash)}"></script>
13 </%def>
12 </%def>
14
13
15 <%def name="css_extra()">
14 <%def name="css_extra()">
16 <link rel="stylesheet" type="text/css" href="${h.asset('css/mergerly.css', ver=c.rhodecode_version_hash)}"/>
17 </%def>
15 </%def>
18
16
19
17
20 <%def name="real_main()">
18 <%def name="real_main()">
21 <div class="box">
19 <div class="box">
22 <div class="title">
20 <div class="title">
23 ${self.breadcrumbs()}
21 ${self.breadcrumbs()}
24 </div>
22 </div>
25
23
26 ##main
24 ##main
27 <div class='sidebar-col-wrapper'>
25 <div class='sidebar-col-wrapper'>
28 ${self.sidebar()}
26 ${self.sidebar()}
29
27
30 <div class="main-content">
28 <div class="main-content">
31
29
32
30
33
31
34 <h2>Code Blocks</h2>
32 <h2>Code Blocks</h2>
35
33
36 <dl class="dl-horizontal">
34 <dl class="dl-horizontal">
37 <dt><code>.codeblock</code></dt>
35 <dt><code>.codeblock</code></dt>
38 <dd>Used as a wrapping element around <code>.code-header</code> and
36 <dd>Used as a wrapping element around <code>.code-header</code> and
39 <code>.code-body</code>. Used to show the content of a file or a
37 <code>.code-body</code>. Used to show the content of a file or a
40 Gist.</dd>
38 Gist.</dd>
41
39
42 <dt><code>.diffblock</code></dt>
40 <dt><code>.diffblock</code></dt>
43 <dd>Used as a wrapping element to show a diff in a Commit or Pull
41 <dd>Used as a wrapping element to show a diff in a Commit or Pull
44 Request page. Contains usually <code>.code-header</code>,
42 Request page. Contains usually <code>.code-header</code>,
45 <code>.code-body</code> and in the edit case a <code>.message</code>.
43 <code>.code-body</code> and in the edit case a <code>.message</code>.
46 </dd>
44 </dd>
47 </dl>
45 </dl>
48
46
49
47
50 <p>Code Blocks are used in the following areas:</p>
48 <p>Code Blocks are used in the following areas:</p>
51
49
52 <ul>
50 <ul>
53 <li>Commit: Showing the Diff (still called Changeset in a few
51 <li>Commit: Showing the Diff (still called Changeset in a few
54 places).</li>
52 places).</li>
55 <li>File: Display a file, annotations, and edit a file.</li>
53 <li>File: Display a file, annotations, and edit a file.</li>
56 <li>Gist: Show the Gist and edit it.</li>
54 <li>Gist: Show the Gist and edit it.</li>
57 <li>Pull Request: Display the Diff of a Pull Request.</li>
55 <li>Pull Request: Display the Diff of a Pull Request.</li>
58 </ul>
56 </ul>
59
57
60
58
61
59
62 <!--
60 <!--
63 Compare Commits
61 Compare Commits
64 -->
62 -->
65 <h2>Compare Commits</h2>
63 <h2>Compare Commits</h2>
66
64
67 <div id="c-e589e34d6be8-5ab783e6d81b" class="diffblock margined comm">
65 <div id="c-e589e34d6be8-5ab783e6d81b" class="diffblock margined comm">
68 <div class="code-header">
66 <div class="code-header">
69 <div title="Go back to changed files overview">
67 <div title="Go back to changed files overview">
70 <a href="#changes_box">
68 <a href="#changes_box">
71 <i class="icon-circle-arrow-up"></i>
69 <i class="icon-circle-arrow-up"></i>
72 </a>
70 </a>
73 </div>
71 </div>
74 <div class="changeset_header">
72 <div class="changeset_header">
75 <div class="changeset_file">
73 <div class="changeset_file">
76 <i class="icon-file"></i>
74 <i class="icon-file"></i>
77 <a href="/example/files/e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d/rhodecode/public/css/code-block.less">rhodecode/public/css/code-block.less</a>
75 <a href="/example/files/e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d/rhodecode/public/css/code-block.less">rhodecode/public/css/code-block.less</a>
78 </div>
76 </div>
79 <div class="diff-actions">
77 <div class="diff-actions">
80 <a href="/example/diff/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full diff for this file">
78 <a href="/example/diff/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full diff for this file">
81 <img class="icon" src="/images/icons/page_white_go.png">
79 <img class="icon" src="/images/icons/page_white_go.png">
82 </a>
80 </a>
83 <a href="/example/diff-2way/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full side-by-side diff for this file">
81 <a href="/example/diff-2way/rhodecode/public/css/code-block.less?fulldiff=1&amp;diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=diff&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Show full side-by-side diff for this file">
84 <img class="icon" src="/images/icons/application_double.png">
82 <img class="icon" src="/images/icons/application_double.png">
85 </a>
83 </a>
86 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=raw&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Raw diff" tt_title="Raw diff">
84 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=raw&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Raw diff" tt_title="Raw diff">
87 <img class="icon" src="/images/icons/page_white.png">
85 <img class="icon" src="/images/icons/page_white.png">
88 </a>
86 </a>
89 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=download&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Download diff">
87 <a href="/example/diff/rhodecode/public/css/code-block.less?diff1=d12301bafcc0aea15c9283d3af018daee2b04cd9&amp;diff=download&amp;diff2=e589e34d6be8ec2b44017f6c2e0bbe782f1aba6d" class="tooltip" title="Download diff">
90 <img class="icon" src="/images/icons/page_save.png">
88 <img class="icon" src="/images/icons/page_save.png">
91 </a>
89 </a>
92 <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=WS%3A1&amp;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>
90 <a class="tooltip" href="/example/changeset/d12301bafcc0aea15c9283d3af018daee2b04cd9...80ead1899f50a894889e19ffeb49c9cebf5bf045?c-e589e34d6be8-5ab783e6d81b=WS%3A1&amp;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 <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>
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 </div>
92 </div>
95 <span>
93 <span>
96 <label>
94 <label>
97 Show inline comments
95 Show inline comments
98 <input checked="checked" class="show-inline-comments" id="" id_for="c-e589e34d6be8-5ab783e6d81b" name="" type="checkbox" value="1">
96 <input checked="checked" class="show-inline-comments" id="" id_for="c-e589e34d6be8-5ab783e6d81b" name="" type="checkbox" value="1">
99 </label>
97 </label>
100 </span>
98 </span>
101 </div>
99 </div>
102 </div>
100 </div>
103 <div class="code-body">
101 <div class="code-body">
104 <div class="full_f_path" path="rhodecode/public/css/code-block.less"></div>
102 <div class="full_f_path" path="rhodecode/public/css/code-block.less"></div>
105 <table class="code-difftable">
103 <table class="code-difftable">
106 <tbody><tr class="line context">
104 <tbody><tr class="line context">
107 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
105 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
108 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
106 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
109 <td class="code no-comment">
107 <td class="code no-comment">
110 <pre>@@ -391,7 +391,7 @@
108 <pre>@@ -391,7 +391,7 @@
111 </pre>
109 </pre>
112 </td>
110 </td>
113 </tr>
111 </tr>
114 <tr class="line unmod">
112 <tr class="line unmod">
115 <td id="rhodecodepubliccsscode-blockless_o391" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o391">391</a></td>
113 <td id="rhodecodepubliccsscode-blockless_o391" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o391">391</a></td>
116 <td id="rhodecodepubliccsscode-blockless_n391" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n391">391</a></td>
114 <td id="rhodecodepubliccsscode-blockless_n391" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n391">391</a></td>
117 <td class="code no-comment">
115 <td class="code no-comment">
118 <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.
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 </pre>
117 </pre>
120 </td>
118 </td>
121 </tr>
119 </tr>
122 <tr class="line unmod">
120 <tr class="line unmod">
123 <td id="rhodecodepubliccsscode-blockless_o392" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o392">392</a></td>
121 <td id="rhodecodepubliccsscode-blockless_o392" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o392">392</a></td>
124 <td id="rhodecodepubliccsscode-blockless_n392" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n392">392</a></td>
122 <td id="rhodecodepubliccsscode-blockless_n392" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n392">392</a></td>
125 <td class="code no-comment">
123 <td class="code no-comment">
126 <pre></pre>
124 <pre></pre>
127 </td>
125 </td>
128 </tr>
126 </tr>
129 <tr class="line unmod">
127 <tr class="line unmod">
130 <td id="rhodecodepubliccsscode-blockless_o393" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o393">393</a></td>
128 <td id="rhodecodepubliccsscode-blockless_o393" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o393">393</a></td>
131 <td id="rhodecodepubliccsscode-blockless_n393" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n393">393</a></td>
129 <td id="rhodecodepubliccsscode-blockless_n393" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n393">393</a></td>
132 <td class="code no-comment">
130 <td class="code no-comment">
133 <pre>.code-body.textarea.editor,
131 <pre>.code-body.textarea.editor,
134 </pre>
132 </pre>
135 </td>
133 </td>
136 </tr>
134 </tr>
137 <tr class="line del">
135 <tr class="line del">
138 <td id="rhodecodepubliccsscode-blockless_o394" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o394">394</a></td>
136 <td id="rhodecodepubliccsscode-blockless_o394" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o394">394</a></td>
139 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n"></a></td>
137 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n"></a></td>
140 <td class="code no-comment">
138 <td class="code no-comment">
141 <pre>div.code-body{
139 <pre>div.code-body{
142 </pre>
140 </pre>
143 </td>
141 </td>
144 </tr>
142 </tr>
145 <tr class="line add">
143 <tr class="line add">
146 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
144 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
147 <td id="rhodecodepubliccsscode-blockless_n394" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n394">394</a></td>
145 <td id="rhodecodepubliccsscode-blockless_n394" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n394">394</a></td>
148 <td class="code no-comment">
146 <td class="code no-comment">
149 <pre>div.code-body<ins> </ins>{
147 <pre>div.code-body<ins> </ins>{
150 </pre>
148 </pre>
151 </td>
149 </td>
152 </tr>
150 </tr>
153 <tr class="line unmod">
151 <tr class="line unmod">
154 <td id="rhodecodepubliccsscode-blockless_o395" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o395">395</a></td>
152 <td id="rhodecodepubliccsscode-blockless_o395" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o395">395</a></td>
155 <td id="rhodecodepubliccsscode-blockless_n395" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n395">395</a></td>
153 <td id="rhodecodepubliccsscode-blockless_n395" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n395">395</a></td>
156 <td class="code no-comment">
154 <td class="code no-comment">
157 <pre> float: left;
155 <pre> float: left;
158 </pre>
156 </pre>
159 </td>
157 </td>
160 </tr>
158 </tr>
161 <tr class="line unmod">
159 <tr class="line unmod">
162 <td id="rhodecodepubliccsscode-blockless_o396" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o396">396</a></td>
160 <td id="rhodecodepubliccsscode-blockless_o396" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o396">396</a></td>
163 <td id="rhodecodepubliccsscode-blockless_n396" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n396">396</a></td>
161 <td id="rhodecodepubliccsscode-blockless_n396" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n396">396</a></td>
164 <td class="code no-comment">
162 <td class="code no-comment">
165 <pre> position: relative;
163 <pre> position: relative;
166 </pre>
164 </pre>
167 </td>
165 </td>
168 </tr>
166 </tr>
169 <tr class="line unmod">
167 <tr class="line unmod">
170 <td id="rhodecodepubliccsscode-blockless_o397" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o397">397</a></td>
168 <td id="rhodecodepubliccsscode-blockless_o397" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o397">397</a></td>
171 <td id="rhodecodepubliccsscode-blockless_n397" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n397">397</a></td>
169 <td id="rhodecodepubliccsscode-blockless_n397" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n397">397</a></td>
172 <td class="code no-comment">
170 <td class="code no-comment">
173 <pre> max-width: none;
171 <pre> max-width: none;
174 </pre>
172 </pre>
175 </td>
173 </td>
176 </tr>
174 </tr>
177 <tr class="line context">
175 <tr class="line context">
178 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
176 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
179 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
177 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
180 <td class="code no-comment">
178 <td class="code no-comment">
181 <pre>@@ -399,3 +399,6 @@
179 <pre>@@ -399,3 +399,6 @@
182 </pre>
180 </pre>
183 </td>
181 </td>
184 </tr>
182 </tr>
185 <tr class="line unmod">
183 <tr class="line unmod">
186 <td id="rhodecodepubliccsscode-blockless_o399" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o399">399</a></td>
184 <td id="rhodecodepubliccsscode-blockless_o399" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o399">399</a></td>
187 <td id="rhodecodepubliccsscode-blockless_n399" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n399">399</a></td>
185 <td id="rhodecodepubliccsscode-blockless_n399" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n399">399</a></td>
188 <td class="code no-comment">
186 <td class="code no-comment">
189 <pre> box-sizing: border-box;
187 <pre> box-sizing: border-box;
190 </pre>
188 </pre>
191 </td>
189 </td>
192 </tr>
190 </tr>
193 <tr class="line unmod">
191 <tr class="line unmod">
194 <td id="rhodecodepubliccsscode-blockless_o400" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o400">400</a></td>
192 <td id="rhodecodepubliccsscode-blockless_o400" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o400">400</a></td>
195 <td id="rhodecodepubliccsscode-blockless_n400" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n400">400</a></td>
193 <td id="rhodecodepubliccsscode-blockless_n400" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n400">400</a></td>
196 <td class="code no-comment">
194 <td class="code no-comment">
197 <pre>}
195 <pre>}
198 </pre>
196 </pre>
199 </td>
197 </td>
200 </tr>
198 </tr>
201 <tr class="line unmod">
199 <tr class="line unmod">
202 <td id="rhodecodepubliccsscode-blockless_o401" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o401">401</a></td>
200 <td id="rhodecodepubliccsscode-blockless_o401" class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o401">401</a></td>
203 <td id="rhodecodepubliccsscode-blockless_n401" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n401">401</a></td>
201 <td id="rhodecodepubliccsscode-blockless_n401" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n401">401</a></td>
204 <td class="code no-comment">
202 <td class="code no-comment">
205 <pre></pre>
203 <pre></pre>
206 </td>
204 </td>
207 </tr>
205 </tr>
208 <tr class="line add">
206 <tr class="line add">
209 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
207 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
210 <td id="rhodecodepubliccsscode-blockless_n402" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n402">402</a></td>
208 <td id="rhodecodepubliccsscode-blockless_n402" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n402">402</a></td>
211 <td class="code no-comment">
209 <td class="code no-comment">
212 <pre>.code-body td{
210 <pre>.code-body td{
213 </pre>
211 </pre>
214 </td>
212 </td>
215 </tr>
213 </tr>
216 <tr class="line add">
214 <tr class="line add">
217 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
215 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
218 <td id="rhodecodepubliccsscode-blockless_n403" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n403">403</a></td>
216 <td id="rhodecodepubliccsscode-blockless_n403" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n403">403</a></td>
219 <td class="code no-comment">
217 <td class="code no-comment">
220 <pre> line-height: 1.2em;
218 <pre> line-height: 1.2em;
221 </pre>
219 </pre>
222 </td>
220 </td>
223 </tr>
221 </tr>
224 <tr class="line add">
222 <tr class="line add">
225 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
223 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o"></a></td>
226 <td id="rhodecodepubliccsscode-blockless_n404" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n404">404</a></td>
224 <td id="rhodecodepubliccsscode-blockless_n404" class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n404">404</a></td>
227 <td class="code no-comment">
225 <td class="code no-comment">
228 <pre>}
226 <pre>}
229 </pre>
227 </pre>
230 </td>
228 </td>
231 </tr>
229 </tr>
232 <tr class="line context">
230 <tr class="line context">
233 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
231 <td class="lineno old"><a href="#rhodecodepubliccsscode-blockless_o...">...</a></td>
234 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
232 <td class="lineno new"><a href="#rhodecodepubliccsscode-blockless_n...">...</a></td>
235 <td class="code no-comment">
233 <td class="code no-comment">
236 <pre> No newline at end of file
234 <pre> No newline at end of file
237 </pre>
235 </pre>
238 </td>
236 </td>
239 </tr>
237 </tr>
240 </tbody></table>
238 </tbody></table>
241 </div>
239 </div>
242 </div>
240 </div>
243
241
244
242
245
243
246
244
247
245
248
246
249 <!--
247 <!--
250 Pull Request
248 Pull Request
251 -->
249 -->
252
250
253 <h2>Pull Request</h2>
251 <h2>Pull Request</h2>
254
252
255 <div class="cs_files">
253 <div class="cs_files">
256 <table class="compare_view_files">
254 <table class="compare_view_files">
257
255
258 <tbody><tr class="cs_M collapse_file" fid="c--5f1d017cf13b">
256 <tbody><tr class="cs_M collapse_file" fid="c--5f1d017cf13b">
259 <td class="cs_icon_td">
257 <td class="cs_icon_td">
260 <span class="collapse_file_icon" fid="c--5f1d017cf13b"></span>
258 <span class="collapse_file_icon" fid="c--5f1d017cf13b"></span>
261 </td>
259 </td>
262 <td class="cs_icon_td">
260 <td class="cs_icon_td">
263 <div class="flag_status not_reviewed hidden"></div>
261 <div class="flag_status not_reviewed hidden"></div>
264 </td>
262 </td>
265 <td id="a_c--5f1d017cf13b">
263 <td id="a_c--5f1d017cf13b">
266 <a class="compare_view_filepath" href="#a_c--5f1d017cf13b">
264 <a class="compare_view_filepath" href="#a_c--5f1d017cf13b">
267 rhodecode/public/css/main.less
265 rhodecode/public/css/main.less
268 </a>
266 </a>
269 <span id="diff_c--5f1d017cf13b" class="diff_links" style="">
267 <span id="diff_c--5f1d017cf13b" class="diff_links" style="">
270 <a href="/example/diff/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
268 <a href="/example/diff/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
271 Unified Diff
269 Unified Diff
272 </a>
270 </a>
273 |
271 |
274 <a href="/example/diff-2way/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
272 <a href="/example/diff-2way/rhodecode/public/css/main.less?fulldiff=1&amp;diff1=f73e9946825c8a7ef2c1178cd1e67986d5831f8f&amp;diff=diff&amp;diff2=27eb56cf467ca849112536d62decb2ed020b3ebc">
275 Side-by-side Diff
273 Side-by-side Diff
276 </a>
274 </a>
277 </span>
275 </span>
278 </td>
276 </td>
279 <td>
277 <td>
280 <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>
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 <div class="comment-bubble pull-right" data-path="rhodecode/public/css/main.less">
279 <div class="comment-bubble pull-right" data-path="rhodecode/public/css/main.less">
282 <i class="icon-comment"></i>
280 <i class="icon-comment"></i>
283 </div>
281 </div>
284 </td>
282 </td>
285 </tr>
283 </tr>
286 <tr id="tr_c--5f1d017cf13b">
284 <tr id="tr_c--5f1d017cf13b">
287 <td></td>
285 <td></td>
288 <td></td>
286 <td></td>
289 <td class="injected_diff" colspan="2">
287 <td class="injected_diff" colspan="2">
290
288
291 <div class="diff-container" id="diff-container-140360026534904">
289 <div class="diff-container" id="diff-container-140360026534904">
292 <div id="c--5f1d017cf13b_target"></div>
290 <div id="c--5f1d017cf13b_target"></div>
293 <div id="c--5f1d017cf13b" class="diffblock margined comm">
291 <div id="c--5f1d017cf13b" class="diffblock margined comm">
294 <div class="code-body">
292 <div class="code-body">
295 <div class="full_f_path" path="rhodecode/public/css/main.less" style="display: none;"></div>
293 <div class="full_f_path" path="rhodecode/public/css/main.less" style="display: none;"></div>
296 <table class="code-difftable">
294 <table class="code-difftable">
297 <tbody><tr class="line context">
295 <tbody><tr class="line context">
298 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
296 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
299 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
297 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
300 <td class="code ">
298 <td class="code ">
301 <pre>@@ -2110,7 +2110,6 @@
299 <pre>@@ -2110,7 +2110,6 @@
302 </pre>
300 </pre>
303 </td>
301 </td>
304 </tr>
302 </tr>
305 <tr class="line unmod">
303 <tr class="line unmod">
306 <td id="rhodecodepubliccssmainless_o2110" class="lineno old"><a href="#rhodecodepubliccssmainless_o2110">2110</a></td>
304 <td id="rhodecodepubliccssmainless_o2110" class="lineno old"><a href="#rhodecodepubliccssmainless_o2110">2110</a></td>
307 <td id="rhodecodepubliccssmainless_n2110" class="lineno new"><a href="#rhodecodepubliccssmainless_n2110">2110</a></td>
305 <td id="rhodecodepubliccssmainless_n2110" class="lineno new"><a href="#rhodecodepubliccssmainless_n2110">2110</a></td>
308 <td class="code ">
306 <td class="code ">
309 <pre><span class="tab-escape"> </span>width: auto !important;
307 <pre><span class="tab-escape"> </span>width: auto !important;
310 </pre>
308 </pre>
311 </td>
309 </td>
312 </tr>
310 </tr>
313 <tr class="line unmod">
311 <tr class="line unmod">
314 <td id="rhodecodepubliccssmainless_o2111" class="lineno old"><a href="#rhodecodepubliccssmainless_o2111">2111</a></td>
312 <td id="rhodecodepubliccssmainless_o2111" class="lineno old"><a href="#rhodecodepubliccssmainless_o2111">2111</a></td>
315 <td id="rhodecodepubliccssmainless_n2111" class="lineno new"><a href="#rhodecodepubliccssmainless_n2111">2111</a></td>
313 <td id="rhodecodepubliccssmainless_n2111" class="lineno new"><a href="#rhodecodepubliccssmainless_n2111">2111</a></td>
316 <td class="code ">
314 <td class="code ">
317 <pre><span class="tab-escape"> </span>min-width: 160px;
315 <pre><span class="tab-escape"> </span>min-width: 160px;
318 </pre>
316 </pre>
319 </td>
317 </td>
320 </tr>
318 </tr>
321 <tr class="line unmod">
319 <tr class="line unmod">
322 <td id="rhodecodepubliccssmainless_o2112" class="lineno old"><a href="#rhodecodepubliccssmainless_o2112">2112</a></td>
320 <td id="rhodecodepubliccssmainless_o2112" class="lineno old"><a href="#rhodecodepubliccssmainless_o2112">2112</a></td>
323 <td id="rhodecodepubliccssmainless_n2112" class="lineno new"><a href="#rhodecodepubliccssmainless_n2112">2112</a></td>
321 <td id="rhodecodepubliccssmainless_n2112" class="lineno new"><a href="#rhodecodepubliccssmainless_n2112">2112</a></td>
324 <td class="code ">
322 <td class="code ">
325 <pre><span class="tab-escape"> </span>margin: @padding @padding @padding 0;
323 <pre><span class="tab-escape"> </span>margin: @padding @padding @padding 0;
326 </pre>
324 </pre>
327 </td>
325 </td>
328 </tr>
326 </tr>
329 <tr class="line del">
327 <tr class="line del">
330 <td id="rhodecodepubliccssmainless_o2113" class="lineno old"><a href="#rhodecodepubliccssmainless_o2113">2113</a></td>
328 <td id="rhodecodepubliccssmainless_o2113" class="lineno old"><a href="#rhodecodepubliccssmainless_o2113">2113</a></td>
331 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
329 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
332 <td class="code ">
330 <td class="code ">
333 <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. */
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 </pre>
332 </pre>
335 </td>
333 </td>
336 </tr>
334 </tr>
337 <tr class="line unmod">
335 <tr class="line unmod">
338 <td id="rhodecodepubliccssmainless_o2114" class="lineno old"><a href="#rhodecodepubliccssmainless_o2114">2114</a></td>
336 <td id="rhodecodepubliccssmainless_o2114" class="lineno old"><a href="#rhodecodepubliccssmainless_o2114">2114</a></td>
339 <td id="rhodecodepubliccssmainless_n2113" class="lineno new"><a href="#rhodecodepubliccssmainless_n2113">2113</a></td>
337 <td id="rhodecodepubliccssmainless_n2113" class="lineno new"><a href="#rhodecodepubliccssmainless_n2113">2113</a></td>
340 <td class="code ">
338 <td class="code ">
341 <pre> line-height: 1em;
339 <pre> line-height: 1em;
342 </pre>
340 </pre>
343 </td>
341 </td>
344 </tr>
342 </tr>
345 <tr class="line unmod">
343 <tr class="line unmod">
346 <td id="rhodecodepubliccssmainless_o2115" class="lineno old"><a href="#rhodecodepubliccssmainless_o2115">2115</a></td>
344 <td id="rhodecodepubliccssmainless_o2115" class="lineno old"><a href="#rhodecodepubliccssmainless_o2115">2115</a></td>
347 <td id="rhodecodepubliccssmainless_n2114" class="lineno new"><a href="#rhodecodepubliccssmainless_n2114">2114</a></td>
345 <td id="rhodecodepubliccssmainless_n2114" class="lineno new"><a href="#rhodecodepubliccssmainless_n2114">2114</a></td>
348 <td class="code ">
346 <td class="code ">
349 <pre><span class="tab-escape"> </span>z-index: 100;//js sets the menu below it to 9999
347 <pre><span class="tab-escape"> </span>z-index: 100;//js sets the menu below it to 9999
350 </pre>
348 </pre>
351 </td>
349 </td>
352 </tr>
350 </tr>
353 <tr class="line unmod">
351 <tr class="line unmod">
354 <td id="rhodecodepubliccssmainless_o2116" class="lineno old"><a href="#rhodecodepubliccssmainless_o2116">2116</a></td>
352 <td id="rhodecodepubliccssmainless_o2116" class="lineno old"><a href="#rhodecodepubliccssmainless_o2116">2116</a></td>
355 <td id="rhodecodepubliccssmainless_n2115" class="lineno new"><a href="#rhodecodepubliccssmainless_n2115">2115</a></td>
353 <td id="rhodecodepubliccssmainless_n2115" class="lineno new"><a href="#rhodecodepubliccssmainless_n2115">2115</a></td>
356 <td class="code ">
354 <td class="code ">
357 <pre><span class="tab-escape"> </span>background-color: white;
355 <pre><span class="tab-escape"> </span>background-color: white;
358 </pre>
356 </pre>
359 </td>
357 </td>
360 </tr>
358 </tr>
361 <tr class="line context">
359 <tr class="line context">
362 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
360 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o...">...</a></td>
363 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
361 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n...">...</a></td>
364 <td class="code ">
362 <td class="code ">
365 <pre>@@ -2118,7 +2117,7 @@
363 <pre>@@ -2118,7 +2117,7 @@
366 </pre>
364 </pre>
367 </td>
365 </td>
368 </tr>
366 </tr>
369 <tr class="line unmod">
367 <tr class="line unmod">
370 <td id="rhodecodepubliccssmainless_o2118" class="lineno old"><a href="#rhodecodepubliccssmainless_o2118">2118</a></td>
368 <td id="rhodecodepubliccssmainless_o2118" class="lineno old"><a href="#rhodecodepubliccssmainless_o2118">2118</a></td>
371 <td id="rhodecodepubliccssmainless_n2117" class="lineno new"><a href="#rhodecodepubliccssmainless_n2117">2117</a></td>
369 <td id="rhodecodepubliccssmainless_n2117" class="lineno new"><a href="#rhodecodepubliccssmainless_n2117">2117</a></td>
372 <td class="code ">
370 <td class="code ">
373 <pre></pre>
371 <pre></pre>
374 </td>
372 </td>
375 </tr>
373 </tr>
376 <tr class="line unmod">
374 <tr class="line unmod">
377 <td id="rhodecodepubliccssmainless_o2119" class="lineno old"><a href="#rhodecodepubliccssmainless_o2119">2119</a></td>
375 <td id="rhodecodepubliccssmainless_o2119" class="lineno old"><a href="#rhodecodepubliccssmainless_o2119">2119</a></td>
378 <td id="rhodecodepubliccssmainless_n2118" class="lineno new"><a href="#rhodecodepubliccssmainless_n2118">2118</a></td>
376 <td id="rhodecodepubliccssmainless_n2118" class="lineno new"><a href="#rhodecodepubliccssmainless_n2118">2118</a></td>
379 <td class="code ">
377 <td class="code ">
380 <pre><span class="tab-escape"> </span>a {
378 <pre><span class="tab-escape"> </span>a {
381 </pre>
379 </pre>
382 </td>
380 </td>
383 </tr>
381 </tr>
384 <tr class="line unmod">
382 <tr class="line unmod">
385 <td id="rhodecodepubliccssmainless_o2120" class="lineno old"><a href="#rhodecodepubliccssmainless_o2120">2120</a></td>
383 <td id="rhodecodepubliccssmainless_o2120" class="lineno old"><a href="#rhodecodepubliccssmainless_o2120">2120</a></td>
386 <td id="rhodecodepubliccssmainless_n2119" class="lineno new"><a href="#rhodecodepubliccssmainless_n2119">2119</a></td>
384 <td id="rhodecodepubliccssmainless_n2119" class="lineno new"><a href="#rhodecodepubliccssmainless_n2119">2119</a></td>
387 <td class="code ">
385 <td class="code ">
388 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>display:block;
386 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>display:block;
389 </pre>
387 </pre>
390 </td>
388 </td>
391 </tr>
389 </tr>
392 <tr class="line del">
390 <tr class="line del">
393 <td id="rhodecodepubliccssmainless_o2121" class="lineno old"><a href="#rhodecodepubliccssmainless_o2121">2121</a></td>
391 <td id="rhodecodepubliccssmainless_o2121" class="lineno old"><a href="#rhodecodepubliccssmainless_o2121">2121</a></td>
394 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
392 <td class="lineno new"><a href="#rhodecodepubliccssmainless_n"></a></td>
395 <td class="code ">
393 <td class="code ">
396 <pre><span class="tab-escape"> </span><del><span< del=""> <del>class=</del><del>"tab-escape"</del><del>&gt; </del>padding: <del>0</del>;
394 <pre><span class="tab-escape"> </span><del><span< del=""> <del>class=</del><del>"tab-escape"</del><del>&gt; </del>padding: <del>0</del>;
397 </span<></del></pre>
395 </span<></del></pre>
398 </td>
396 </td>
399 </tr>
397 </tr>
400 <tr class="line add">
398 <tr class="line add">
401 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o"></a></td>
399 <td class="lineno old"><a href="#rhodecodepubliccssmainless_o"></a></td>
402 <td id="rhodecodepubliccssmainless_n2120" class="lineno new"><a href="#rhodecodepubliccssmainless_n2120">2120</a></td>
400 <td id="rhodecodepubliccssmainless_n2120" class="lineno new"><a href="#rhodecodepubliccssmainless_n2120">2120</a></td>
403 <td class="code ">
401 <td class="code ">
404 <pre><span class="tab-escape"> </span><ins> </ins> <ins> </ins><ins> </ins>padding: <ins>.9em</ins>;
402 <pre><span class="tab-escape"> </span><ins> </ins> <ins> </ins><ins> </ins>padding: <ins>.9em</ins>;
405 </pre>
403 </pre>
406 </td>
404 </td>
407 </tr>
405 </tr>
408 <tr class="line unmod">
406 <tr class="line unmod">
409 <td id="rhodecodepubliccssmainless_o2122" class="lineno old"><a href="#rhodecodepubliccssmainless_o2122">2122</a></td>
407 <td id="rhodecodepubliccssmainless_o2122" class="lineno old"><a href="#rhodecodepubliccssmainless_o2122">2122</a></td>
410 <td id="rhodecodepubliccssmainless_n2121" class="lineno new"><a href="#rhodecodepubliccssmainless_n2121">2121</a></td>
408 <td id="rhodecodepubliccssmainless_n2121" class="lineno new"><a href="#rhodecodepubliccssmainless_n2121">2121</a></td>
411 <td class="code ">
409 <td class="code ">
412 <pre></pre>
410 <pre></pre>
413 </td>
411 </td>
414 </tr>
412 </tr>
415 <tr class="line unmod">
413 <tr class="line unmod">
416 <td id="rhodecodepubliccssmainless_o2123" class="lineno old"><a href="#rhodecodepubliccssmainless_o2123">2123</a></td>
414 <td id="rhodecodepubliccssmainless_o2123" class="lineno old"><a href="#rhodecodepubliccssmainless_o2123">2123</a></td>
417 <td id="rhodecodepubliccssmainless_n2122" class="lineno new"><a href="#rhodecodepubliccssmainless_n2122">2122</a></td>
415 <td id="rhodecodepubliccssmainless_n2122" class="lineno new"><a href="#rhodecodepubliccssmainless_n2122">2122</a></td>
418 <td class="code ">
416 <td class="code ">
419 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>&amp;:after {
417 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span>&amp;:after {
420 </pre>
418 </pre>
421 </td>
419 </td>
422 </tr>
420 </tr>
423 <tr class="line unmod">
421 <tr class="line unmod">
424 <td id="rhodecodepubliccssmainless_o2124" class="lineno old"><a href="#rhodecodepubliccssmainless_o2124">2124</a></td>
422 <td id="rhodecodepubliccssmainless_o2124" class="lineno old"><a href="#rhodecodepubliccssmainless_o2124">2124</a></td>
425 <td id="rhodecodepubliccssmainless_n2123" class="lineno new"><a href="#rhodecodepubliccssmainless_n2123">2123</a></td>
423 <td id="rhodecodepubliccssmainless_n2123" class="lineno new"><a href="#rhodecodepubliccssmainless_n2123">2123</a></td>
426 <td class="code ">
424 <td class="code ">
427 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span><span class="tab-escape"> </span>content: "\00A0\25BE";
425 <pre><span class="tab-escape"> </span><span class="tab-escape"> </span><span class="tab-escape"> </span>content: "\00A0\25BE";
428 </pre>
426 </pre>
429 </td>
427 </td>
430 </tr>
428 </tr>
431 </tbody></table>
429 </tbody></table>
432 </div>
430 </div>
433 </div>
431 </div>
434 </div>
432 </div>
435
433
436 </td>
434 </td>
437 </tr>
435 </tr>
438 </tbody></table>
436 </tbody></table>
439 </div>
437 </div>
440
438
441
439
442
440
443
441
444
442
445
443
446
444
447
445
448
446
449 <!--
447 <!--
450 File View
448 File View
451 -->
449 -->
452
450
453 ##TODO: lisa: I believe this needs to be updated as the layout has changed.
451 ##TODO: lisa: I believe this needs to be updated as the layout has changed.
454 <h2>File View</h2>
452 <h2>File View</h2>
455
453
456 <div class="codeblock">
454 <div class="codeblock">
457 <div class="code-header">
455 <div class="code-header">
458 <div class="stats">
456 <div class="stats">
459 <div class="img">
457 <div class="img">
460 <i class="icon-file"></i>
458 <i class="icon-file"></i>
461 <span class="revision_id item"><a href="/example/changeset/fc252256eb0fcb4f2613e66f0126ea27967ae28c">r5487:fc252256eb0f</a></span>
459 <span class="revision_id item"><a href="/example/changeset/fc252256eb0fcb4f2613e66f0126ea27967ae28c">r5487:fc252256eb0f</a></span>
462 <span>1.2 KiB</span>
460 <span>1.2 KiB</span>
463 <span class="item last">text/x-python</span>
461 <span class="item last">text/x-python</span>
464 <div class="buttons">
462 <div class="buttons">
465
463
466 <a id="file_history_overview" class="btn btn-mini" href="#">
464 <a id="file_history_overview" class="btn btn-mini" href="#">
467 <i class="icon-time"></i> history
465 <i class="icon-time"></i> history
468 </a>
466 </a>
469 <a id="file_history_overview_full" class="btn btn-mini" style="display: none" href="/example/changelog/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
467 <a id="file_history_overview_full" class="btn btn-mini" style="display: none" href="/example/changelog/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
470 <i class="icon-time"></i> show full history
468 <i class="icon-time"></i> show full history
471 </a>
469 </a>
472 <a class="btn btn-mini" href="/example/annotate/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">annotation</a>
470 <a class="btn btn-mini" href="/example/annotate/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">annotation</a>
473 <a class="btn btn-mini" href="/example/raw/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">raw</a>
471 <a class="btn btn-mini" href="/example/raw/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">raw</a>
474 <a class="btn btn-mini" href="/example/rawfile/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
472 <a class="btn btn-mini" href="/example/rawfile/fc252256eb0fcb4f2613e66f0126ea27967ae28c/rhodecode/websetup.py">
475 <i class="icon-archive"></i> download
473 <i class="icon-archive"></i> download
476 </a>
474 </a>
477
475
478 <a class="btn btn-mini disabled tooltip" href="#" title="Editing files allowed only when on branch head commit">edit</a>
476 <a class="btn btn-mini disabled tooltip" href="#" title="Editing files allowed only when on branch head commit">edit</a>
479 <a class="btn btn-mini btn-danger disabled tooltip" href="#" title="Deleting files allowed only when on branch head commit">delete</a>
477 <a class="btn btn-mini btn-danger disabled tooltip" href="#" title="Deleting files allowed only when on branch head commit">delete</a>
480 </div>
478 </div>
481 </div>
479 </div>
482 </div>
480 </div>
483 <div id="file_history_container"></div>
481 <div id="file_history_container"></div>
484 <div class="author">
482 <div class="author">
485 <div class="gravatar">
483 <div class="gravatar">
486 <img alt="gravatar" src="https://secure.gravatar.com/avatar/99e27b99c64003ca8c9875c9e3843495?d=identicon&amp;s=32" height="16" width="16">
484 <img alt="gravatar" src="https://secure.gravatar.com/avatar/99e27b99c64003ca8c9875c9e3843495?d=identicon&amp;s=32" height="16" width="16">
487 </div>
485 </div>
488 <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>
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 </div>
487 </div>
490 <div id="trimmed_message_box" class="commit">License changes</div>
488 <div id="trimmed_message_box" class="commit">License changes</div>
491 <div id="message_expand" style="display: none;">
489 <div id="message_expand" style="display: none;">
492 <i class="icon-resize-vertical"></i>
490 <i class="icon-resize-vertical"></i>
493 expand
491 expand
494 <i class="icon-resize-vertical"></i>
492 <i class="icon-resize-vertical"></i>
495 </div>
493 </div>
496 </div>
494 </div>
497 <div class="code-body">
495 <div class="code-body">
498 <table class="code-highlighttable"><tbody><tr><td class="linenos"><div class="linenodiv"><pre><a href="#L1"> 1</a>
496 <table class="code-highlighttable"><tbody><tr><td class="linenos"><div class="linenodiv"><pre><a href="#L1"> 1</a>
499 <a href="#L2"> 2</a>
497 <a href="#L2"> 2</a>
500 <a href="#L3"> 3</a>
498 <a href="#L3"> 3</a>
501 <a href="#L4"> 4</a>
499 <a href="#L4"> 4</a>
502 <a href="#L5"> 5</a>
500 <a href="#L5"> 5</a>
503 <a href="#L6"> 6</a>
501 <a href="#L6"> 6</a>
504 <a href="#L7"> 7</a>
502 <a href="#L7"> 7</a>
505 <a href="#L8"> 8</a>
503 <a href="#L8"> 8</a>
506 <a href="#L9"> 9</a>
504 <a href="#L9"> 9</a>
507 <a href="#L10">10</a>
505 <a href="#L10">10</a>
508 <a href="#L11">11</a>
506 <a href="#L11">11</a>
509 <a href="#L12">12</a>
507 <a href="#L12">12</a>
510 <a href="#L13">13</a>
508 <a href="#L13">13</a>
511 <a href="#L14">14</a>
509 <a href="#L14">14</a>
512 <a href="#L15">15</a>
510 <a href="#L15">15</a>
513 <a href="#L16">16</a>
511 <a href="#L16">16</a>
514 <a href="#L17">17</a>
512 <a href="#L17">17</a>
515 <a href="#L18">18</a>
513 <a href="#L18">18</a>
516 <a href="#L19">19</a>
514 <a href="#L19">19</a>
517 <a href="#L20">20</a>
515 <a href="#L20">20</a>
518 <a href="#L21">21</a>
516 <a href="#L21">21</a>
519 <a href="#L22">22</a>
517 <a href="#L22">22</a>
520 <a href="#L23">23</a>
518 <a href="#L23">23</a>
521 <a href="#L24">24</a>
519 <a href="#L24">24</a>
522 <a href="#L25">25</a>
520 <a href="#L25">25</a>
523 <a href="#L26">26</a>
521 <a href="#L26">26</a>
524 <a href="#L27">27</a>
522 <a href="#L27">27</a>
525 <a href="#L28">28</a>
523 <a href="#L28">28</a>
526 <a href="#L29">29</a>
524 <a href="#L29">29</a>
527 <a href="#L30">30</a>
525 <a href="#L30">30</a>
528 <a href="#L31">31</a>
526 <a href="#L31">31</a>
529 <a href="#L32">32</a>
527 <a href="#L32">32</a>
530 <a href="#L33">33</a>
528 <a href="#L33">33</a>
531 <a href="#L34">34</a>
529 <a href="#L34">34</a>
532 <a href="#L35">35</a>
530 <a href="#L35">35</a>
533 <a href="#L36">36</a>
531 <a href="#L36">36</a>
534 <a href="#L37">37</a>
532 <a href="#L37">37</a>
535 <a href="#L38">38</a>
533 <a href="#L38">38</a>
536 <a href="#L39">39</a>
534 <a href="#L39">39</a>
537 <a href="#L40">40</a>
535 <a href="#L40">40</a>
538 <a href="#L41">41</a>
536 <a href="#L41">41</a>
539 <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>
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 </div><div id="L2"><a name="L-2"></a>
538 </div><div id="L2"><a name="L-2"></a>
541 </div><div id="L3"><a name="L-3"></a><span class="c"># Published under Business Source License.</span>
539 </div><div id="L3"><a name="L-3"></a><span class="c"># Published under Business Source License.</span>
542 </div><div id="L4"><a name="L-4"></a><span class="c"># Read the full license text at https://rhodecode.com/licenses.</span>
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 </div><div id="L5"><a name="L-5"></a><span class="sd">"""</span>
541 </div><div id="L5"><a name="L-5"></a><span class="sd">"""</span>
544 </div><div id="L6"><a name="L-6"></a><span class="sd">rhodecode.websetup</span>
542 </div><div id="L6"><a name="L-6"></a><span class="sd">rhodecode.websetup</span>
545 </div><div id="L7"><a name="L-7"></a><span class="sd">~~~~~~~~~~~~~~~~~~</span>
543 </div><div id="L7"><a name="L-7"></a><span class="sd">~~~~~~~~~~~~~~~~~~</span>
546 </div><div id="L8"><a name="L-8"></a>
544 </div><div id="L8"><a name="L-8"></a>
547 </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>
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 </div><div id="L10"><a name="L-10"></a>
546 </div><div id="L10"><a name="L-10"></a>
549 </div><div id="L11"><a name="L-11"></a><span class="sd">:created_on: Dec 11, 2010</span>
547 </div><div id="L11"><a name="L-11"></a><span class="sd">:created_on: Dec 11, 2010</span>
550 </div><div id="L12"><a name="L-12"></a><span class="sd">:author: marcink</span>
548 </div><div id="L12"><a name="L-12"></a><span class="sd">:author: marcink</span>
551 </div><div id="L13"><a name="L-13"></a><span class="sd">:copyright: (c) 2013-2015 RhodeCode GmbH.</span>
549 </div><div id="L13"><a name="L-13"></a><span class="sd">:copyright: (c) 2013-2015 RhodeCode GmbH.</span>
552 </div><div id="L14"><a name="L-14"></a><span class="sd">:license: Business Source License, see LICENSE for more details.</span>
550 </div><div id="L14"><a name="L-14"></a><span class="sd">:license: Business Source License, see LICENSE for more details.</span>
553 </div><div id="L15"><a name="L-15"></a><span class="sd">"""</span>
551 </div><div id="L15"><a name="L-15"></a><span class="sd">"""</span>
554 </div><div id="L16"><a name="L-16"></a>
552 </div><div id="L16"><a name="L-16"></a>
555 </div><div id="L17"><a name="L-17"></a><span class="kn">import</span> <span class="nn">logging</span>
553 </div><div id="L17"><a name="L-17"></a><span class="kn">import</span> <span class="nn">logging</span>
556 </div><div id="L18"><a name="L-18"></a>
554 </div><div id="L18"><a name="L-18"></a>
557 </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>
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 </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>
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 </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>
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 </div><div id="L22"><a name="L-22"></a>
558 </div><div id="L22"><a name="L-22"></a>
561 </div><div id="L23"><a name="L-23"></a>
559 </div><div id="L23"><a name="L-23"></a>
562 </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>
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 </div><div id="L25"><a name="L-25"></a>
561 </div><div id="L25"><a name="L-25"></a>
564 </div><div id="L26"><a name="L-26"></a>
562 </div><div id="L26"><a name="L-26"></a>
565 </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>
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 </div><div id="L28"><a name="L-28"></a> <span class="sd">"""Place any commands to setup rhodecode here"""</span>
564 </div><div id="L28"><a name="L-28"></a> <span class="sd">"""Place any commands to setup rhodecode here"""</span>
567 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </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>
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 </div></pre></div>
579 </div></pre></div>
582 </td></tr></tbody></table>
580 </td></tr></tbody></table>
583 </div>
581 </div>
584 </div>
582 </div>
585
583
586
584
587
585
588
586
589
587
590
588
591
589
592
590
593
591
594 <!--
592 <!--
595 Gist Edit
593 Gist Edit
596 -->
594 -->
597
595
598
596
599 <h2>Gist Edit</h2>
597 <h2>Gist Edit</h2>
600
598
601 <div class="codeblock">
599 <div class="codeblock">
602 <div class="code-header">
600 <div class="code-header">
603 <div class="form">
601 <div class="form">
604 <div class="fields">
602 <div class="fields">
605 <input id="filename" name="filename" placeholder="name this file..." size="30" type="text">
603 <input id="filename" name="filename" placeholder="name this file..." size="30" type="text">
606 <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;">
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 <option selected="selected" value="plain">plain</option>
605 <option selected="selected" value="plain">plain</option>
608 <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>
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 <script>
607 <script>
610 $(document).ready(function() {
608 $(document).ready(function() {
611 $('#mimetype').select2({
609 $('#mimetype').select2({
612 containerCssClass: 'drop-menu',
610 containerCssClass: 'drop-menu',
613 dropdownCssClass: 'drop-menu-dropdown',
611 dropdownCssClass: 'drop-menu-dropdown',
614 dropdownAutoWidth: true
612 dropdownAutoWidth: true
615 });
613 });
616 });
614 });
617 </script>
615 </script>
618
616
619 </div>
617 </div>
620 </div>
618 </div>
621 </div>
619 </div>
622 <div id="editor_container">
620 <div id="editor_container">
623 <div id="editor_pre"></div>
621 <div id="editor_pre"></div>
624 <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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&lt;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&gt;=</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>&nbsp;</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>&nbsp;</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;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</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>
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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&lt;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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">&gt;=</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>&nbsp;</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>&nbsp;</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;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</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 </div>
623 </div>
626 </div>
624 </div>
627
625
628
626
629
627
630
628
631
629
632 <!--
630 <!--
633 File Edit
631 File Edit
634 -->
632 -->
635
633
636 <h2>File Edit</h2>
634 <h2>File Edit</h2>
637
635
638 <div class="codeblock">
636 <div class="codeblock">
639 <div class="code-header">
637 <div class="code-header">
640 <div class="stats">
638 <div class="stats">
641 <i class="icon-file"></i>
639 <i class="icon-file"></i>
642 <span class="item"><a href="/example/changeset/80ead1899f50a894889e19ffeb49c9cebf5bf045">r8248:80ead1899f50</a></span>
640 <span class="item"><a href="/example/changeset/80ead1899f50a894889e19ffeb49c9cebf5bf045">r8248:80ead1899f50</a></span>
643 <span class="item">1.2 KiB</span>
641 <span class="item">1.2 KiB</span>
644 <span class="item last">text/x-python</span>
642 <span class="item last">text/x-python</span>
645 <div class="buttons">
643 <div class="buttons">
646 <a class="btn btn-mini" href="/example/changelog/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
644 <a class="btn btn-mini" href="/example/changelog/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
647 <i class="icon-time"></i> history
645 <i class="icon-time"></i> history
648 </a>
646 </a>
649
647
650 <a class="btn btn-mini" href="/example/files/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">source</a>
648 <a class="btn btn-mini" href="/example/files/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">source</a>
651 <a class="btn btn-mini" href="/example/raw/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">raw</a>
649 <a class="btn btn-mini" href="/example/raw/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">raw</a>
652 <a class="btn btn-mini" href="/example/rawfile/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
650 <a class="btn btn-mini" href="/example/rawfile/80ead1899f50a894889e19ffeb49c9cebf5bf045/rhodecode/websetup.py">
653 <i class="icon-archive"></i> download
651 <i class="icon-archive"></i> download
654 </a>
652 </a>
655 </div>
653 </div>
656 </div>
654 </div>
657 <div class="form">
655 <div class="form">
658 <label for="set_mode">Editing file:</label>
656 <label for="set_mode">Editing file:</label>
659 rhodecode /
657 rhodecode /
660 <input type="text" name="filename" value="websetup.py">
658 <input type="text" name="filename" value="websetup.py">
661
659
662 <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;">
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 <option selected="selected" value="plain">plain</option>
661 <option selected="selected" value="plain">plain</option>
664 <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>
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 <script>
663 <script>
666 $(document).ready(function() {
664 $(document).ready(function() {
667 $('#set_mode').select2({
665 $('#set_mode').select2({
668 containerCssClass: 'drop-menu',
666 containerCssClass: 'drop-menu',
669 dropdownCssClass: 'drop-menu-dropdown',
667 dropdownCssClass: 'drop-menu-dropdown',
670 dropdownAutoWidth: true
668 dropdownAutoWidth: true
671 });
669 });
672 });
670 });
673 </script>
671 </script>
674
672
675 <label for="line_wrap">line wraps</label>
673 <label for="line_wrap">line wraps</label>
676 <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;">
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 <option value="on">on</option>
675 <option value="on">on</option>
678 <option selected="selected" value="off">off</option>
676 <option selected="selected" value="off">off</option>
679 </select>
677 </select>
680 <script>
678 <script>
681 $(document).ready(function() {
679 $(document).ready(function() {
682 $('#line_wrap').select2({
680 $('#line_wrap').select2({
683 containerCssClass: 'drop-menu',
681 containerCssClass: 'drop-menu',
684 dropdownCssClass: 'drop-menu-dropdown',
682 dropdownCssClass: 'drop-menu-dropdown',
685 dropdownAutoWidth: true,
683 dropdownAutoWidth: true,
686 minimumResultsForSearch: -1
684 minimumResultsForSearch: -1
687
685
688 });
686 });
689 });
687 });
690 </script>
688 </script>
691
689
692 <div id="render_preview" class="btn btn-mini hidden disabled">Preview</div>
690 <div id="render_preview" class="btn btn-mini hidden disabled">Preview</div>
693 </div>
691 </div>
694 </div>
692 </div>
695 <div id="editor_container">
693 <div id="editor_container">
696 <pre id="editor_pre"></pre>
694 <pre id="editor_pre"></pre>
697 <textarea id="editor" name="content" style="display: none;"># -*- coding: utf-8 -*-
695 <textarea id="editor" name="content" style="display: none;"># -*- coding: utf-8 -*-
698
696
699 # Published under Commercial License.
697 # Published under Commercial License.
700 # Read the full license text at https://rhodecode.com/licenses.
698 # Read the full license text at https://rhodecode.com/licenses.
701 """
699 """
702 rhodecode.websetup
700 rhodecode.websetup
703 ~~~~~~~~~~~~~~~~~~
701 ~~~~~~~~~~~~~~~~~~
704
702
705 Weboperations and setup for rhodecode
703 Weboperations and setup for rhodecode
706
704
707 :created_on: Dec 11, 2010
705 :created_on: Dec 11, 2010
708 :author: marcink
706 :author: marcink
709 :copyright: (c) 2013-2015 RhodeCode GmbH.
707 :copyright: (c) 2013-2015 RhodeCode GmbH.
710 :license: Commercial License, see LICENSE for more details.
708 :license: Commercial License, see LICENSE for more details.
711 """
709 """
712
710
713 import logging
711 import logging
714
712
715 from rhodecode.config.environment import load_environment
713 from rhodecode.config.environment import load_environment
716 from rhodecode.lib.db_manage import DbManage
714 from rhodecode.lib.db_manage import DbManage
717 from rhodecode.model.meta import Session
715 from rhodecode.model.meta import Session
718
716
719
717
720 log = logging.getLogger(__name__)
718 log = logging.getLogger(__name__)
721
719
722
720
723 def setup_app(command, conf, vars):
721 def setup_app(command, conf, vars):
724 """Place any commands to setup rhodecode here"""
722 """Place any commands to setup rhodecode here"""
725 dbconf = conf['sqlalchemy.db1.url']
723 dbconf = conf['sqlalchemy.db1.url']
726 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
724 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=conf['here'],
727 tests=False, cli_args=command.options.__dict__)
725 tests=False, cli_args=command.options.__dict__)
728 dbmanage.create_tables(override=True)
726 dbmanage.create_tables(override=True)
729 dbmanage.set_db_version()
727 dbmanage.set_db_version()
730 opts = dbmanage.config_prompt(None)
728 opts = dbmanage.config_prompt(None)
731 dbmanage.create_settings(opts)
729 dbmanage.create_settings(opts)
732 dbmanage.create_default_user()
730 dbmanage.create_default_user()
733 dbmanage.admin_prompt()
731 dbmanage.admin_prompt()
734 dbmanage.create_permissions()
732 dbmanage.create_permissions()
735 dbmanage.populate_default_permissions()
733 dbmanage.populate_default_permissions()
736 Session().commit()
734 Session().commit()
737 load_environment(conf.global_conf, conf.local_conf, initial=True)
735 load_environment(conf.global_conf, conf.local_conf, initial=True)
738 </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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</pre></div></div><div class="CodeMirror-cursor" style="left: 4px; top: 0px; height: 13px;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</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>
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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</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>&nbsp;</pre></div></div><div class="CodeMirror-cursor" style="left: 4px; top: 0px; height: 13px;">&nbsp;</div><div class="CodeMirror-cursor CodeMirror-secondarycursor" style="display: none;">&nbsp;</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 <div id="editor_preview"></div>
737 <div id="editor_preview"></div>
740 </div>
738 </div>
741 <div class="message">
739 <div class="message">
742 <label class="codeblock-label">Commit Message</label>
740 <label class="codeblock-label">Commit Message</label>
743 <textarea id="commit" name="message" placeholder="Edited file rhodecode/websetup.py via RhodeCode"></textarea>
741 <textarea id="commit" name="message" placeholder="Edited file rhodecode/websetup.py via RhodeCode"></textarea>
744 </div>
742 </div>
745 </div>
743 </div>
746
744
747
745
748
746
749
747
750
748
751
749
752 <!--
750 <!--
753 Commit with comments
751 Commit with comments
754 -->
752 -->
755
753
756 <h2>Commit with comments</h2>
754 <h2>Commit with comments</h2>
757
755
758 <div class="diff-container" id="diff-container-140360037209920">
756 <div class="diff-container" id="diff-container-140360037209920">
759 <div id="c-4e5ee86997c6-7046e4320b26_target"></div>
757 <div id="c-4e5ee86997c6-7046e4320b26_target"></div>
760 <div id="c-4e5ee86997c6-7046e4320b26" class="diffblock margined comm">
758 <div id="c-4e5ee86997c6-7046e4320b26" class="diffblock margined comm">
761 <div class="code-header">
759 <div class="code-header">
762 <div title="Go back to changed files overview">
760 <div title="Go back to changed files overview">
763 <a href="#changes_box">
761 <a href="#changes_box">
764 <i class="icon-circle-arrow-up"></i>
762 <i class="icon-circle-arrow-up"></i>
765 </a>
763 </a>
766 </div>
764 </div>
767 <div class="changeset_header">
765 <div class="changeset_header">
768 <div class="changeset_file">
766 <div class="changeset_file">
769 <i class="icon-file"></i>
767 <i class="icon-file"></i>
770 <a href="/andersonsantos/rhodecode-dev-fork/files/4e5ee86997c64981d85cf62283af448624e26929/rhodecode/tests/functional/test_compare_local.py">rhodecode/tests/functional/test_compare_local.py</a>
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 </div>
769 </div>
772 <div class="diff-actions">
770 <div class="diff-actions">
773 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full diff for this file">
771 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full diff for this file">
774 <img class="icon" src="/images/icons/page_white_go.png">
772 <img class="icon" src="/images/icons/page_white_go.png">
775 </a>
773 </a>
776 <a href="/andersonsantos/rhodecode-dev-fork/diff-2way/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full side-by-side diff for this file">
774 <a href="/andersonsantos/rhodecode-dev-fork/diff-2way/rhodecode/tests/functional/test_compare_local.py?fulldiff=1&amp;diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=diff&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Show full side-by-side diff for this file">
777 <img class="icon" src="/images/icons/application_double.png">
775 <img class="icon" src="/images/icons/application_double.png">
778 </a>
776 </a>
779 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=raw&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Raw diff">
777 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=raw&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Raw diff">
780 <img class="icon" src="/images/icons/page_white.png">
778 <img class="icon" src="/images/icons/page_white.png">
781 </a>
779 </a>
782 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=download&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Download diff">
780 <a href="/andersonsantos/rhodecode-dev-fork/diff/rhodecode/tests/functional/test_compare_local.py?diff1=682135c2e3958d7c84db06d716efe482bd3ce7c6&amp;diff=download&amp;diff2=4e5ee86997c64981d85cf62283af448624e26929" class="tooltip" title="Download diff">
783 <img class="icon" src="/images/icons/page_save.png">
781 <img class="icon" src="/images/icons/page_save.png">
784 </a>
782 </a>
785 <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=WS%3A1&amp;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>
783 <a class="tooltip" href="/andersonsantos/rhodecode-dev-fork/changeset/4e5ee86997c64981d85cf62283af448624e26929?c-4e5ee86997c6-7046e4320b26=WS%3A1&amp;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 <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>
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 </div>
785 </div>
788 <span>
786 <span>
789 <label>
787 <label>
790 Show inline comments
788 Show inline comments
791 <input checked="checked" class="show-inline-comments" id="" id_for="c-4e5ee86997c6-7046e4320b26" name="" type="checkbox" value="1">
789 <input checked="checked" class="show-inline-comments" id="" id_for="c-4e5ee86997c6-7046e4320b26" name="" type="checkbox" value="1">
792 </label>
790 </label>
793 </span>
791 </span>
794 </div>
792 </div>
795 </div>
793 </div>
796 <div class="code-body">
794 <div class="code-body">
797 <div class="full_f_path" path="rhodecode/tests/functional/test_compare_local.py"></div>
795 <div class="full_f_path" path="rhodecode/tests/functional/test_compare_local.py"></div>
798 <table class="code-difftable">
796 <table class="code-difftable">
799 <tbody><tr class="line context">
797 <tbody><tr class="line context">
800 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
798 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
801 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
799 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
802 <td class="code ">
800 <td class="code ">
803 <pre>@@ -59,7 +59,7 @@
801 <pre>@@ -59,7 +59,7 @@
804 </pre>
802 </pre>
805 </td>
803 </td>
806 </tr>
804 </tr>
807 <tr class="line unmod">
805 <tr class="line unmod">
808 <td id="rhodecodetestsfunctionaltest_compare_localpy_o59" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o59">59</a></td>
806 <td id="rhodecodetestsfunctionaltest_compare_localpy_o59" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o59">59</a></td>
809 <td id="rhodecodetestsfunctionaltest_compare_localpy_n59" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n59">59</a></td>
807 <td id="rhodecodetestsfunctionaltest_compare_localpy_n59" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n59">59</a></td>
810 <td class="code ">
808 <td class="code ">
811 <pre> 'tag': 'v0.2.0',
809 <pre> 'tag': 'v0.2.0',
812 </pre>
810 </pre>
813 </td>
811 </td>
814 </tr>
812 </tr>
815 <tr class="line unmod">
813 <tr class="line unmod">
816 <td id="rhodecodetestsfunctionaltest_compare_localpy_o60" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o60">60</a></td>
814 <td id="rhodecodetestsfunctionaltest_compare_localpy_o60" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o60">60</a></td>
817 <td id="rhodecodetestsfunctionaltest_compare_localpy_n60" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n60">60</a></td>
815 <td id="rhodecodetestsfunctionaltest_compare_localpy_n60" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n60">60</a></td>
818 <td class="code ">
816 <td class="code ">
819 <pre> 'branch': 'default',
817 <pre> 'branch': 'default',
820 </pre>
818 </pre>
821 </td>
819 </td>
822 </tr>
820 </tr>
823 <tr class="line unmod">
821 <tr class="line unmod">
824 <td id="rhodecodetestsfunctionaltest_compare_localpy_o61" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o61">61</a></td>
822 <td id="rhodecodetestsfunctionaltest_compare_localpy_o61" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o61">61</a></td>
825 <td id="rhodecodetestsfunctionaltest_compare_localpy_n61" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n61">61</a></td>
823 <td id="rhodecodetestsfunctionaltest_compare_localpy_n61" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n61">61</a></td>
826 <td class="code ">
824 <td class="code ">
827 <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.
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 </pre>
826 </pre>
829 </td>
827 </td>
830 </tr>
828 </tr>
831 <tr class="line del">
829 <tr class="line del">
832 <td id="rhodecodetestsfunctionaltest_compare_localpy_o62" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o62">62</a></td>
830 <td id="rhodecodetestsfunctionaltest_compare_localpy_o62" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o62">62</a></td>
833 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
831 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
834 <td class="code ">
832 <td class="code ">
835 <pre> '147 files changed: 5700 inserted, 10176 deleted'
833 <pre> '147 files changed: 5700 inserted, 10176 deleted'
836 </pre>
834 </pre>
837 </td>
835 </td>
838 </tr>
836 </tr>
839 <tr class="line add">
837 <tr class="line add">
840 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
838 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
841 <td id="rhodecodetestsfunctionaltest_compare_localpy_n62" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n62">62</a></td>
839 <td id="rhodecodetestsfunctionaltest_compare_localpy_n62" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n62">62</a></td>
842 <td class="code ">
840 <td class="code ">
843 <pre><ins> </ins> '147 files changed: 5700 inserted, 10176 deleted'
841 <pre><ins> </ins> '147 files changed: 5700 inserted, 10176 deleted'
844 </pre>
842 </pre>
845 </td>
843 </td>
846 </tr>
844 </tr>
847 <tr class="line unmod">
845 <tr class="line unmod">
848 <td id="rhodecodetestsfunctionaltest_compare_localpy_o63" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o63">63</a></td>
846 <td id="rhodecodetestsfunctionaltest_compare_localpy_o63" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o63">63</a></td>
849 <td id="rhodecodetestsfunctionaltest_compare_localpy_n63" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n63">63</a></td>
847 <td id="rhodecodetestsfunctionaltest_compare_localpy_n63" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n63">63</a></td>
850 <td class="code ">
848 <td class="code ">
851 <pre> },
849 <pre> },
852 </pre>
850 </pre>
853 </td>
851 </td>
854 </tr>
852 </tr>
855 <tr class="line unmod">
853 <tr class="line unmod">
856 <td id="rhodecodetestsfunctionaltest_compare_localpy_o64" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o64">64</a></td>
854 <td id="rhodecodetestsfunctionaltest_compare_localpy_o64" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o64">64</a></td>
857 <td id="rhodecodetestsfunctionaltest_compare_localpy_n64" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n64">64</a></td>
855 <td id="rhodecodetestsfunctionaltest_compare_localpy_n64" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n64">64</a></td>
858 <td class="code ">
856 <td class="code ">
859 <pre> 'git': {
857 <pre> 'git': {
860 </pre>
858 </pre>
861 </td>
859 </td>
862 </tr>
860 </tr>
863 <tr class="line unmod">
861 <tr class="line unmod">
864 <td id="rhodecodetestsfunctionaltest_compare_localpy_o65" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o65">65</a></td>
862 <td id="rhodecodetestsfunctionaltest_compare_localpy_o65" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o65">65</a></td>
865 <td id="rhodecodetestsfunctionaltest_compare_localpy_n65" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n65">65</a></td>
863 <td id="rhodecodetestsfunctionaltest_compare_localpy_n65" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n65">65</a></td>
866 <td class="code ">
864 <td class="code ">
867 <pre> 'tag': 'v0.2.2',
865 <pre> 'tag': 'v0.2.2',
868 </pre>
866 </pre>
869 </td>
867 </td>
870 </tr>
868 </tr>
871 <tr class="line context">
869 <tr class="line context">
872 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
870 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o...">...</a></td>
873 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
871 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n...">...</a></td>
874 <td class="code ">
872 <td class="code ">
875 <pre>@@ -77,9 +77,11 @@
873 <pre>@@ -77,9 +77,11 @@
876 </pre>
874 </pre>
877 </td>
875 </td>
878 </tr>
876 </tr>
879 <tr class="line unmod">
877 <tr class="line unmod">
880 <td id="rhodecodetestsfunctionaltest_compare_localpy_o77" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o77">77</a></td>
878 <td id="rhodecodetestsfunctionaltest_compare_localpy_o77" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o77">77</a></td>
881 <td id="rhodecodetestsfunctionaltest_compare_localpy_n77" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n77">77</a></td>
879 <td id="rhodecodetestsfunctionaltest_compare_localpy_n77" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n77">77</a></td>
882 <td class="code ">
880 <td class="code ">
883 <pre> target_ref=revisions[backend.alias]['tag'],
881 <pre> target_ref=revisions[backend.alias]['tag'],
884 </pre>
882 </pre>
885 </td>
883 </td>
886 </tr>
884 </tr>
887 <tr class="line unmod">
885 <tr class="line unmod">
888 <td id="rhodecodetestsfunctionaltest_compare_localpy_o78" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o78">78</a></td>
886 <td id="rhodecodetestsfunctionaltest_compare_localpy_o78" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o78">78</a></td>
889 <td id="rhodecodetestsfunctionaltest_compare_localpy_n78" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n78">78</a></td>
887 <td id="rhodecodetestsfunctionaltest_compare_localpy_n78" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n78">78</a></td>
890 <td class="code ">
888 <td class="code ">
891 <pre> ))
889 <pre> ))
892 </pre>
890 </pre>
893 </td>
891 </td>
894 </tr><tr id="comment-tr-3754" class="inline-comments"><td></td><td></td><td>
892 </tr><tr id="comment-tr-3754" class="inline-comments"><td></td><td></td><td>
895
893
896 <div class="comment" id="comment-3754" line="n78">
894 <div class="comment" id="comment-3754" line="n78">
897 <div class="comment-wrapp">
895 <div class="comment-wrapp">
898 <div class="meta">
896 <div class="meta">
899 <span class="gravatar">
897 <span class="gravatar">
900 <img src="https://secure.gravatar.com/avatar/72706ebd30734451af9ff3fb59f05ff1?d=identicon&amp;s=40" height="20" width="20">
898 <img src="https://secure.gravatar.com/avatar/72706ebd30734451af9ff3fb59f05ff1?d=identicon&amp;s=40" height="20" width="20">
901 </span>
899 </span>
902 <span class="user">
900 <span class="user">
903 anderson
901 anderson
904 </span>
902 </span>
905 <span class="date">
903 <span class="date">
906 just now |
904 just now |
907 </span>
905 </span>
908 <span class="status-change">
906 <span class="status-change">
909 Comment on commit
907 Comment on commit
910 </span>
908 </span>
911 <a class="permalink" href="#comment-3754"></a>
909 <a class="permalink" href="#comment-3754"></a>
912 </div>
910 </div>
913 <div class="text">
911 <div class="text">
914 <div class="rst-block"><p>commented line
912 <div class="rst-block"><p>commented line
915 with multiple lines</p>
913 with multiple lines</p>
916 </div>
914 </div>
917 </div>
915 </div>
918 </div>
916 </div>
919 </div><div class="add-comment"><span class="btn btn-default">Add another comment</span></div>
917 </div><div class="add-comment"><span class="btn btn-default">Add another comment</span></div>
920
918
921 </td></tr>
919 </td></tr>
922 <tr class="line unmod">
920 <tr class="line unmod">
923 <td id="rhodecodetestsfunctionaltest_compare_localpy_o79" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o79">79</a></td>
921 <td id="rhodecodetestsfunctionaltest_compare_localpy_o79" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o79">79</a></td>
924 <td id="rhodecodetestsfunctionaltest_compare_localpy_n79" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n79">79</a></td>
922 <td id="rhodecodetestsfunctionaltest_compare_localpy_n79" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n79">79</a></td>
925 <td class="code ">
923 <td class="code ">
926 <pre></pre>
924 <pre></pre>
927 </td>
925 </td>
928 </tr>
926 </tr>
929 <tr class="line del form-open hl-comment">
927 <tr class="line del form-open hl-comment">
930 <td id="rhodecodetestsfunctionaltest_compare_localpy_o80" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o80">80</a></td>
928 <td id="rhodecodetestsfunctionaltest_compare_localpy_o80" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o80">80</a></td>
931 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
929 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
932 <td class="code ">
930 <td class="code ">
933 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
931 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
934 </pre>
932 </pre>
935 </td>
933 </td>
936 </tr><tr id="comment-tr-undefined" class="comment-form-inline"><td></td><td></td><td>
934 </tr><tr id="comment-tr-undefined" class="comment-form-inline"><td></td><td></td><td>
937 <div class="comment-inline-form ac">
935 <div class="comment-inline-form ac">
938 <div class="overlay"><div class="overlay-text">Submitting...</div></div>
936 <div class="overlay"><div class="overlay-text">Submitting...</div></div>
939 <form action="#" class="inline-form" method="get">
937 <form action="#" class="inline-form" method="get">
940 <div id="edit-container_o80" class="clearfix">
938 <div id="edit-container_o80" class="clearfix">
941 <div class="comment-title pull-left">
939 <div class="comment-title pull-left">
942 Commenting on line o80.
940 Commenting on line o80.
943 </div>
941 </div>
944 <div class="comment-help pull-right">
942 <div class="comment-help pull-right">
945 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.
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 </div>
944 </div>
947 <div style="clear: both"></div>
945 <div style="clear: both"></div>
948 <textarea id="text_o80" name="text" class="comment-block-ta ac-input" autocomplete="off"></textarea>
946 <textarea id="text_o80" name="text" class="comment-block-ta ac-input" autocomplete="off"></textarea>
949 </div>
947 </div>
950 <div id="preview-container_o80" class="clearfix" style="display: none;">
948 <div id="preview-container_o80" class="clearfix" style="display: none;">
951 <div class="comment-help">
949 <div class="comment-help">
952 Comment preview
950 Comment preview
953 </div>
951 </div>
954 <div id="preview-box_o80" class="preview-box"></div>
952 <div id="preview-box_o80" class="preview-box"></div>
955 </div>
953 </div>
956 <div class="comment-button pull-right">
954 <div class="comment-button pull-right">
957 <input type="hidden" name="f_path" value="rhodecode/tests/functional/test_compare_local.py">
955 <input type="hidden" name="f_path" value="rhodecode/tests/functional/test_compare_local.py">
958 <input type="hidden" name="line" value="o80">
956 <input type="hidden" name="line" value="o80">
959 <div id="preview-btn_o80" class="btn btn-default">Preview</div>
957 <div id="preview-btn_o80" class="btn btn-default">Preview</div>
960 <div id="edit-btn_o80" class="btn" style="display: none;">Edit</div>
958 <div id="edit-btn_o80" class="btn" style="display: none;">Edit</div>
961 <input class="btn btn-success save-inline-form" id="save" name="save" type="submit" value="Comment">
959 <input class="btn btn-success save-inline-form" id="save" name="save" type="submit" value="Comment">
962 </div>
960 </div>
963 <div class="comment-button hide-inline-form-button">
961 <div class="comment-button hide-inline-form-button">
964 <input class="btn hide-inline-form" id="hide-inline-form" name="hide-inline-form" type="reset" value="Cancel">
962 <input class="btn hide-inline-form" id="hide-inline-form" name="hide-inline-form" type="reset" value="Cancel">
965 </div>
963 </div>
966 </form>
964 </form>
967 </div>
965 </div>
968 </td></tr>
966 </td></tr>
969 <tr class="line add">
967 <tr class="line add">
970 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
968 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
971 <td id="rhodecodetestsfunctionaltest_compare_localpy_n80" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n80">80</a></td>
969 <td id="rhodecodetestsfunctionaltest_compare_localpy_n80" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n80">80</a></td>
972 <td class="code ">
970 <td class="code ">
973 <pre> response.mustcontain('%s@%s' % (
971 <pre> response.mustcontain('%s@%s' % (
974 </pre>
972 </pre>
975 </td>
973 </td>
976 </tr>
974 </tr>
977 <tr class="line add">
975 <tr class="line add">
978 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
976 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
979 <td id="rhodecodetestsfunctionaltest_compare_localpy_n81" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n81">81</a></td>
977 <td id="rhodecodetestsfunctionaltest_compare_localpy_n81" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n81">81</a></td>
980 <td class="code ">
978 <td class="code ">
981 <pre> backend.repo_name,
979 <pre> backend.repo_name,
982 </pre>
980 </pre>
983 </td>
981 </td>
984 </tr>
982 </tr>
985 <tr class="line unmod">
983 <tr class="line unmod">
986 <td id="rhodecodetestsfunctionaltest_compare_localpy_o81" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o81">81</a></td>
984 <td id="rhodecodetestsfunctionaltest_compare_localpy_o81" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o81">81</a></td>
987 <td id="rhodecodetestsfunctionaltest_compare_localpy_n82" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n82">82</a></td>
985 <td id="rhodecodetestsfunctionaltest_compare_localpy_n82" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n82">82</a></td>
988 <td class="code ">
986 <td class="code ">
989 <pre> revisions[backend.alias]['branch']))
987 <pre> revisions[backend.alias]['branch']))
990 </pre>
988 </pre>
991 </td>
989 </td>
992 </tr>
990 </tr>
993 <tr class="line del">
991 <tr class="line del">
994 <td id="rhodecodetestsfunctionaltest_compare_localpy_o82" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o82">82</a></td>
992 <td id="rhodecodetestsfunctionaltest_compare_localpy_o82" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o82">82</a></td>
995 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
993 <td class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n"></a></td>
996 <td class="code ">
994 <td class="code ">
997 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
995 <pre> response.mustcontain('%s@%s' % (<del>backend.repo_name,</del>
998 </pre>
996 </pre>
999 </td>
997 </td>
1000 </tr>
998 </tr>
1001 <tr class="line add">
999 <tr class="line add">
1002 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1000 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1003 <td id="rhodecodetestsfunctionaltest_compare_localpy_n83" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n83">83</a></td>
1001 <td id="rhodecodetestsfunctionaltest_compare_localpy_n83" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n83">83</a></td>
1004 <td class="code ">
1002 <td class="code ">
1005 <pre> response.mustcontain('%s@%s' % (
1003 <pre> response.mustcontain('%s@%s' % (
1006 </pre>
1004 </pre>
1007 </td>
1005 </td>
1008 </tr>
1006 </tr>
1009 <tr class="line add">
1007 <tr class="line add">
1010 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1008 <td class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o"></a></td>
1011 <td id="rhodecodetestsfunctionaltest_compare_localpy_n84" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n84">84</a></td>
1009 <td id="rhodecodetestsfunctionaltest_compare_localpy_n84" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n84">84</a></td>
1012 <td class="code ">
1010 <td class="code ">
1013 <pre> backend.repo_name,
1011 <pre> backend.repo_name,
1014 </pre>
1012 </pre>
1015 </td>
1013 </td>
1016 </tr>
1014 </tr>
1017 <tr class="line unmod">
1015 <tr class="line unmod">
1018 <td id="rhodecodetestsfunctionaltest_compare_localpy_o83" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o83">83</a></td>
1016 <td id="rhodecodetestsfunctionaltest_compare_localpy_o83" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o83">83</a></td>
1019 <td id="rhodecodetestsfunctionaltest_compare_localpy_n85" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n85">85</a></td>
1017 <td id="rhodecodetestsfunctionaltest_compare_localpy_n85" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n85">85</a></td>
1020 <td class="code ">
1018 <td class="code ">
1021 <pre> revisions[backend.alias]['tag']))
1019 <pre> revisions[backend.alias]['tag']))
1022 </pre>
1020 </pre>
1023 </td>
1021 </td>
1024 </tr>
1022 </tr>
1025 <tr class="line unmod">
1023 <tr class="line unmod">
1026 <td id="rhodecodetestsfunctionaltest_compare_localpy_o84" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o84">84</a></td>
1024 <td id="rhodecodetestsfunctionaltest_compare_localpy_o84" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o84">84</a></td>
1027 <td id="rhodecodetestsfunctionaltest_compare_localpy_n86" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n86">86</a></td>
1025 <td id="rhodecodetestsfunctionaltest_compare_localpy_n86" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n86">86</a></td>
1028 <td class="code ">
1026 <td class="code ">
1029 <pre> response.mustcontain(revisions[backend.alias]['response'])
1027 <pre> response.mustcontain(revisions[backend.alias]['response'])
1030 </pre>
1028 </pre>
1031 </td>
1029 </td>
1032 </tr>
1030 </tr>
1033 <tr class="line unmod">
1031 <tr class="line unmod">
1034 <td id="rhodecodetestsfunctionaltest_compare_localpy_o85" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o85">85</a></td>
1032 <td id="rhodecodetestsfunctionaltest_compare_localpy_o85" class="lineno old"><a href="#rhodecodetestsfunctionaltest_compare_localpy_o85">85</a></td>
1035 <td id="rhodecodetestsfunctionaltest_compare_localpy_n87" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n87">87</a></td>
1033 <td id="rhodecodetestsfunctionaltest_compare_localpy_n87" class="lineno new"><a href="#rhodecodetestsfunctionaltest_compare_localpy_n87">87</a></td>
1036 <td class="code ">
1034 <td class="code ">
1037 <pre></pre>
1035 <pre></pre>
1038 </td>
1036 </td>
1039 </tr>
1037 </tr>
1040 </tbody></table>
1038 </tbody></table>
1041 </div>
1039 </div>
1042 </div>
1040 </div>
1043 </div>
1041 </div>
1044
1042
1045
1043
1046
1044
1047 <!--
1045 <!--
1048 Side-by-side diff
1046 Side-by-side diff
1049 -->
1047 -->
1050
1048
1051 <h2>Side-by-side diff</h2>
1049 <h2>Side-by-side diff</h2>
1052
1050
1053 <div class="box">
1051 <div class="box">
1054 <div class="diff-container" style="overflow-x: hidden">
1052 <div class="diff-container" style="overflow-x: hidden">
1055 <div class="diffblock comm" style="margin:3px; padding:1px">
1053 <div class="diffblock comm" style="margin:3px; padding:1px">
1056 <div class="code-header">
1054 <div class="code-header">
1057 <div class="changeset_header">
1055 <div class="changeset_header">
1058 <div class="changeset_file">
1056 <div class="changeset_file">
1059 <i class="icon-file"></i>
1057 <i class="icon-file"></i>
1060 <a href="/pygments/files/ea295cfb622620f5ba13e226ec531e3fe5296399/tests/test_basic_api.py">tests/test_basic_api.py</a>
1058 <a href="/pygments/files/ea295cfb622620f5ba13e226ec531e3fe5296399/tests/test_basic_api.py">tests/test_basic_api.py</a>
1061 [mode: <span id="selected_mode">python</span>]
1059 [mode: <span id="selected_mode">python</span>]
1062 </div>
1060 </div>
1063 <div class="diff-actions">
1061 <div class="diff-actions">
1064 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;fulldiff=1" class="tooltip" title="Show full diff for this file">
1062 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;fulldiff=1" class="tooltip" title="Show full diff for this file">
1065 <img class="icon" src="/images/icons/page_white_go.png">
1063 <img class="icon" src="/images/icons/page_white_go.png">
1066 </a>
1064 </a>
1067 <a href="/pygments/diff-2way/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;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">
1065 <a href="/pygments/diff-2way/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff=diff&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;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 <img class="icon" src="/images/icons/application_double.png">
1066 <img class="icon" src="/images/icons/application_double.png">
1069 </a>
1067 </a>
1070 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=raw" class="tooltip" title="Raw diff">
1068 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=raw" class="tooltip" title="Raw diff">
1071 <img class="icon" src="/images/icons/page_white.png">
1069 <img class="icon" src="/images/icons/page_white.png">
1072 </a>
1070 </a>
1073 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=download" class="tooltip" title="Download diff">
1071 <a href="/pygments/diff/tests/test_basic_api.py?diff2=ea295cfb622620f5ba13e226ec531e3fe5296399&amp;diff1=de45f950b669e2d991c4ba512fa6fe450c6616db&amp;diff=download" class="tooltip" title="Download diff">
1074 <img class="icon" src="/images/icons/page_save.png">
1072 <img class="icon" src="/images/icons/page_save.png">
1075 </a>
1073 </a>
1076 <label><input id="ignorews" name="ignorews" type="checkbox" value="1">ignore white space</label>
1074 <label><input id="ignorews" name="ignorews" type="checkbox" value="1">ignore white space</label>
1077 <label><input id="edit_mode" name="edit_mode" type="checkbox" value="1">turn on edit mode</label>
1075 <label><input id="edit_mode" name="edit_mode" type="checkbox" value="1">turn on edit mode</label>
1078
1076
1079 </div>
1077 </div>
1080 <div style="float: right; padding: 0px 10px 0px 0px">
1078 <div style="float: right; padding: 0px 10px 0px 0px">
1081 r1538:de45f950b669 ... r1539:ea295cfb6226
1079 r1538:de45f950b669 ... r1539:ea295cfb6226
1082 </div>
1080 </div>
1083 </div>
1081 </div>
1084 </div>
1082 </div>
1085 <div id="compare"></div>
1083 <div id="compare"></div>
1086 </div>
1084 </div>
1087 </div>
1085 </div>
1088
1086
1089 <script>
1087 <script>
1090 $(document).ready(function () {
1088 $(document).ready(function () {
1091 var example_lines = '1\n2\n3\n4\n5\n6\n7\n8\n9\n \n';
1089 var example_lines = '1\n2\n3\n4\n5\n6\n7\n8\n9\n \n';
1092
1090
1093 $('#compare').mergely({
1091 $('#compare').mergely({
1094 width: 'auto',
1092 width: 'auto',
1095 height: '600',
1093 height: '600',
1096 fgcolor: {a:'#ddffdd',c:'#cccccc',d:'#ffdddd'},
1094 fgcolor: {a:'#ddffdd',c:'#cccccc',d:'#ffdddd'},
1097 bgcolor: '#fff',
1095 bgcolor: '#fff',
1098 viewport: true,
1096 viewport: true,
1099 cmsettings: {mode: 'text/plain', readOnly: true, lineWrapping: false, lineNumbers: true},
1097 cmsettings: {mode: 'text/plain', readOnly: true, lineWrapping: false, lineNumbers: true},
1100 lhs: function(setValue) {
1098 lhs: function(setValue) {
1101 if("False" == "True"){
1099 if("False" == "True"){
1102 setValue('Binary file')
1100 setValue('Binary file')
1103 }
1101 }
1104 else if("MercurialCommit" == "EmptyCommit"){
1102 else if("MercurialCommit" == "EmptyCommit"){
1105 setValue('');
1103 setValue('');
1106 }
1104 }
1107 else{
1105 else{
1108 var left_value = example_lines.slice(0, 10) +
1106 var left_value = example_lines.slice(0, 10) +
1109 '123456789 '.repeat(10) +
1107 '123456789 '.repeat(10) +
1110 '\n'+
1108 '\n'+
1111 example_lines.slice(10, 20);
1109 example_lines.slice(10, 20);
1112 setValue(left_value + example_lines.repeat(9));
1110 setValue(left_value + example_lines.repeat(9));
1113 }
1111 }
1114
1112
1115 },
1113 },
1116 rhs: function(setValue) {
1114 rhs: function(setValue) {
1117 if("False" == "True"){
1115 if("False" == "True"){
1118 setValue('Binary file')
1116 setValue('Binary file')
1119 }
1117 }
1120 else if("MercurialCommit" == "EmptyCommit"){
1118 else if("MercurialCommit" == "EmptyCommit"){
1121 setValue('');
1119 setValue('');
1122 }
1120 }
1123 else{
1121 else{
1124 var right_value = example_lines +
1122 var right_value = example_lines +
1125 example_lines.slice(0, 8) +
1123 example_lines.slice(0, 8) +
1126 'abcdefghi '.repeat(10) +
1124 'abcdefghi '.repeat(10) +
1127 '\n'+
1125 '\n'+
1128 example_lines.slice(8, 20);
1126 example_lines.slice(8, 20);
1129 setValue(right_value + example_lines.repeat(9));
1127 setValue(right_value + example_lines.repeat(9));
1130 }
1128 }
1131 },
1129 },
1132 });
1130 });
1133
1131
1134 var detected_mode = detectCodeMirrorModeFromExt('test_basic_api.py', true);
1132 var detected_mode = detectCodeMirrorModeFromExt('test_basic_api.py', true);
1135 if(detected_mode){
1133 if(detected_mode){
1136 setCodeMirrorMode($('#compare').mergely('cm', 'lhs'), detected_mode);
1134 setCodeMirrorMode($('#compare').mergely('cm', 'lhs'), detected_mode);
1137 setCodeMirrorMode($('#compare').mergely('cm', 'rhs'), detected_mode);
1135 setCodeMirrorMode($('#compare').mergely('cm', 'rhs'), detected_mode);
1138 $('#selected_mode').html(detected_mode);
1136 $('#selected_mode').html(detected_mode);
1139 }
1137 }
1140
1138
1141 $('#ignorews').change(function(e){
1139 $('#ignorews').change(function(e){
1142 var val = e.currentTarget.checked;
1140 var val = e.currentTarget.checked;
1143 $('#compare').mergely('options', {ignorews: val});
1141 $('#compare').mergely('options', {ignorews: val});
1144 $('#compare').mergely('update');
1142 $('#compare').mergely('update');
1145 })
1143 })
1146 $('#edit_mode').change(function(e){
1144 $('#edit_mode').change(function(e){
1147 var val = !e.currentTarget.checked;
1145 var val = !e.currentTarget.checked;
1148 $('#compare').mergely('cm', 'lhs').setOption('readOnly', val);
1146 $('#compare').mergely('cm', 'lhs').setOption('readOnly', val);
1149 $('#compare').mergely('cm', 'rhs').setOption('readOnly', val);
1147 $('#compare').mergely('cm', 'rhs').setOption('readOnly', val);
1150 $('#compare').mergely('update');
1148 $('#compare').mergely('update');
1151 })
1149 })
1152 });
1150 });
1153 </script>
1151 </script>
1154
1152
1155 </div>
1153 </div>
1156
1154
1157 <!-- end examples -->
1155 <!-- end examples -->
1158
1156
1159 </div>
1157 </div>
1160 </div>
1158 </div>
1161 </div>
1159 </div>
1162 </%def>
1160 </%def>
@@ -1,286 +1,324 b''
1 <%inherit file="/base/base.html"/>
1 <%inherit file="/base/base.html"/>
2
2
3 <%def name="title(*args)">
3 <%def name="title(*args)">
4 ${_('%s Files') % c.repo_name}
4 ${_('%s Files') % c.repo_name}
5 %if hasattr(c,'file'):
5 %if hasattr(c,'file'):
6 &middot; ${h.safe_unicode(c.file.path) or '\\'}
6 &middot; ${h.safe_unicode(c.file.path) or '\\'}
7 %endif
7 %endif
8
8
9 %if c.rhodecode_name:
9 %if c.rhodecode_name:
10 &middot; ${h.branding(c.rhodecode_name)}
10 &middot; ${h.branding(c.rhodecode_name)}
11 %endif
11 %endif
12 </%def>
12 </%def>
13
13
14 <%def name="breadcrumbs_links()">
14 <%def name="breadcrumbs_links()">
15 ${_('Files')}
15 ${_('Files')}
16 %if c.file:
16 %if c.file:
17 @ ${h.show_id(c.commit)}
17 @ ${h.show_id(c.commit)}
18 %endif
18 %endif
19 </%def>
19 </%def>
20
20
21 <%def name="menu_bar_nav()">
21 <%def name="menu_bar_nav()">
22 ${self.menu_items(active='repositories')}
22 ${self.menu_items(active='repositories')}
23 </%def>
23 </%def>
24
24
25 <%def name="menu_bar_subnav()">
25 <%def name="menu_bar_subnav()">
26 ${self.repo_menu(active='files')}
26 ${self.repo_menu(active='files')}
27 </%def>
27 </%def>
28
28
29 <%def name="main()">
29 <%def name="main()">
30 <div class="title">
30 <div class="title">
31 ${self.repo_page_title(c.rhodecode_db_repo)}
31 ${self.repo_page_title(c.rhodecode_db_repo)}
32 </div>
32 </div>
33
33
34 <div id="pjax-container" class="summary">
34 <div id="pjax-container" class="summary">
35 <div id="files_data">
35 <div id="files_data">
36 <%include file='files_pjax.html'/>
36 <%include file='files_pjax.html'/>
37 </div>
37 </div>
38 </div>
38 </div>
39 <script>
39 <script>
40 var curState = {
40 var curState = {
41 commit_id: "${c.commit.raw_id}"
41 commit_id: "${c.commit.raw_id}"
42 };
42 };
43
43
44 var getState = function(context) {
44 var getState = function(context) {
45 var url = $(location).attr('href');
45 var url = $(location).attr('href');
46 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
46 var _base_url = '${h.url("files_home",repo_name=c.repo_name,revision='',f_path='')}';
47 var _annotate_url = '${h.url("files_annotate_home",repo_name=c.repo_name,revision='',f_path='')}';
47 var _annotate_url = '${h.url("files_annotate_home",repo_name=c.repo_name,revision='',f_path='')}';
48 _base_url = _base_url.replace('//', '/');
48 _base_url = _base_url.replace('//', '/');
49 _annotate_url = _annotate_url.replace('//', '/');
49 _annotate_url = _annotate_url.replace('//', '/');
50
50
51 //extract f_path from url.
51 //extract f_path from url.
52 var parts = url.split(_base_url);
52 var parts = url.split(_base_url);
53 if (parts.length != 2) {
53 if (parts.length != 2) {
54 parts = url.split(_annotate_url);
54 parts = url.split(_annotate_url);
55 if (parts.length != 2) {
55 if (parts.length != 2) {
56 var rev = "tip";
56 var rev = "tip";
57 var f_path = "";
57 var f_path = "";
58 } else {
58 } else {
59 var parts2 = parts[1].split('/');
59 var parts2 = parts[1].split('/');
60 var rev = parts2.shift(); // pop the first element which is the revision
60 var rev = parts2.shift(); // pop the first element which is the revision
61 var f_path = parts2.join('/');
61 var f_path = parts2.join('/');
62 }
62 }
63
63
64 } else {
64 } else {
65 var parts2 = parts[1].split('/');
65 var parts2 = parts[1].split('/');
66 var rev = parts2.shift(); // pop the first element which is the revision
66 var rev = parts2.shift(); // pop the first element which is the revision
67 var f_path = parts2.join('/');
67 var f_path = parts2.join('/');
68 }
68 }
69
69
70 var _node_list_url = pyroutes.url('files_nodelist_home',
70 var _node_list_url = pyroutes.url('files_nodelist_home',
71 {repo_name: templateContext.repo_name,
71 {repo_name: templateContext.repo_name,
72 revision: rev, f_path: f_path});
72 revision: rev, f_path: f_path});
73 var _url_base = pyroutes.url('files_home',
73 var _url_base = pyroutes.url('files_home',
74 {repo_name: templateContext.repo_name,
74 {repo_name: templateContext.repo_name,
75 revision: rev, f_path:'__FPATH__'});
75 revision: rev, f_path:'__FPATH__'});
76 return {
76 return {
77 url: url,
77 url: url,
78 f_path: f_path,
78 f_path: f_path,
79 rev: rev,
79 rev: rev,
80 commit_id: curState.commit_id,
80 commit_id: curState.commit_id,
81 node_list_url: _node_list_url,
81 node_list_url: _node_list_url,
82 url_base: _url_base
82 url_base: _url_base
83 };
83 };
84 };
84 };
85
85
86 var metadataRequest = null;
86 var metadataRequest = null;
87 var getFilesMetadata = function() {
87 var getFilesMetadata = function() {
88 if (metadataRequest && metadataRequest.readyState != 4) {
88 if (metadataRequest && metadataRequest.readyState != 4) {
89 metadataRequest.abort();
89 metadataRequest.abort();
90 }
90 }
91 if (fileSourcePage) {
91 if (fileSourcePage) {
92 return false;
92 return false;
93 }
93 }
94
94
95 if ($('#file-tree-wrapper').hasClass('full-load')) {
95 if ($('#file-tree-wrapper').hasClass('full-load')) {
96 // in case our HTML wrapper has full-load class we don't
96 // in case our HTML wrapper has full-load class we don't
97 // trigger the async load of metadata
97 // trigger the async load of metadata
98 return false;
98 return false;
99 }
99 }
100
100
101 var state = getState('metadata');
101 var state = getState('metadata');
102 var url_data = {
102 var url_data = {
103 'repo_name': templateContext.repo_name,
103 'repo_name': templateContext.repo_name,
104 'commit_id': state.commit_id,
104 'commit_id': state.commit_id,
105 'f_path': state.f_path
105 'f_path': state.f_path
106 };
106 };
107
107
108 var url = pyroutes.url('files_nodetree_full', url_data);
108 var url = pyroutes.url('files_nodetree_full', url_data);
109
109
110 metadataRequest = $.ajax({url: url});
110 metadataRequest = $.ajax({url: url});
111
111
112 metadataRequest.done(function(data) {
112 metadataRequest.done(function(data) {
113 $('#file-tree').html(data);
113 $('#file-tree').html(data);
114 timeagoActivate();
114 timeagoActivate();
115 });
115 });
116 metadataRequest.fail(function (data, textStatus, errorThrown) {
116 metadataRequest.fail(function (data, textStatus, errorThrown) {
117 console.log(data);
117 console.log(data);
118 if (data.status != 0) {
118 if (data.status != 0) {
119 alert("Error while fetching metadata.\nError code {0} ({1}).Please consider reloading the page".format(data.status,data.statusText));
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 var callbacks = function() {
124 var callbacks = function() {
125 var state = getState('callbacks');
125 var state = getState('callbacks');
126 timeagoActivate();
126 timeagoActivate();
127
127
128 // used for history, and switch to
128 // used for history, and switch to
129 var initialCommitData = {
129 var initialCommitData = {
130 id: null,
130 id: null,
131 text: '${_("Switch To Commit")}',
131 text: '${_("Pick Commit")}',
132 type: 'sha',
132 type: 'sha',
133 raw_id: null,
133 raw_id: null,
134 files_url: null
134 files_url: null
135 };
135 };
136
136
137 if ($('#trimmed_message_box').height() < 50) {
137 if ($('#trimmed_message_box').height() < 50) {
138 $('#message_expand').hide();
138 $('#message_expand').hide();
139 }
139 }
140
140
141 $('#message_expand').on('click', function(e) {
141 $('#message_expand').on('click', function(e) {
142 $('#trimmed_message_box').css('max-height', 'none');
142 $('#trimmed_message_box').css('max-height', 'none');
143 $(this).hide();
143 $(this).hide();
144 });
144 });
145
145
146 if (fileSourcePage) {
146 if (fileSourcePage) {
147 // variants for with source code, not tree view
147 // variants for with source code, not tree view
148
148
149 // select code link event
149 // select code link event
150 $("#hlcode").mouseup(getSelectionLink);
150 $("#hlcode").mouseup(getSelectionLink);
151
151
152 // file history select2
152 // file history select2
153 select2FileHistorySwitcher('#diff1', initialCommitData, state);
153 select2FileHistorySwitcher('#diff1', initialCommitData, state);
154
155 // show at, diff to actions handlers
154 $('#diff1').on('change', function(e) {
156 $('#diff1').on('change', function(e) {
155 $('#diff').removeClass('disabled').removeAttr("disabled");
157 $('#diff_to_commit').removeClass('disabled').removeAttr("disabled");
156 $('#show_rev').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 // show more authors
197 // show more authors
160 $('#show_authors').on('click', function(e) {
198 $('#show_authors').on('click', function(e) {
161 e.preventDefault();
199 e.preventDefault();
162 var url = pyroutes.url('files_authors_home',
200 var url = pyroutes.url('files_authors_home',
163 {'repo_name': templateContext.repo_name,
201 {'repo_name': templateContext.repo_name,
164 'revision': state.rev, 'f_path': state.f_path});
202 'revision': state.rev, 'f_path': state.f_path});
165
203
166 $.pjax({
204 $.pjax({
167 url: url,
205 url: url,
168 data: 'annotate=${"1" if c.annotate else "0"}',
206 data: 'annotate=${"1" if c.annotate else "0"}',
169 container: '#file_authors',
207 container: '#file_authors',
170 push: false,
208 push: false,
171 timeout: pjaxTimeout
209 timeout: pjaxTimeout
172 }).complete(function(){
210 }).complete(function(){
173 $('#show_authors').hide();
211 $('#show_authors').hide();
174 })
212 })
175 });
213 });
176
214
177 // load file short history
215 // load file short history
178 $('#file_history_overview').on('click', function(e) {
216 $('#file_history_overview').on('click', function(e) {
179 e.preventDefault();
217 e.preventDefault();
180 path = state.f_path;
218 path = state.f_path;
181 if (path.indexOf("#") >= 0) {
219 if (path.indexOf("#") >= 0) {
182 path = path.slice(0, path.indexOf("#"));
220 path = path.slice(0, path.indexOf("#"));
183 }
221 }
184 var url = pyroutes.url('changelog_file_home',
222 var url = pyroutes.url('changelog_file_home',
185 {'repo_name': templateContext.repo_name,
223 {'repo_name': templateContext.repo_name,
186 'revision': state.rev, 'f_path': path, 'limit': 6});
224 'revision': state.rev, 'f_path': path, 'limit': 6});
187 $('#file_history_container').show();
225 $('#file_history_container').show();
188 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
226 $('#file_history_container').html('<div class="file-history-inner">{0}</div>'.format(_gettext('Loading ...')));
189
227
190 $.pjax({
228 $.pjax({
191 url: url,
229 url: url,
192 container: '#file_history_container',
230 container: '#file_history_container',
193 push: false,
231 push: false,
194 timeout: pjaxTimeout
232 timeout: pjaxTimeout
195 })
233 })
196 });
234 });
197
235
198 }
236 }
199 else {
237 else {
200 getFilesMetadata();
238 getFilesMetadata();
201
239
202 // fuzzy file filter
240 // fuzzy file filter
203 fileBrowserListeners(state.node_list_url, state.url_base);
241 fileBrowserListeners(state.node_list_url, state.url_base);
204
242
205 // switch to widget
243 // switch to widget
206 select2RefSwitcher('#refs_filter', initialCommitData);
244 select2RefSwitcher('#refs_filter', initialCommitData);
207 $('#refs_filter').on('change', function(e) {
245 $('#refs_filter').on('change', function(e) {
208 var data = $('#refs_filter').select2('data');
246 var data = $('#refs_filter').select2('data');
209 curState.commit_id = data.raw_id;
247 curState.commit_id = data.raw_id;
210 $.pjax({url: data.files_url, container: '#pjax-container', timeout: pjaxTimeout});
248 $.pjax({url: data.files_url, container: '#pjax-container', timeout: pjaxTimeout});
211 });
249 });
212
250
213 $("#prev_commit_link").on('click', function(e) {
251 $("#prev_commit_link").on('click', function(e) {
214 var data = $(this).data();
252 var data = $(this).data();
215 curState.commit_id = data.commitId;
253 curState.commit_id = data.commitId;
216 });
254 });
217
255
218 $("#next_commit_link").on('click', function(e) {
256 $("#next_commit_link").on('click', function(e) {
219 var data = $(this).data();
257 var data = $(this).data();
220 curState.commit_id = data.commitId;
258 curState.commit_id = data.commitId;
221 });
259 });
222
260
223 $('#at_rev').on("keypress", function(e) {
261 $('#at_rev').on("keypress", function(e) {
224 /* ENTER PRESSED */
262 /* ENTER PRESSED */
225 if (e.keyCode === 13) {
263 if (e.keyCode === 13) {
226 var rev = $('#at_rev').val();
264 var rev = $('#at_rev').val();
227 // explicit reload page here. with pjax entering bad input
265 // explicit reload page here. with pjax entering bad input
228 // produces not so nice results
266 // produces not so nice results
229 window.location = pyroutes.url('files_home',
267 window.location = pyroutes.url('files_home',
230 {'repo_name': templateContext.repo_name,
268 {'repo_name': templateContext.repo_name,
231 'revision': rev, 'f_path': state.f_path});
269 'revision': rev, 'f_path': state.f_path});
232 }
270 }
233 });
271 });
234 }
272 }
235 };
273 };
236
274
237 var pjaxTimeout = 5000;
275 var pjaxTimeout = 5000;
238
276
239 $(document).pjax(".pjax-link", "#pjax-container", {
277 $(document).pjax(".pjax-link", "#pjax-container", {
240 "fragment": "#pjax-content",
278 "fragment": "#pjax-content",
241 "maxCacheLength": 1000,
279 "maxCacheLength": 1000,
242 "timeout": pjaxTimeout
280 "timeout": pjaxTimeout
243 });
281 });
244
282
245 // define global back/forward states
283 // define global back/forward states
246 var isPjaxPopState = false;
284 var isPjaxPopState = false;
247 $(document).on('pjax:popstate', function() {
285 $(document).on('pjax:popstate', function() {
248 isPjaxPopState = true;
286 isPjaxPopState = true;
249 });
287 });
250
288
251 $(document).on('pjax:end', function(xhr, options) {
289 $(document).on('pjax:end', function(xhr, options) {
252 if (isPjaxPopState) {
290 if (isPjaxPopState) {
253 isPjaxPopState = false;
291 isPjaxPopState = false;
254 callbacks();
292 callbacks();
255 _NODEFILTER.resetFilter();
293 _NODEFILTER.resetFilter();
256 }
294 }
257
295
258 // run callback for tracking if defined for google analytics etc.
296 // run callback for tracking if defined for google analytics etc.
259 // this is used to trigger tracking on pjax
297 // this is used to trigger tracking on pjax
260 if (typeof window.rhodecode_statechange_callback !== 'undefined') {
298 if (typeof window.rhodecode_statechange_callback !== 'undefined') {
261 var state = getState('statechange');
299 var state = getState('statechange');
262 rhodecode_statechange_callback(state.url, null)
300 rhodecode_statechange_callback(state.url, null)
263 }
301 }
264 });
302 });
265
303
266 $(document).on('pjax:success', function(event, xhr, options) {
304 $(document).on('pjax:success', function(event, xhr, options) {
267 if (event.target.id == "file_history_container") {
305 if (event.target.id == "file_history_container") {
268 $('#file_history_overview').hide();
306 $('#file_history_overview').hide();
269 $('#file_history_overview_full').show();
307 $('#file_history_overview_full').show();
270 timeagoActivate();
308 timeagoActivate();
271 } else {
309 } else {
272 callbacks();
310 callbacks();
273 }
311 }
274 });
312 });
275
313
276 $(document).ready(function() {
314 $(document).ready(function() {
277 callbacks();
315 callbacks();
278 var search_GET = "${request.GET.get('search','')}";
316 var search_GET = "${request.GET.get('search','')}";
279 if (search_GET == "1") {
317 if (search_GET == "1") {
280 _NODEFILTER.initFilter();
318 _NODEFILTER.initFilter();
281 }
319 }
282 });
320 });
283
321
284 </script>
322 </script>
285
323
286 </%def>
324 </%def>
@@ -1,62 +1,74 b''
1 <%namespace name="file_base" file="/files/base.html"/>
1 <%namespace name="file_base" file="/files/base.html"/>
2
2
3 <div class="fieldset collapsable-content no-hide" data-toggle="summary-details">
3 <div class="fieldset collapsable-content no-hide" data-toggle="summary-details">
4 <div class="left-label">
4 <div class="left-label">
5 ${_('Commit Description')}:
5 ${_('Commit Description')}:
6 </div>
6 </div>
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>
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 </div>
8 </div>
9
9
10 <div class="fieldset collapsable-content" data-toggle="summary-details">
10 <div class="fieldset collapsable-content" data-toggle="summary-details">
11 <div class="left-label">
11 <div class="left-label">
12 ${_('Commit Description')}:
12 ${_('Commit Description')}:
13 </div>
13 </div>
14 <div class="commit right-content">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
14 <div class="commit right-content">${h.urlify_commit_message(c.commit.message,c.repo_name)}</div>
15 </div>
15 </div>
16
16
17
17
18 <div class="fieldset " data-toggle="summary-details">
18 <div class="fieldset " data-toggle="summary-details">
19 <div class="left-label">
19 <div class="left-label">
20 ${_('References')}:
20 ${_('References')}:
21 </div>
21 </div>
22 <div class="right-content">
22 <div class="right-content">
23 <div class="tags tags-main">
23 <div class="tags tags-main">
24 <code>
24 <code>
25 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.commit.raw_id)}">${h.show_id(c.commit)}</a>
25 <a href="${h.url('changeset_home',repo_name=c.repo_name,revision=c.commit.raw_id)}">${h.show_id(c.commit)}</a>
26 </code>
26 </code>
27
27
28 ${file_base.refs(c.commit)}
28 ${file_base.refs(c.commit)}
29 </div>
29 </div>
30 </div>
30 </div>
31 </div>
31 </div>
32
32
33 <div class="fieldset collapsable-content" data-toggle="summary-details">
33 <div class="fieldset collapsable-content" data-toggle="summary-details">
34 <div class="left-label">
34 <div class="left-label">
35 ${_('File last commit')}:
35 ${_('File last commit')}:
36 </div>
36 </div>
37 <div class="right-content">
37 <div class="right-content">
38 <div class="tags">
38 <div class="tags">
39 <code>
39 <code>
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>
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 </code>
41 </code>
42
42
43 ${file_base.refs(c.file_last_commit)}
43 ${file_base.refs(c.file_last_commit)}
44 </div>
44 </div>
45 </div>
45 </div>
46 </div>
46 </div>
47
47
48
48
49 <div id="node_history" class="file_diff_buttons collapsable-content" data-toggle="summary-details">
49 <div class="fieldset collapsable-content" data-toggle="summary-details">
50 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
50 <div class="left-label">
51 ${_('Show/Diff file')}:
52 </div>
53 <div class="right-content">
51 ${h.hidden('diff1')}
54 ${h.hidden('diff1')}
52 ${h.hidden('diff2',c.file_last_commit.raw_id)}
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")}
60
55 ${h.submit('show_rev',_('Show at Commit'),class_="btn disabled",disabled="true")}
61 <div class="fieldset collapsable-content" data-toggle="summary-details">
56 ${h.hidden('annotate', c.annotate)}
62 <div class="left-label">
57 ${h.end_form()}
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 </div>
69 </div>
59
70
71
60 <script>
72 <script>
61 collapsableContent();
73 collapsableContent();
62 </script> No newline at end of file
74 </script>
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
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
NO CONTENT: file was removed
1 NO CONTENT: file was removed
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
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now