##// END OF EJS Templates
whitespace cleanup
marcink -
r2461:015a42e9 beta
parent child Browse files
Show More
@@ -1,504 +1,504 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.controllers.files
3 rhodecode.controllers.files
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 Files controller for RhodeCode
6 Files controller for RhodeCode
7
7
8 :created_on: Apr 21, 2010
8 :created_on: Apr 21, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25 from __future__ import with_statement
25 from __future__ import with_statement
26 import os
26 import os
27 import logging
27 import logging
28 import traceback
28 import traceback
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 pylons.decorators import jsonify
34 from pylons.decorators import jsonify
35 from paste.fileapp import FileApp, _FileIter
35 from paste.fileapp import FileApp, _FileIter
36
36
37 from rhodecode.lib import diffs
37 from rhodecode.lib import diffs
38 from rhodecode.lib import helpers as h
38 from rhodecode.lib import helpers as h
39
39
40 from rhodecode.lib.compat import OrderedDict
40 from rhodecode.lib.compat import OrderedDict
41 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
41 from rhodecode.lib.utils2 import convert_line_endings, detect_mode, safe_str
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
42 from rhodecode.lib.auth import LoginRequired, HasRepoPermissionAnyDecorator
43 from rhodecode.lib.base import BaseRepoController, render
43 from rhodecode.lib.base import BaseRepoController, render
44 from rhodecode.lib.utils import EmptyChangeset
44 from rhodecode.lib.utils import EmptyChangeset
45 from rhodecode.lib.vcs.conf import settings
45 from rhodecode.lib.vcs.conf import settings
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
46 from rhodecode.lib.vcs.exceptions import RepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
47 ChangesetDoesNotExistError, EmptyRepositoryError, \
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
48 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError
49 from rhodecode.lib.vcs.nodes import FileNode
49 from rhodecode.lib.vcs.nodes import FileNode
50
50
51 from rhodecode.model.repo import RepoModel
51 from rhodecode.model.repo import RepoModel
52 from rhodecode.model.scm import ScmModel
52 from rhodecode.model.scm import ScmModel
53 from rhodecode.model.db import Repository
53 from rhodecode.model.db import Repository
54
54
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
55 from rhodecode.controllers.changeset import anchor_url, _ignorews_url,\
56 _context_url, get_line_ctx, get_ignore_ws
56 _context_url, get_line_ctx, get_ignore_ws
57
57
58
58
59 log = logging.getLogger(__name__)
59 log = logging.getLogger(__name__)
60
60
61
61
62 class FilesController(BaseRepoController):
62 class FilesController(BaseRepoController):
63
63
64
64
65 def __before__(self):
65 def __before__(self):
66 super(FilesController, self).__before__()
66 super(FilesController, self).__before__()
67 c.cut_off_limit = self.cut_off_limit
67 c.cut_off_limit = self.cut_off_limit
68
68
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
69 def __get_cs_or_redirect(self, rev, repo_name, redirect_after=True):
70 """
70 """
71 Safe way to get changeset if error occur it redirects to tip with
71 Safe way to get changeset if error occur it redirects to tip with
72 proper message
72 proper message
73
73
74 :param rev: revision to fetch
74 :param rev: revision to fetch
75 :param repo_name: repo name to redirect after
75 :param repo_name: repo name to redirect after
76 """
76 """
77
77
78 try:
78 try:
79 return c.rhodecode_repo.get_changeset(rev)
79 return c.rhodecode_repo.get_changeset(rev)
80 except EmptyRepositoryError, e:
80 except EmptyRepositoryError, e:
81 if not redirect_after:
81 if not redirect_after:
82 return None
82 return None
83 url_ = url('files_add_home',
83 url_ = url('files_add_home',
84 repo_name=c.repo_name,
84 repo_name=c.repo_name,
85 revision=0, f_path='')
85 revision=0, f_path='')
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
86 add_new = '<a href="%s">[%s]</a>' % (url_, _('add new'))
87 h.flash(h.literal(_('There are no files yet %s' % add_new)),
87 h.flash(h.literal(_('There are no files yet %s' % add_new)),
88 category='warning')
88 category='warning')
89 redirect(h.url('summary_home', repo_name=repo_name))
89 redirect(h.url('summary_home', repo_name=repo_name))
90
90
91 except RepositoryError, e:
91 except RepositoryError, e:
92 h.flash(str(e), category='warning')
92 h.flash(str(e), category='warning')
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
93 redirect(h.url('files_home', repo_name=repo_name, revision='tip'))
94
94
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
95 def __get_filenode_or_redirect(self, repo_name, cs, path):
96 """
96 """
97 Returns file_node, if error occurs or given path is directory,
97 Returns file_node, if error occurs or given path is directory,
98 it'll redirect to top level path
98 it'll redirect to top level path
99
99
100 :param repo_name: repo_name
100 :param repo_name: repo_name
101 :param cs: given changeset
101 :param cs: given changeset
102 :param path: path to lookup
102 :param path: path to lookup
103 """
103 """
104
104
105 try:
105 try:
106 file_node = cs.get_node(path)
106 file_node = cs.get_node(path)
107 if file_node.is_dir():
107 if file_node.is_dir():
108 raise RepositoryError('given path is a directory')
108 raise RepositoryError('given path is a directory')
109 except RepositoryError, e:
109 except RepositoryError, e:
110 h.flash(str(e), category='warning')
110 h.flash(str(e), category='warning')
111 redirect(h.url('files_home', repo_name=repo_name,
111 redirect(h.url('files_home', repo_name=repo_name,
112 revision=cs.raw_id))
112 revision=cs.raw_id))
113
113
114 return file_node
114 return file_node
115
115
116 @LoginRequired()
116 @LoginRequired()
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
117 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
118 'repository.admin')
118 'repository.admin')
119 def index(self, repo_name, revision, f_path, annotate=False):
119 def index(self, repo_name, revision, f_path, annotate=False):
120 # redirect to given revision from form if given
120 # redirect to given revision from form if given
121 post_revision = request.POST.get('at_rev', None)
121 post_revision = request.POST.get('at_rev', None)
122 if post_revision:
122 if post_revision:
123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
123 cs = self.__get_cs_or_redirect(post_revision, repo_name)
124 redirect(url('files_home', repo_name=c.repo_name,
124 redirect(url('files_home', repo_name=c.repo_name,
125 revision=cs.raw_id, f_path=f_path))
125 revision=cs.raw_id, f_path=f_path))
126
126
127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
127 c.changeset = self.__get_cs_or_redirect(revision, repo_name)
128 c.branch = request.GET.get('branch', None)
128 c.branch = request.GET.get('branch', None)
129 c.f_path = f_path
129 c.f_path = f_path
130 c.annotate = annotate
130 c.annotate = annotate
131 cur_rev = c.changeset.revision
131 cur_rev = c.changeset.revision
132
132
133 # prev link
133 # prev link
134 try:
134 try:
135 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
135 prev_rev = c.rhodecode_repo.get_changeset(cur_rev).prev(c.branch)
136 c.url_prev = url('files_home', repo_name=c.repo_name,
136 c.url_prev = url('files_home', repo_name=c.repo_name,
137 revision=prev_rev.raw_id, f_path=f_path)
137 revision=prev_rev.raw_id, f_path=f_path)
138 if c.branch:
138 if c.branch:
139 c.url_prev += '?branch=%s' % c.branch
139 c.url_prev += '?branch=%s' % c.branch
140 except (ChangesetDoesNotExistError, VCSError):
140 except (ChangesetDoesNotExistError, VCSError):
141 c.url_prev = '#'
141 c.url_prev = '#'
142
142
143 # next link
143 # next link
144 try:
144 try:
145 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
145 next_rev = c.rhodecode_repo.get_changeset(cur_rev).next(c.branch)
146 c.url_next = url('files_home', repo_name=c.repo_name,
146 c.url_next = url('files_home', repo_name=c.repo_name,
147 revision=next_rev.raw_id, f_path=f_path)
147 revision=next_rev.raw_id, f_path=f_path)
148 if c.branch:
148 if c.branch:
149 c.url_next += '?branch=%s' % c.branch
149 c.url_next += '?branch=%s' % c.branch
150 except (ChangesetDoesNotExistError, VCSError):
150 except (ChangesetDoesNotExistError, VCSError):
151 c.url_next = '#'
151 c.url_next = '#'
152
152
153 # files or dirs
153 # files or dirs
154 try:
154 try:
155 c.file = c.changeset.get_node(f_path)
155 c.file = c.changeset.get_node(f_path)
156
156
157 if c.file.is_file():
157 if c.file.is_file():
158 _hist = c.changeset.get_file_history(f_path)
158 _hist = c.changeset.get_file_history(f_path)
159 c.file_history = self._get_node_history(c.changeset, f_path,
159 c.file_history = self._get_node_history(c.changeset, f_path,
160 _hist)
160 _hist)
161 c.authors = []
161 c.authors = []
162 for a in set([x.author for x in _hist]):
162 for a in set([x.author for x in _hist]):
163 c.authors.append((h.email(a), h.person(a)))
163 c.authors.append((h.email(a), h.person(a)))
164 else:
164 else:
165 c.authors = c.file_history = []
165 c.authors = c.file_history = []
166 except RepositoryError, e:
166 except RepositoryError, e:
167 h.flash(str(e), category='warning')
167 h.flash(str(e), category='warning')
168 redirect(h.url('files_home', repo_name=repo_name,
168 redirect(h.url('files_home', repo_name=repo_name,
169 revision=revision))
169 revision=revision))
170
170
171 return render('files/files.html')
171 return render('files/files.html')
172
172
173 @LoginRequired()
173 @LoginRequired()
174 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
174 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
175 'repository.admin')
175 'repository.admin')
176 def rawfile(self, repo_name, revision, f_path):
176 def rawfile(self, repo_name, revision, f_path):
177 cs = self.__get_cs_or_redirect(revision, repo_name)
177 cs = self.__get_cs_or_redirect(revision, repo_name)
178 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
178 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
179
179
180 response.content_disposition = 'attachment; filename=%s' % \
180 response.content_disposition = 'attachment; filename=%s' % \
181 safe_str(f_path.split(Repository.url_sep())[-1])
181 safe_str(f_path.split(Repository.url_sep())[-1])
182
182
183 response.content_type = file_node.mimetype
183 response.content_type = file_node.mimetype
184 return file_node.content
184 return file_node.content
185
185
186 @LoginRequired()
186 @LoginRequired()
187 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
187 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
188 'repository.admin')
188 'repository.admin')
189 def raw(self, repo_name, revision, f_path):
189 def raw(self, repo_name, revision, f_path):
190 cs = self.__get_cs_or_redirect(revision, repo_name)
190 cs = self.__get_cs_or_redirect(revision, repo_name)
191 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
191 file_node = self.__get_filenode_or_redirect(repo_name, cs, f_path)
192
192
193 raw_mimetype_mapping = {
193 raw_mimetype_mapping = {
194 # map original mimetype to a mimetype used for "show as raw"
194 # map original mimetype to a mimetype used for "show as raw"
195 # you can also provide a content-disposition to override the
195 # you can also provide a content-disposition to override the
196 # default "attachment" disposition.
196 # default "attachment" disposition.
197 # orig_type: (new_type, new_dispo)
197 # orig_type: (new_type, new_dispo)
198
198
199 # show images inline:
199 # show images inline:
200 'image/x-icon': ('image/x-icon', 'inline'),
200 'image/x-icon': ('image/x-icon', 'inline'),
201 'image/png': ('image/png', 'inline'),
201 'image/png': ('image/png', 'inline'),
202 'image/gif': ('image/gif', 'inline'),
202 'image/gif': ('image/gif', 'inline'),
203 'image/jpeg': ('image/jpeg', 'inline'),
203 'image/jpeg': ('image/jpeg', 'inline'),
204 'image/svg+xml': ('image/svg+xml', 'inline'),
204 'image/svg+xml': ('image/svg+xml', 'inline'),
205 }
205 }
206
206
207 mimetype = file_node.mimetype
207 mimetype = file_node.mimetype
208 try:
208 try:
209 mimetype, dispo = raw_mimetype_mapping[mimetype]
209 mimetype, dispo = raw_mimetype_mapping[mimetype]
210 except KeyError:
210 except KeyError:
211 # we don't know anything special about this, handle it safely
211 # we don't know anything special about this, handle it safely
212 if file_node.is_binary:
212 if file_node.is_binary:
213 # do same as download raw for binary files
213 # do same as download raw for binary files
214 mimetype, dispo = 'application/octet-stream', 'attachment'
214 mimetype, dispo = 'application/octet-stream', 'attachment'
215 else:
215 else:
216 # do not just use the original mimetype, but force text/plain,
216 # do not just use the original mimetype, but force text/plain,
217 # otherwise it would serve text/html and that might be unsafe.
217 # otherwise it would serve text/html and that might be unsafe.
218 # Note: underlying vcs library fakes text/plain mimetype if the
218 # Note: underlying vcs library fakes text/plain mimetype if the
219 # mimetype can not be determined and it thinks it is not
219 # mimetype can not be determined and it thinks it is not
220 # binary.This might lead to erroneous text display in some
220 # binary.This might lead to erroneous text display in some
221 # cases, but helps in other cases, like with text files
221 # cases, but helps in other cases, like with text files
222 # without extension.
222 # without extension.
223 mimetype, dispo = 'text/plain', 'inline'
223 mimetype, dispo = 'text/plain', 'inline'
224
224
225 if dispo == 'attachment':
225 if dispo == 'attachment':
226 dispo = 'attachment; filename=%s' % \
226 dispo = 'attachment; filename=%s' % \
227 safe_str(f_path.split(os.sep)[-1])
227 safe_str(f_path.split(os.sep)[-1])
228
228
229 response.content_disposition = dispo
229 response.content_disposition = dispo
230 response.content_type = mimetype
230 response.content_type = mimetype
231 return file_node.content
231 return file_node.content
232
232
233 @LoginRequired()
233 @LoginRequired()
234 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
234 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
235 def edit(self, repo_name, revision, f_path):
235 def edit(self, repo_name, revision, f_path):
236 r_post = request.POST
236 r_post = request.POST
237
237
238 c.cs = self.__get_cs_or_redirect(revision, repo_name)
238 c.cs = self.__get_cs_or_redirect(revision, repo_name)
239 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
239 c.file = self.__get_filenode_or_redirect(repo_name, c.cs, f_path)
240
240
241 if c.file.is_binary:
241 if c.file.is_binary:
242 return redirect(url('files_home', repo_name=c.repo_name,
242 return redirect(url('files_home', repo_name=c.repo_name,
243 revision=c.cs.raw_id, f_path=f_path))
243 revision=c.cs.raw_id, f_path=f_path))
244
244
245 c.f_path = f_path
245 c.f_path = f_path
246
246
247 if r_post:
247 if r_post:
248
248
249 old_content = c.file.content
249 old_content = c.file.content
250 sl = old_content.splitlines(1)
250 sl = old_content.splitlines(1)
251 first_line = sl[0] if sl else ''
251 first_line = sl[0] if sl else ''
252 # modes: 0 - Unix, 1 - Mac, 2 - DOS
252 # modes: 0 - Unix, 1 - Mac, 2 - DOS
253 mode = detect_mode(first_line, 0)
253 mode = detect_mode(first_line, 0)
254 content = convert_line_endings(r_post.get('content'), mode)
254 content = convert_line_endings(r_post.get('content'), mode)
255
255
256 message = r_post.get('message') or (_('Edited %s via RhodeCode')
256 message = r_post.get('message') or (_('Edited %s via RhodeCode')
257 % (f_path))
257 % (f_path))
258 author = self.rhodecode_user.full_contact
258 author = self.rhodecode_user.full_contact
259
259
260 if content == old_content:
260 if content == old_content:
261 h.flash(_('No changes'),
261 h.flash(_('No changes'),
262 category='warning')
262 category='warning')
263 return redirect(url('changeset_home', repo_name=c.repo_name,
263 return redirect(url('changeset_home', repo_name=c.repo_name,
264 revision='tip'))
264 revision='tip'))
265
265
266 try:
266 try:
267 self.scm_model.commit_change(repo=c.rhodecode_repo,
267 self.scm_model.commit_change(repo=c.rhodecode_repo,
268 repo_name=repo_name, cs=c.cs,
268 repo_name=repo_name, cs=c.cs,
269 user=self.rhodecode_user,
269 user=self.rhodecode_user,
270 author=author, message=message,
270 author=author, message=message,
271 content=content, f_path=f_path)
271 content=content, f_path=f_path)
272 h.flash(_('Successfully committed to %s' % f_path),
272 h.flash(_('Successfully committed to %s' % f_path),
273 category='success')
273 category='success')
274
274
275 except Exception:
275 except Exception:
276 log.error(traceback.format_exc())
276 log.error(traceback.format_exc())
277 h.flash(_('Error occurred during commit'), category='error')
277 h.flash(_('Error occurred during commit'), category='error')
278 return redirect(url('changeset_home',
278 return redirect(url('changeset_home',
279 repo_name=c.repo_name, revision='tip'))
279 repo_name=c.repo_name, revision='tip'))
280
280
281 return render('files/files_edit.html')
281 return render('files/files_edit.html')
282
282
283 @LoginRequired()
283 @LoginRequired()
284 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
284 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
285 def add(self, repo_name, revision, f_path):
285 def add(self, repo_name, revision, f_path):
286 r_post = request.POST
286 r_post = request.POST
287 c.cs = self.__get_cs_or_redirect(revision, repo_name,
287 c.cs = self.__get_cs_or_redirect(revision, repo_name,
288 redirect_after=False)
288 redirect_after=False)
289 if c.cs is None:
289 if c.cs is None:
290 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
290 c.cs = EmptyChangeset(alias=c.rhodecode_repo.alias)
291
291
292 c.f_path = f_path
292 c.f_path = f_path
293
293
294 if r_post:
294 if r_post:
295 unix_mode = 0
295 unix_mode = 0
296 content = convert_line_endings(r_post.get('content'), unix_mode)
296 content = convert_line_endings(r_post.get('content'), unix_mode)
297
297
298 message = r_post.get('message') or (_('Added %s via RhodeCode')
298 message = r_post.get('message') or (_('Added %s via RhodeCode')
299 % (f_path))
299 % (f_path))
300 location = r_post.get('location')
300 location = r_post.get('location')
301 filename = r_post.get('filename')
301 filename = r_post.get('filename')
302 file_obj = r_post.get('upload_file', None)
302 file_obj = r_post.get('upload_file', None)
303
303
304 if file_obj is not None and hasattr(file_obj, 'filename'):
304 if file_obj is not None and hasattr(file_obj, 'filename'):
305 filename = file_obj.filename
305 filename = file_obj.filename
306 content = file_obj.file
306 content = file_obj.file
307
307
308 node_path = os.path.join(location, filename)
308 node_path = os.path.join(location, filename)
309 author = self.rhodecode_user.full_contact
309 author = self.rhodecode_user.full_contact
310
310
311 if not content:
311 if not content:
312 h.flash(_('No content'), category='warning')
312 h.flash(_('No content'), category='warning')
313 return redirect(url('changeset_home', repo_name=c.repo_name,
313 return redirect(url('changeset_home', repo_name=c.repo_name,
314 revision='tip'))
314 revision='tip'))
315 if not filename:
315 if not filename:
316 h.flash(_('No filename'), category='warning')
316 h.flash(_('No filename'), category='warning')
317 return redirect(url('changeset_home', repo_name=c.repo_name,
317 return redirect(url('changeset_home', repo_name=c.repo_name,
318 revision='tip'))
318 revision='tip'))
319
319
320 try:
320 try:
321 self.scm_model.create_node(repo=c.rhodecode_repo,
321 self.scm_model.create_node(repo=c.rhodecode_repo,
322 repo_name=repo_name, cs=c.cs,
322 repo_name=repo_name, cs=c.cs,
323 user=self.rhodecode_user,
323 user=self.rhodecode_user,
324 author=author, message=message,
324 author=author, message=message,
325 content=content, f_path=node_path)
325 content=content, f_path=node_path)
326 h.flash(_('Successfully committed to %s' % node_path),
326 h.flash(_('Successfully committed to %s' % node_path),
327 category='success')
327 category='success')
328 except NodeAlreadyExistsError, e:
328 except NodeAlreadyExistsError, e:
329 h.flash(_(e), category='error')
329 h.flash(_(e), category='error')
330 except Exception:
330 except Exception:
331 log.error(traceback.format_exc())
331 log.error(traceback.format_exc())
332 h.flash(_('Error occurred during commit'), category='error')
332 h.flash(_('Error occurred during commit'), category='error')
333 return redirect(url('changeset_home',
333 return redirect(url('changeset_home',
334 repo_name=c.repo_name, revision='tip'))
334 repo_name=c.repo_name, revision='tip'))
335
335
336 return render('files/files_add.html')
336 return render('files/files_add.html')
337
337
338 @LoginRequired()
338 @LoginRequired()
339 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
339 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
340 'repository.admin')
340 'repository.admin')
341 def archivefile(self, repo_name, fname):
341 def archivefile(self, repo_name, fname):
342
342
343 fileformat = None
343 fileformat = None
344 revision = None
344 revision = None
345 ext = None
345 ext = None
346 subrepos = request.GET.get('subrepos') == 'true'
346 subrepos = request.GET.get('subrepos') == 'true'
347
347
348 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
348 for a_type, ext_data in settings.ARCHIVE_SPECS.items():
349 archive_spec = fname.split(ext_data[1])
349 archive_spec = fname.split(ext_data[1])
350 if len(archive_spec) == 2 and archive_spec[1] == '':
350 if len(archive_spec) == 2 and archive_spec[1] == '':
351 fileformat = a_type or ext_data[1]
351 fileformat = a_type or ext_data[1]
352 revision = archive_spec[0]
352 revision = archive_spec[0]
353 ext = ext_data[1]
353 ext = ext_data[1]
354
354
355 try:
355 try:
356 dbrepo = RepoModel().get_by_repo_name(repo_name)
356 dbrepo = RepoModel().get_by_repo_name(repo_name)
357 if dbrepo.enable_downloads is False:
357 if dbrepo.enable_downloads is False:
358 return _('downloads disabled')
358 return _('downloads disabled')
359
359
360 if c.rhodecode_repo.alias == 'hg':
360 if c.rhodecode_repo.alias == 'hg':
361 # patch and reset hooks section of UI config to not run any
361 # patch and reset hooks section of UI config to not run any
362 # hooks on fetching archives with subrepos
362 # hooks on fetching archives with subrepos
363 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
363 for k, v in c.rhodecode_repo._repo.ui.configitems('hooks'):
364 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
364 c.rhodecode_repo._repo.ui.setconfig('hooks', k, None)
365
365
366 cs = c.rhodecode_repo.get_changeset(revision)
366 cs = c.rhodecode_repo.get_changeset(revision)
367 content_type = settings.ARCHIVE_SPECS[fileformat][0]
367 content_type = settings.ARCHIVE_SPECS[fileformat][0]
368 except ChangesetDoesNotExistError:
368 except ChangesetDoesNotExistError:
369 return _('Unknown revision %s') % revision
369 return _('Unknown revision %s') % revision
370 except EmptyRepositoryError:
370 except EmptyRepositoryError:
371 return _('Empty repository')
371 return _('Empty repository')
372 except (ImproperArchiveTypeError, KeyError):
372 except (ImproperArchiveTypeError, KeyError):
373 return _('Unknown archive type')
373 return _('Unknown archive type')
374
374
375 fd, archive = tempfile.mkstemp()
375 fd, archive = tempfile.mkstemp()
376 t = open(archive, 'wb')
376 t = open(archive, 'wb')
377 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
377 cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
378 t.close()
378 t.close()
379
379
380 def get_chunked_archive(archive):
380 def get_chunked_archive(archive):
381 stream = open(archive, 'rb')
381 stream = open(archive, 'rb')
382 while True:
382 while True:
383 data = stream.read(16 * 1024)
383 data = stream.read(16 * 1024)
384 if not data:
384 if not data:
385 stream.close()
385 stream.close()
386 os.close(fd)
386 os.close(fd)
387 os.remove(archive)
387 os.remove(archive)
388 break
388 break
389 yield data
389 yield data
390
390
391 response.content_disposition = str('attachment; filename=%s-%s%s' \
391 response.content_disposition = str('attachment; filename=%s-%s%s' \
392 % (repo_name, revision[:12], ext))
392 % (repo_name, revision[:12], ext))
393 response.content_type = str(content_type)
393 response.content_type = str(content_type)
394 return get_chunked_archive(archive)
394 return get_chunked_archive(archive)
395
395
396 @LoginRequired()
396 @LoginRequired()
397 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
397 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
398 'repository.admin')
398 'repository.admin')
399 def diff(self, repo_name, f_path):
399 def diff(self, repo_name, f_path):
400 ignore_whitespace = request.GET.get('ignorews') == '1'
400 ignore_whitespace = request.GET.get('ignorews') == '1'
401 line_context = request.GET.get('context', 3)
401 line_context = request.GET.get('context', 3)
402 diff1 = request.GET.get('diff1', '')
402 diff1 = request.GET.get('diff1', '')
403 diff2 = request.GET.get('diff2', '')
403 diff2 = request.GET.get('diff2', '')
404 c.action = request.GET.get('diff')
404 c.action = request.GET.get('diff')
405 c.no_changes = diff1 == diff2
405 c.no_changes = diff1 == diff2
406 c.f_path = f_path
406 c.f_path = f_path
407 c.big_diff = False
407 c.big_diff = False
408 c.anchor_url = anchor_url
408 c.anchor_url = anchor_url
409 c.ignorews_url = _ignorews_url
409 c.ignorews_url = _ignorews_url
410 c.context_url = _context_url
410 c.context_url = _context_url
411 c.changes = OrderedDict()
411 c.changes = OrderedDict()
412 c.changes[diff2] = []
412 c.changes[diff2] = []
413 try:
413 try:
414 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
414 if diff1 not in ['', None, 'None', '0' * 12, '0' * 40]:
415 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
415 c.changeset_1 = c.rhodecode_repo.get_changeset(diff1)
416 node1 = c.changeset_1.get_node(f_path)
416 node1 = c.changeset_1.get_node(f_path)
417 else:
417 else:
418 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
418 c.changeset_1 = EmptyChangeset(repo=c.rhodecode_repo)
419 node1 = FileNode('.', '', changeset=c.changeset_1)
419 node1 = FileNode('.', '', changeset=c.changeset_1)
420
420
421 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
421 if diff2 not in ['', None, 'None', '0' * 12, '0' * 40]:
422 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
422 c.changeset_2 = c.rhodecode_repo.get_changeset(diff2)
423 node2 = c.changeset_2.get_node(f_path)
423 node2 = c.changeset_2.get_node(f_path)
424 else:
424 else:
425 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
425 c.changeset_2 = EmptyChangeset(repo=c.rhodecode_repo)
426 node2 = FileNode('.', '', changeset=c.changeset_2)
426 node2 = FileNode('.', '', changeset=c.changeset_2)
427 except RepositoryError:
427 except RepositoryError:
428 return redirect(url('files_home', repo_name=c.repo_name,
428 return redirect(url('files_home', repo_name=c.repo_name,
429 f_path=f_path))
429 f_path=f_path))
430
430
431 if c.action == 'download':
431 if c.action == 'download':
432 _diff = diffs.get_gitdiff(node1, node2,
432 _diff = diffs.get_gitdiff(node1, node2,
433 ignore_whitespace=ignore_whitespace,
433 ignore_whitespace=ignore_whitespace,
434 context=line_context)
434 context=line_context)
435 diff = diffs.DiffProcessor(_diff, format='gitdiff')
435 diff = diffs.DiffProcessor(_diff, format='gitdiff')
436
436
437 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
437 diff_name = '%s_vs_%s.diff' % (diff1, diff2)
438 response.content_type = 'text/plain'
438 response.content_type = 'text/plain'
439 response.content_disposition = (
439 response.content_disposition = (
440 'attachment; filename=%s' % diff_name
440 'attachment; filename=%s' % diff_name
441 )
441 )
442 return diff.raw_diff()
442 return diff.raw_diff()
443
443
444 elif c.action == 'raw':
444 elif c.action == 'raw':
445 _diff = diffs.get_gitdiff(node1, node2,
445 _diff = diffs.get_gitdiff(node1, node2,
446 ignore_whitespace=ignore_whitespace,
446 ignore_whitespace=ignore_whitespace,
447 context=line_context)
447 context=line_context)
448 diff = diffs.DiffProcessor(_diff, format='gitdiff')
448 diff = diffs.DiffProcessor(_diff, format='gitdiff')
449 response.content_type = 'text/plain'
449 response.content_type = 'text/plain'
450 return diff.raw_diff()
450 return diff.raw_diff()
451
451
452 else:
452 else:
453 fid = h.FID(diff2, node2.path)
453 fid = h.FID(diff2, node2.path)
454 line_context_lcl = get_line_ctx(fid, request.GET)
454 line_context_lcl = get_line_ctx(fid, request.GET)
455 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
455 ign_whitespace_lcl = get_ignore_ws(fid, request.GET)
456
456
457 lim = request.GET.get('fulldiff') or self.cut_off_limit
457 lim = request.GET.get('fulldiff') or self.cut_off_limit
458 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
458 _, cs1, cs2, diff, st = diffs.wrapped_diff(filenode_old=node1,
459 filenode_new=node2,
459 filenode_new=node2,
460 cut_off_limit=lim,
460 cut_off_limit=lim,
461 ignore_whitespace=ign_whitespace_lcl,
461 ignore_whitespace=ign_whitespace_lcl,
462 line_context=line_context_lcl,
462 line_context=line_context_lcl,
463 enable_comments=False)
463 enable_comments=False)
464
464
465 c.changes = [('', node2, diff, cs1, cs2, st,)]
465 c.changes = [('', node2, diff, cs1, cs2, st,)]
466
466
467 return render('files/file_diff.html')
467 return render('files/file_diff.html')
468
468
469 def _get_node_history(self, cs, f_path, changesets=None):
469 def _get_node_history(self, cs, f_path, changesets=None):
470 if changesets is None:
470 if changesets is None:
471 changesets = cs.get_file_history(f_path)
471 changesets = cs.get_file_history(f_path)
472 hist_l = []
472 hist_l = []
473
473
474 changesets_group = ([], _("Changesets"))
474 changesets_group = ([], _("Changesets"))
475 branches_group = ([], _("Branches"))
475 branches_group = ([], _("Branches"))
476 tags_group = ([], _("Tags"))
476 tags_group = ([], _("Tags"))
477 _hg = cs.repository.alias == 'hg'
477 _hg = cs.repository.alias == 'hg'
478 for chs in changesets:
478 for chs in changesets:
479 _branch = '(%s)' % chs.branch if _hg else ''
479 _branch = '(%s)' % chs.branch if _hg else ''
480 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
480 n_desc = 'r%s:%s %s' % (chs.revision, chs.short_id, _branch)
481 changesets_group[0].append((chs.raw_id, n_desc,))
481 changesets_group[0].append((chs.raw_id, n_desc,))
482
482
483 hist_l.append(changesets_group)
483 hist_l.append(changesets_group)
484
484
485 for name, chs in c.rhodecode_repo.branches.items():
485 for name, chs in c.rhodecode_repo.branches.items():
486 branches_group[0].append((chs, name),)
486 branches_group[0].append((chs, name),)
487 hist_l.append(branches_group)
487 hist_l.append(branches_group)
488
488
489 for name, chs in c.rhodecode_repo.tags.items():
489 for name, chs in c.rhodecode_repo.tags.items():
490 tags_group[0].append((chs, name),)
490 tags_group[0].append((chs, name),)
491 hist_l.append(tags_group)
491 hist_l.append(tags_group)
492
492
493 return hist_l
493 return hist_l
494
494
495 @LoginRequired()
495 @LoginRequired()
496 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
496 @HasRepoPermissionAnyDecorator('repository.read', 'repository.write',
497 'repository.admin')
497 'repository.admin')
498 @jsonify
498 @jsonify
499 def nodelist(self, repo_name, revision, f_path):
499 def nodelist(self, repo_name, revision, f_path):
500 if request.environ.get('HTTP_X_PARTIAL_XHR'):
500 if request.environ.get('HTTP_X_PARTIAL_XHR'):
501 cs = self.__get_cs_or_redirect(revision, repo_name)
501 cs = self.__get_cs_or_redirect(revision, repo_name)
502 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
502 _d, _f = ScmModel().get_nodes(repo_name, cs.raw_id, f_path,
503 flat=False)
503 flat=False)
504 return {'nodes': _d + _f}
504 return {'nodes': _d + _f}
@@ -1,77 +1,77 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2
2
3 ${h.form(url('repos'))}
3 ${h.form(url('repos'))}
4 <div class="form">
4 <div class="form">
5 <!-- fields -->
5 <!-- fields -->
6 <div class="fields">
6 <div class="fields">
7 <div class="field">
7 <div class="field">
8 <div class="label">
8 <div class="label">
9 <label for="repo_name">${_('Name')}:</label>
9 <label for="repo_name">${_('Name')}:</label>
10 </div>
10 </div>
11 <div class="input">
11 <div class="input">
12 ${h.text('repo_name',c.new_repo,class_="small")}
12 ${h.text('repo_name',c.new_repo,class_="small")}
13 %if not h.HasPermissionAll('hg.admin')('repo create form'):
13 %if not h.HasPermissionAll('hg.admin')('repo create form'):
14 ${h.hidden('user_created',True)}
14 ${h.hidden('user_created',True)}
15 %endif
15 %endif
16 </div>
16 </div>
17 </div>
17 </div>
18 <div class="field">
18 <div class="field">
19 <div class="label">
19 <div class="label">
20 <label for="clone_uri">${_('Clone from')}:</label>
20 <label for="clone_uri">${_('Clone from')}:</label>
21 </div>
21 </div>
22 <div class="input">
22 <div class="input">
23 ${h.text('clone_uri',class_="small")}
23 ${h.text('clone_uri',class_="small")}
24 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
24 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
25 </div>
25 </div>
26 </div>
26 </div>
27 <div class="field">
27 <div class="field">
28 <div class="label">
28 <div class="label">
29 <label for="repo_group">${_('Repository group')}:</label>
29 <label for="repo_group">${_('Repository group')}:</label>
30 </div>
30 </div>
31 <div class="input">
31 <div class="input">
32 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
32 ${h.select('repo_group',request.GET.get('parent_group'),c.repo_groups,class_="medium")}
33 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
33 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
34 </div>
34 </div>
35 </div>
35 </div>
36 <div class="field">
36 <div class="field">
37 <div class="label">
37 <div class="label">
38 <label for="repo_type">${_('Type')}:</label>
38 <label for="repo_type">${_('Type')}:</label>
39 </div>
39 </div>
40 <div class="input">
40 <div class="input">
41 ${h.select('repo_type','hg',c.backends,class_="small")}
41 ${h.select('repo_type','hg',c.backends,class_="small")}
42 <span class="help-block">${_('Type of repository to create.')}</span>
42 <span class="help-block">${_('Type of repository to create.')}</span>
43 </div>
43 </div>
44 </div>
44 </div>
45 <div class="field">
45 <div class="field">
46 <div class="label">
46 <div class="label">
47 <label for="landing_rev">${_('Landing revision')}:</label>
47 <label for="landing_rev">${_('Landing revision')}:</label>
48 </div>
48 </div>
49 <div class="input">
49 <div class="input">
50 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
50 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
51 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
51 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
52 </div>
52 </div>
53 </div>
53 </div>
54 <div class="field">
54 <div class="field">
55 <div class="label label-textarea">
55 <div class="label label-textarea">
56 <label for="description">${_('Description')}:</label>
56 <label for="description">${_('Description')}:</label>
57 </div>
57 </div>
58 <div class="textarea text-area editor">
58 <div class="textarea text-area editor">
59 ${h.textarea('description')}
59 ${h.textarea('description')}
60 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
60 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
61 </div>
61 </div>
62 </div>
62 </div>
63 <div class="field">
63 <div class="field">
64 <div class="label label-checkbox">
64 <div class="label label-checkbox">
65 <label for="private">${_('Private repository')}:</label>
65 <label for="private">${_('Private repository')}:</label>
66 </div>
66 </div>
67 <div class="checkboxes">
67 <div class="checkboxes">
68 ${h.checkbox('private',value="True")}
68 ${h.checkbox('private',value="True")}
69 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
69 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
70 </div>
70 </div>
71 </div>
71 </div>
72 <div class="buttons">
72 <div class="buttons">
73 ${h.submit('add',_('add'),class_="ui-button")}
73 ${h.submit('add',_('add'),class_="ui-button")}
74 </div>
74 </div>
75 </div>
75 </div>
76 </div>
76 </div>
77 ${h.end_form()}
77 ${h.end_form()}
@@ -1,240 +1,240 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 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
5 ${_('Edit repository')} ${c.repo_info.repo_name} - ${c.rhodecode_name}
6 </%def>
6 </%def>
7
7
8 <%def name="breadcrumbs_links()">
8 <%def name="breadcrumbs_links()">
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
9 ${h.link_to(_('Admin'),h.url('admin_home'))}
10 &raquo;
10 &raquo;
11 ${h.link_to(_('Repositories'),h.url('repos'))}
11 ${h.link_to(_('Repositories'),h.url('repos'))}
12 &raquo;
12 &raquo;
13 ${_('edit')} &raquo; ${h.link_to(c.repo_info.just_name,h.url('summary_home',repo_name=c.repo_name))}
13 ${_('edit')} &raquo; ${h.link_to(c.repo_info.just_name,h.url('summary_home',repo_name=c.repo_name))}
14 </%def>
14 </%def>
15
15
16 <%def name="page_nav()">
16 <%def name="page_nav()">
17 ${self.menu('admin')}
17 ${self.menu('admin')}
18 </%def>
18 </%def>
19
19
20 <%def name="main()">
20 <%def name="main()">
21 <div class="box box-left">
21 <div class="box box-left">
22 <!-- box / title -->
22 <!-- box / title -->
23 <div class="title">
23 <div class="title">
24 ${self.breadcrumbs()}
24 ${self.breadcrumbs()}
25 </div>
25 </div>
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
26 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='put')}
27 <div class="form">
27 <div class="form">
28 <!-- fields -->
28 <!-- fields -->
29 <div class="fields">
29 <div class="fields">
30 <div class="field">
30 <div class="field">
31 <div class="label">
31 <div class="label">
32 <label for="repo_name">${_('Name')}:</label>
32 <label for="repo_name">${_('Name')}:</label>
33 </div>
33 </div>
34 <div class="input">
34 <div class="input">
35 ${h.text('repo_name',class_="medium")}
35 ${h.text('repo_name',class_="medium")}
36 </div>
36 </div>
37 </div>
37 </div>
38 <div class="field">
38 <div class="field">
39 <div class="label">
39 <div class="label">
40 <label for="clone_uri">${_('Clone uri')}:</label>
40 <label for="clone_uri">${_('Clone uri')}:</label>
41 </div>
41 </div>
42 <div class="input">
42 <div class="input">
43 ${h.text('clone_uri',class_="medium")}
43 ${h.text('clone_uri',class_="medium")}
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
44 <span class="help-block">${_('Optional http[s] url from which repository should be cloned.')}</span>
45 </div>
45 </div>
46 </div>
46 </div>
47 <div class="field">
47 <div class="field">
48 <div class="label">
48 <div class="label">
49 <label for="repo_group">${_('Repository group')}:</label>
49 <label for="repo_group">${_('Repository group')}:</label>
50 </div>
50 </div>
51 <div class="input">
51 <div class="input">
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
52 ${h.select('repo_group','',c.repo_groups,class_="medium")}
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
53 <span class="help-block">${_('Optional select a group to put this repository into.')}</span>
54 </div>
54 </div>
55 </div>
55 </div>
56 <div class="field">
56 <div class="field">
57 <div class="label">
57 <div class="label">
58 <label for="repo_type">${_('Type')}:</label>
58 <label for="repo_type">${_('Type')}:</label>
59 </div>
59 </div>
60 <div class="input">
60 <div class="input">
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
61 ${h.select('repo_type','hg',c.backends,class_="medium")}
62 </div>
62 </div>
63 </div>
63 </div>
64 <div class="field">
64 <div class="field">
65 <div class="label">
65 <div class="label">
66 <label for="landing_rev">${_('Landing revision')}:</label>
66 <label for="landing_rev">${_('Landing revision')}:</label>
67 </div>
67 </div>
68 <div class="input">
68 <div class="input">
69 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
69 ${h.select('landing_rev','',c.landing_revs,class_="medium")}
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
70 <span class="help-block">${_('Default revision for files page, downloads, whoosh and readme')}</span>
71 </div>
71 </div>
72 </div>
72 </div>
73 <div class="field">
73 <div class="field">
74 <div class="label label-textarea">
74 <div class="label label-textarea">
75 <label for="description">${_('Description')}:</label>
75 <label for="description">${_('Description')}:</label>
76 </div>
76 </div>
77 <div class="textarea text-area editor">
77 <div class="textarea text-area editor">
78 ${h.textarea('description')}
78 ${h.textarea('description')}
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
79 <span class="help-block">${_('Keep it short and to the point. Use a README file for longer descriptions.')}</span>
80 </div>
80 </div>
81 </div>
81 </div>
82
82
83 <div class="field">
83 <div class="field">
84 <div class="label label-checkbox">
84 <div class="label label-checkbox">
85 <label for="private">${_('Private repository')}:</label>
85 <label for="private">${_('Private repository')}:</label>
86 </div>
86 </div>
87 <div class="checkboxes">
87 <div class="checkboxes">
88 ${h.checkbox('private',value="True")}
88 ${h.checkbox('private',value="True")}
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
89 <span class="help-block">${_('Private repositories are only visible to people explicitly added as collaborators.')}</span>
90 </div>
90 </div>
91 </div>
91 </div>
92 <div class="field">
92 <div class="field">
93 <div class="label label-checkbox">
93 <div class="label label-checkbox">
94 <label for="enable_statistics">${_('Enable statistics')}:</label>
94 <label for="enable_statistics">${_('Enable statistics')}:</label>
95 </div>
95 </div>
96 <div class="checkboxes">
96 <div class="checkboxes">
97 ${h.checkbox('enable_statistics',value="True")}
97 ${h.checkbox('enable_statistics',value="True")}
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
98 <span class="help-block">${_('Enable statistics window on summary page.')}</span>
99 </div>
99 </div>
100 </div>
100 </div>
101 <div class="field">
101 <div class="field">
102 <div class="label label-checkbox">
102 <div class="label label-checkbox">
103 <label for="enable_downloads">${_('Enable downloads')}:</label>
103 <label for="enable_downloads">${_('Enable downloads')}:</label>
104 </div>
104 </div>
105 <div class="checkboxes">
105 <div class="checkboxes">
106 ${h.checkbox('enable_downloads',value="True")}
106 ${h.checkbox('enable_downloads',value="True")}
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
107 <span class="help-block">${_('Enable download menu on summary page.')}</span>
108 </div>
108 </div>
109 </div>
109 </div>
110 <div class="field">
110 <div class="field">
111 <div class="label">
111 <div class="label">
112 <label for="user">${_('Owner')}:</label>
112 <label for="user">${_('Owner')}:</label>
113 </div>
113 </div>
114 <div class="input input-medium ac">
114 <div class="input input-medium ac">
115 <div class="perm_ac">
115 <div class="perm_ac">
116 ${h.text('user',class_='yui-ac-input')}
116 ${h.text('user',class_='yui-ac-input')}
117 <span class="help-block">${_('Change owner of this repository.')}</span>
117 <span class="help-block">${_('Change owner of this repository.')}</span>
118 <div id="owner_container"></div>
118 <div id="owner_container"></div>
119 </div>
119 </div>
120 </div>
120 </div>
121 </div>
121 </div>
122
122
123 <div class="field">
123 <div class="field">
124 <div class="label">
124 <div class="label">
125 <label for="input">${_('Permissions')}:</label>
125 <label for="input">${_('Permissions')}:</label>
126 </div>
126 </div>
127 <div class="input">
127 <div class="input">
128 <%include file="repo_edit_perms.html"/>
128 <%include file="repo_edit_perms.html"/>
129 </div>
129 </div>
130
130
131 <div class="buttons">
131 <div class="buttons">
132 ${h.submit('save','Save',class_="ui-button")}
132 ${h.submit('save','Save',class_="ui-button")}
133 ${h.reset('reset','Reset',class_="ui-button")}
133 ${h.reset('reset','Reset',class_="ui-button")}
134 </div>
134 </div>
135 </div>
135 </div>
136 </div>
136 </div>
137 </div>
137 </div>
138 ${h.end_form()}
138 ${h.end_form()}
139 </div>
139 </div>
140
140
141 <div class="box box-right">
141 <div class="box box-right">
142 <div class="title">
142 <div class="title">
143 <h5>${_('Administration')}</h5>
143 <h5>${_('Administration')}</h5>
144 </div>
144 </div>
145
145
146 <h3>${_('Statistics')}</h3>
146 <h3>${_('Statistics')}</h3>
147 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
147 ${h.form(url('repo_stats', repo_name=c.repo_info.repo_name),method='delete')}
148 <div class="form">
148 <div class="form">
149 <div class="fields">
149 <div class="fields">
150 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
150 ${h.submit('reset_stats_%s' % c.repo_info.repo_name,_('Reset current statistics'),class_="ui-btn",onclick="return confirm('"+_('Confirm to remove current statistics')+"');")}
151 <div class="field" style="border:none;color:#888">
151 <div class="field" style="border:none;color:#888">
152 <ul>
152 <ul>
153 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
153 <li>${_('Fetched to rev')}: ${c.stats_revision}/${c.repo_last_rev}</li>
154 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
154 <li>${_('Stats gathered')}: ${c.stats_percentage}%</li>
155 </ul>
155 </ul>
156 </div>
156 </div>
157 </div>
157 </div>
158 </div>
158 </div>
159 ${h.end_form()}
159 ${h.end_form()}
160
160
161 %if c.repo_info.clone_uri:
161 %if c.repo_info.clone_uri:
162 <h3>${_('Remote')}</h3>
162 <h3>${_('Remote')}</h3>
163 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
163 ${h.form(url('repo_pull', repo_name=c.repo_info.repo_name),method='put')}
164 <div class="form">
164 <div class="form">
165 <div class="fields">
165 <div class="fields">
166 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
166 ${h.submit('remote_pull_%s' % c.repo_info.repo_name,_('Pull changes from remote location'),class_="ui-btn",onclick="return confirm('"+_('Confirm to pull changes from remote side')+"');")}
167 <div class="field" style="border:none">
167 <div class="field" style="border:none">
168 <ul>
168 <ul>
169 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
169 <li><a href="${c.repo_info.clone_uri}">${c.repo_info.clone_uri}</a></li>
170 </ul>
170 </ul>
171 </div>
171 </div>
172 </div>
172 </div>
173 </div>
173 </div>
174 ${h.end_form()}
174 ${h.end_form()}
175 %endif
175 %endif
176
176
177 <h3>${_('Cache')}</h3>
177 <h3>${_('Cache')}</h3>
178 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
178 ${h.form(url('repo_cache', repo_name=c.repo_info.repo_name),method='delete')}
179 <div class="form">
179 <div class="form">
180 <div class="fields">
180 <div class="fields">
181 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
181 ${h.submit('reset_cache_%s' % c.repo_info.repo_name,_('Invalidate repository cache'),class_="ui-btn",onclick="return confirm('"+_('Confirm to invalidate repository cache')+"');")}
182 </div>
182 </div>
183 </div>
183 </div>
184 ${h.end_form()}
184 ${h.end_form()}
185
185
186 <h3>${_('Public journal')}</h3>
186 <h3>${_('Public journal')}</h3>
187 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
187 ${h.form(url('repo_public_journal', repo_name=c.repo_info.repo_name),method='put')}
188 <div class="form">
188 <div class="form">
189 ${h.hidden('auth_token',str(h.get_token()))}
189 ${h.hidden('auth_token',str(h.get_token()))}
190 <div class="field">
190 <div class="field">
191 %if c.in_public_journal:
191 %if c.in_public_journal:
192 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
192 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Remove from public journal'),class_="ui-btn")}
193 %else:
193 %else:
194 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
194 ${h.submit('set_public_%s' % c.repo_info.repo_name,_('Add to public journal'),class_="ui-btn")}
195 %endif
195 %endif
196 </div>
196 </div>
197 <div class="field" style="border:none;color:#888">
197 <div class="field" style="border:none;color:#888">
198 <ul>
198 <ul>
199 <li>${_('''All actions made on this repository will be accessible to everyone in public journal''')}
199 <li>${_('''All actions made on this repository will be accessible to everyone in public journal''')}
200 </li>
200 </li>
201 </ul>
201 </ul>
202 </div>
202 </div>
203 </div>
203 </div>
204 ${h.end_form()}
204 ${h.end_form()}
205
205
206 <h3>${_('Delete')}</h3>
206 <h3>${_('Delete')}</h3>
207 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
207 ${h.form(url('repo', repo_name=c.repo_info.repo_name),method='delete')}
208 <div class="form">
208 <div class="form">
209 <div class="fields">
209 <div class="fields">
210 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
210 ${h.submit('remove_%s' % c.repo_info.repo_name,_('Remove this repository'),class_="ui-btn red",onclick="return confirm('"+_('Confirm to delete this repository')+"');")}
211 </div>
211 </div>
212 <div class="field" style="border:none;color:#888">
212 <div class="field" style="border:none;color:#888">
213 <ul>
213 <ul>
214 <li>${_('''This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems.
214 <li>${_('''This repository will be renamed in a special way in order to be unaccesible for RhodeCode and VCS systems.
215 If you need fully delete it from filesystem please do it manually''')}
215 If you need fully delete it from filesystem please do it manually''')}
216 </li>
216 </li>
217 </ul>
217 </ul>
218 </div>
218 </div>
219 </div>
219 </div>
220 ${h.end_form()}
220 ${h.end_form()}
221
221
222 <h3>${_('Set as fork of')}</h3>
222 <h3>${_('Set as fork of')}</h3>
223 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
223 ${h.form(url('repo_as_fork', repo_name=c.repo_info.repo_name),method='put')}
224 <div class="form">
224 <div class="form">
225 <div class="fields">
225 <div class="fields">
226 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
226 ${h.select('id_fork_of','',c.repos_list,class_="medium")}
227 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
227 ${h.submit('set_as_fork_%s' % c.repo_info.repo_name,_('set'),class_="ui-btn",)}
228 </div>
228 </div>
229 <div class="field" style="border:none;color:#888">
229 <div class="field" style="border:none;color:#888">
230 <ul>
230 <ul>
231 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
231 <li>${_('''Manually set this repository as a fork of another from the list''')}</li>
232 </ul>
232 </ul>
233 </div>
233 </div>
234 </div>
234 </div>
235 ${h.end_form()}
235 ${h.end_form()}
236
236
237 </div>
237 </div>
238
238
239
239
240 </%def>
240 </%def>
@@ -1,126 +1,126 b''
1 <dl>
1 <dl>
2 <dt class="file_history">${_('History')}</dt>
2 <dt class="file_history">${_('History')}</dt>
3 <dd>
3 <dd>
4 <div>
4 <div>
5 <div style="float:left">
5 <div style="float:left">
6 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
6 ${h.form(h.url('files_diff_home',repo_name=c.repo_name,f_path=c.f_path),method='get')}
7 ${h.hidden('diff2',c.file.changeset.raw_id)}
7 ${h.hidden('diff2',c.file.changeset.raw_id)}
8 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
8 ${h.select('diff1',c.file.changeset.raw_id,c.file_history)}
9 ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
9 ${h.submit('diff',_('diff to revision'),class_="ui-btn")}
10 ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
10 ${h.submit('show_rev',_('show at revision'),class_="ui-btn")}
11 ${h.end_form()}
11 ${h.end_form()}
12 </div>
12 </div>
13 <div class="file_author">
13 <div class="file_author">
14 <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
14 <div class="item">${h.literal(ungettext(u'%s author',u'%s authors',len(c.authors)) % ('<b>%s</b>' % len(c.authors))) }</div>
15 %for email, user in c.authors:
15 %for email, user in c.authors:
16 <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
16 <div class="contributor tooltip" style="float:left" title="${h.tooltip(user)}">
17 <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
17 <div class="gravatar" style="margin:1px"><img alt="gravatar" src="${h.gravatar_url(email, 20)}"/> </div>
18 </div>
18 </div>
19 %endfor
19 %endfor
20 </div>
20 </div>
21 </div>
21 </div>
22 <div style="clear:both"></div>
22 <div style="clear:both"></div>
23 </dd>
23 </dd>
24
24
25 </dl>
25 </dl>
26
26
27 <div id="body" class="codeblock">
27 <div id="body" class="codeblock">
28 <div class="code-header">
28 <div class="code-header">
29 <div class="stats">
29 <div class="stats">
30 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
30 <div class="left img"><img src="${h.url('/images/icons/file.png')}"/></div>
31 <div class="left item"><pre class="tooltip" title="${h.tooltip(h.fmt_date(c.file.changeset.date))}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
31 <div class="left item"><pre class="tooltip" title="${h.tooltip(h.fmt_date(c.file.changeset.date))}">${h.link_to("r%s:%s" % (c.file.changeset.revision,h.short_id(c.file.changeset.raw_id)),h.url('changeset_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id))}</pre></div>
32 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
32 <div class="left item"><pre>${h.format_byte_size(c.file.size,binary=True)}</pre></div>
33 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
33 <div class="left item last"><pre>${c.file.mimetype}</pre></div>
34 <div class="buttons">
34 <div class="buttons">
35 %if c.annotate:
35 %if c.annotate:
36 ${h.link_to(_('show source'), h.url('files_home', repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
36 ${h.link_to(_('show source'), h.url('files_home', repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
37 %else:
37 %else:
38 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
38 ${h.link_to(_('show annotation'),h.url('files_annotate_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
39 %endif
39 %endif
40 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
40 ${h.link_to(_('show as raw'),h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
41 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
41 ${h.link_to(_('download as raw'),h.url('files_rawfile_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
42 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
42 % if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
43 % if not c.file.is_binary:
43 % if not c.file.is_binary:
44 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
44 ${h.link_to(_('edit'),h.url('files_edit_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path),class_="ui-btn")}
45 % endif
45 % endif
46 % endif
46 % endif
47 </div>
47 </div>
48 </div>
48 </div>
49 <div class="author">
49 <div class="author">
50 <div class="gravatar">
50 <div class="gravatar">
51 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
51 <img alt="gravatar" src="${h.gravatar_url(h.email(c.file.changeset.author),16)}"/>
52 </div>
52 </div>
53 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
53 <div title="${c.file.changeset.author}" class="user">${h.person(c.file.changeset.author)}</div>
54 </div>
54 </div>
55 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
55 <div class="commit">${h.urlify_commit(c.file.changeset.message,c.repo_name)}</div>
56 </div>
56 </div>
57 <div class="code-body">
57 <div class="code-body">
58 %if c.file.is_binary:
58 %if c.file.is_binary:
59 ${_('Binary file (%s)') % c.file.mimetype}
59 ${_('Binary file (%s)') % c.file.mimetype}
60 %else:
60 %else:
61 % if c.file.size < c.cut_off_limit:
61 % if c.file.size < c.cut_off_limit:
62 %if c.annotate:
62 %if c.annotate:
63 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
63 ${h.pygmentize_annotation(c.repo_name,c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
64 %else:
64 %else:
65 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
65 ${h.pygmentize(c.file,linenos=True,anchorlinenos=True,lineanchors='L',cssclass="code-highlight")}
66 %endif
66 %endif
67 %else:
67 %else:
68 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
68 ${_('File is too big to display')} ${h.link_to(_('show as raw'),
69 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
69 h.url('files_raw_home',repo_name=c.repo_name,revision=c.file.changeset.raw_id,f_path=c.f_path))}
70 %endif
70 %endif
71 %endif
71 %endif
72 </div>
72 </div>
73 </div>
73 </div>
74
74
75 <script type="text/javascript">
75 <script type="text/javascript">
76 YUE.onDOMReady(function(){
76 YUE.onDOMReady(function(){
77 function highlight_lines(lines){
77 function highlight_lines(lines){
78 for(pos in lines){
78 for(pos in lines){
79 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
79 YUD.setStyle('L'+lines[pos],'background-color','#FFFFBE');
80 }
80 }
81 }
81 }
82 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
82 page_highlights = location.href.substring(location.href.indexOf('#')+1).split('L');
83 if (page_highlights.length == 2){
83 if (page_highlights.length == 2){
84 highlight_ranges = page_highlights[1].split(",");
84 highlight_ranges = page_highlights[1].split(",");
85
85
86 var h_lines = [];
86 var h_lines = [];
87 for (pos in highlight_ranges){
87 for (pos in highlight_ranges){
88 var _range = highlight_ranges[pos].split('-');
88 var _range = highlight_ranges[pos].split('-');
89 if(_range.length == 2){
89 if(_range.length == 2){
90 var start = parseInt(_range[0]);
90 var start = parseInt(_range[0]);
91 var end = parseInt(_range[1]);
91 var end = parseInt(_range[1]);
92 if (start < end){
92 if (start < end){
93 for(var i=start;i<=end;i++){
93 for(var i=start;i<=end;i++){
94 h_lines.push(i);
94 h_lines.push(i);
95 }
95 }
96 }
96 }
97 }
97 }
98 else{
98 else{
99 h_lines.push(parseInt(highlight_ranges[pos]));
99 h_lines.push(parseInt(highlight_ranges[pos]));
100 }
100 }
101 }
101 }
102 highlight_lines(h_lines);
102 highlight_lines(h_lines);
103
103
104 //remember original location
104 //remember original location
105 var old_hash = location.href.substring(location.href.indexOf('#'));
105 var old_hash = location.href.substring(location.href.indexOf('#'));
106
106
107 // this makes a jump to anchor moved by 3 posstions for padding
107 // this makes a jump to anchor moved by 3 posstions for padding
108 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
108 window.location.hash = '#L'+Math.max(parseInt(h_lines[0])-3,1);
109
109
110 //sets old anchor
110 //sets old anchor
111 window.location.hash = old_hash;
111 window.location.hash = old_hash;
112
112
113 }
113 }
114 YUE.on('show_rev','click',function(e){
114 YUE.on('show_rev','click',function(e){
115 YUE.preventDefault(e);
115 YUE.preventDefault(e);
116 var cs = YUD.get('diff1').value;
116 var cs = YUD.get('diff1').value;
117 %if c.annotate:
117 %if c.annotate:
118 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
118 var url = "${h.url('files_annotate_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
119 %else:
119 %else:
120 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
120 var url = "${h.url('files_home',repo_name=c.repo_name,revision='__CS__',f_path=c.f_path)}".replace('__CS__',cs);
121 %endif
121 %endif
122 window.location = url;
122 window.location = url;
123 });
123 });
124 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
124 YUE.on('hlcode','mouseup',getSelectionLink("${_('Selection link')}"))
125 });
125 });
126 </script>
126 </script>
General Comments 0
You need to be logged in to leave comments. Login now