##// END OF EJS Templates
files: added updated new repo instructions.
marcink -
r3775:78fc7cee new-ui
parent child Browse files
Show More
@@ -1,1528 +1,1530 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2
2
3 # Copyright (C) 2011-2019 RhodeCode GmbH
3 # Copyright (C) 2011-2019 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 import itertools
21 import itertools
22 import logging
22 import logging
23 import os
23 import os
24 import shutil
24 import shutil
25 import tempfile
25 import tempfile
26 import collections
26 import collections
27 import urllib
27 import urllib
28 import pathlib2
28 import pathlib2
29
29
30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
30 from pyramid.httpexceptions import HTTPNotFound, HTTPBadRequest, HTTPFound
31 from pyramid.view import view_config
31 from pyramid.view import view_config
32 from pyramid.renderers import render
32 from pyramid.renderers import render
33 from pyramid.response import Response
33 from pyramid.response import Response
34
34
35 import rhodecode
35 import rhodecode
36 from rhodecode.apps._base import RepoAppView
36 from rhodecode.apps._base import RepoAppView
37
37
38
38
39 from rhodecode.lib import diffs, helpers as h, rc_cache
39 from rhodecode.lib import diffs, helpers as h, rc_cache
40 from rhodecode.lib import audit_logger
40 from rhodecode.lib import audit_logger
41 from rhodecode.lib.view_utils import parse_path_ref
41 from rhodecode.lib.view_utils import parse_path_ref
42 from rhodecode.lib.exceptions import NonRelativePathError
42 from rhodecode.lib.exceptions import NonRelativePathError
43 from rhodecode.lib.codeblocks import (
43 from rhodecode.lib.codeblocks import (
44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
44 filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
45 from rhodecode.lib.utils2 import (
45 from rhodecode.lib.utils2 import (
46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
46 convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1, safe_unicode)
47 from rhodecode.lib.auth import (
47 from rhodecode.lib.auth import (
48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
48 LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
49 from rhodecode.lib.vcs import path as vcspath
49 from rhodecode.lib.vcs import path as vcspath
50 from rhodecode.lib.vcs.backends.base import EmptyCommit
50 from rhodecode.lib.vcs.backends.base import EmptyCommit
51 from rhodecode.lib.vcs.conf import settings
51 from rhodecode.lib.vcs.conf import settings
52 from rhodecode.lib.vcs.nodes import FileNode
52 from rhodecode.lib.vcs.nodes import FileNode
53 from rhodecode.lib.vcs.exceptions import (
53 from rhodecode.lib.vcs.exceptions import (
54 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
54 RepositoryError, CommitDoesNotExistError, EmptyRepositoryError,
55 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
55 ImproperArchiveTypeError, VCSError, NodeAlreadyExistsError,
56 NodeDoesNotExistError, CommitError, NodeError)
56 NodeDoesNotExistError, CommitError, NodeError)
57
57
58 from rhodecode.model.scm import ScmModel
58 from rhodecode.model.scm import ScmModel
59 from rhodecode.model.db import Repository
59 from rhodecode.model.db import Repository
60
60
61 log = logging.getLogger(__name__)
61 log = logging.getLogger(__name__)
62
62
63
63
64 class RepoFilesView(RepoAppView):
64 class RepoFilesView(RepoAppView):
65
65
66 @staticmethod
66 @staticmethod
67 def adjust_file_path_for_svn(f_path, repo):
67 def adjust_file_path_for_svn(f_path, repo):
68 """
68 """
69 Computes the relative path of `f_path`.
69 Computes the relative path of `f_path`.
70
70
71 This is mainly based on prefix matching of the recognized tags and
71 This is mainly based on prefix matching of the recognized tags and
72 branches in the underlying repository.
72 branches in the underlying repository.
73 """
73 """
74 tags_and_branches = itertools.chain(
74 tags_and_branches = itertools.chain(
75 repo.branches.iterkeys(),
75 repo.branches.iterkeys(),
76 repo.tags.iterkeys())
76 repo.tags.iterkeys())
77 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
77 tags_and_branches = sorted(tags_and_branches, key=len, reverse=True)
78
78
79 for name in tags_and_branches:
79 for name in tags_and_branches:
80 if f_path.startswith('{}/'.format(name)):
80 if f_path.startswith('{}/'.format(name)):
81 f_path = vcspath.relpath(f_path, name)
81 f_path = vcspath.relpath(f_path, name)
82 break
82 break
83 return f_path
83 return f_path
84
84
85 def load_default_context(self):
85 def load_default_context(self):
86 c = self._get_local_tmpl_context(include_app_defaults=True)
86 c = self._get_local_tmpl_context(include_app_defaults=True)
87 c.rhodecode_repo = self.rhodecode_vcs_repo
87 c.rhodecode_repo = self.rhodecode_vcs_repo
88 c.enable_downloads = self.db_repo.enable_downloads
88 c.enable_downloads = self.db_repo.enable_downloads
89 return c
89 return c
90
90
91 def _ensure_not_locked(self, commit_id='tip'):
91 def _ensure_not_locked(self, commit_id='tip'):
92 _ = self.request.translate
92 _ = self.request.translate
93
93
94 repo = self.db_repo
94 repo = self.db_repo
95 if repo.enable_locking and repo.locked[0]:
95 if repo.enable_locking and repo.locked[0]:
96 h.flash(_('This repository has been locked by %s on %s')
96 h.flash(_('This repository has been locked by %s on %s')
97 % (h.person_by_id(repo.locked[0]),
97 % (h.person_by_id(repo.locked[0]),
98 h.format_date(h.time_to_datetime(repo.locked[1]))),
98 h.format_date(h.time_to_datetime(repo.locked[1]))),
99 'warning')
99 'warning')
100 files_url = h.route_path(
100 files_url = h.route_path(
101 'repo_files:default_path',
101 'repo_files:default_path',
102 repo_name=self.db_repo_name, commit_id=commit_id)
102 repo_name=self.db_repo_name, commit_id=commit_id)
103 raise HTTPFound(files_url)
103 raise HTTPFound(files_url)
104
104
105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
105 def forbid_non_head(self, is_head, f_path, commit_id='tip', json_mode=False):
106 _ = self.request.translate
106 _ = self.request.translate
107
107
108 if not is_head:
108 if not is_head:
109 message = _('You can only modify files with commit being a valid branch head.')
109 message = _('Cannot modify file. '
110 'Given commit `{}` is not head of a branch.').format(commit_id)
110 h.flash(message, category='warning')
111 h.flash(message, category='warning')
111
112
112 if json_mode:
113 if json_mode:
113 return message
114 return message
114
115
115 files_url = h.route_path(
116 files_url = h.route_path(
116 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
117 'repo_files', repo_name=self.db_repo_name, commit_id=commit_id,
117 f_path=f_path)
118 f_path=f_path)
118 raise HTTPFound(files_url)
119 raise HTTPFound(files_url)
119
120
120 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
121 def check_branch_permission(self, branch_name, commit_id='tip', json_mode=False):
121 _ = self.request.translate
122 _ = self.request.translate
122
123
123 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
124 rule, branch_perm = self._rhodecode_user.get_rule_and_branch_permission(
124 self.db_repo_name, branch_name)
125 self.db_repo_name, branch_name)
125 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
126 if branch_perm and branch_perm not in ['branch.push', 'branch.push_force']:
126 message = _('Branch `{}` changes forbidden by rule {}.').format(
127 message = _('Branch `{}` changes forbidden by rule {}.').format(
127 branch_name, rule)
128 branch_name, rule)
128 h.flash(message, 'warning')
129 h.flash(message, 'warning')
129
130
130 if json_mode:
131 if json_mode:
131 return message
132 return message
132
133
133 files_url = h.route_path(
134 files_url = h.route_path(
134 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
135 'repo_files:default_path', repo_name=self.db_repo_name, commit_id=commit_id)
135
136
136 raise HTTPFound(files_url)
137 raise HTTPFound(files_url)
137
138
138 def _get_commit_and_path(self):
139 def _get_commit_and_path(self):
139 default_commit_id = self.db_repo.landing_rev[1]
140 default_commit_id = self.db_repo.landing_rev[1]
140 default_f_path = '/'
141 default_f_path = '/'
141
142
142 commit_id = self.request.matchdict.get(
143 commit_id = self.request.matchdict.get(
143 'commit_id', default_commit_id)
144 'commit_id', default_commit_id)
144 f_path = self._get_f_path(self.request.matchdict, default_f_path)
145 f_path = self._get_f_path(self.request.matchdict, default_f_path)
145 return commit_id, f_path
146 return commit_id, f_path
146
147
147 def _get_default_encoding(self, c):
148 def _get_default_encoding(self, c):
148 enc_list = getattr(c, 'default_encodings', [])
149 enc_list = getattr(c, 'default_encodings', [])
149 return enc_list[0] if enc_list else 'UTF-8'
150 return enc_list[0] if enc_list else 'UTF-8'
150
151
151 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
152 def _get_commit_or_redirect(self, commit_id, redirect_after=True):
152 """
153 """
153 This is a safe way to get commit. If an error occurs it redirects to
154 This is a safe way to get commit. If an error occurs it redirects to
154 tip with proper message
155 tip with proper message
155
156
156 :param commit_id: id of commit to fetch
157 :param commit_id: id of commit to fetch
157 :param redirect_after: toggle redirection
158 :param redirect_after: toggle redirection
158 """
159 """
159 _ = self.request.translate
160 _ = self.request.translate
160
161
161 try:
162 try:
162 return self.rhodecode_vcs_repo.get_commit(commit_id)
163 return self.rhodecode_vcs_repo.get_commit(commit_id)
163 except EmptyRepositoryError:
164 except EmptyRepositoryError:
164 if not redirect_after:
165 if not redirect_after:
165 return None
166 return None
166
167
167 _url = h.route_path(
168 _url = h.route_path(
168 'repo_files_add_file',
169 'repo_files_add_file',
169 repo_name=self.db_repo_name, commit_id=0, f_path='')
170 repo_name=self.db_repo_name, commit_id=0, f_path='')
170
171
171 if h.HasRepoPermissionAny(
172 if h.HasRepoPermissionAny(
172 'repository.write', 'repository.admin')(self.db_repo_name):
173 'repository.write', 'repository.admin')(self.db_repo_name):
173 add_new = h.link_to(
174 add_new = h.link_to(
174 _('Click here to add a new file.'), _url, class_="alert-link")
175 _('Click here to add a new file.'), _url, class_="alert-link")
175 else:
176 else:
176 add_new = ""
177 add_new = ""
177
178
178 h.flash(h.literal(
179 h.flash(h.literal(
179 _('There are no files yet. %s') % add_new), category='warning')
180 _('There are no files yet. %s') % add_new), category='warning')
180 raise HTTPFound(
181 raise HTTPFound(
181 h.route_path('repo_summary', repo_name=self.db_repo_name))
182 h.route_path('repo_summary', repo_name=self.db_repo_name))
182
183
183 except (CommitDoesNotExistError, LookupError):
184 except (CommitDoesNotExistError, LookupError):
184 msg = _('No such commit exists for this repository')
185 msg = _('No such commit exists for this repository')
185 h.flash(msg, category='error')
186 h.flash(msg, category='error')
186 raise HTTPNotFound()
187 raise HTTPNotFound()
187 except RepositoryError as e:
188 except RepositoryError as e:
188 h.flash(safe_str(h.escape(e)), category='error')
189 h.flash(safe_str(h.escape(e)), category='error')
189 raise HTTPNotFound()
190 raise HTTPNotFound()
190
191
191 def _get_filenode_or_redirect(self, commit_obj, path):
192 def _get_filenode_or_redirect(self, commit_obj, path):
192 """
193 """
193 Returns file_node, if error occurs or given path is directory,
194 Returns file_node, if error occurs or given path is directory,
194 it'll redirect to top level path
195 it'll redirect to top level path
195 """
196 """
196 _ = self.request.translate
197 _ = self.request.translate
197
198
198 try:
199 try:
199 file_node = commit_obj.get_node(path)
200 file_node = commit_obj.get_node(path)
200 if file_node.is_dir():
201 if file_node.is_dir():
201 raise RepositoryError('The given path is a directory')
202 raise RepositoryError('The given path is a directory')
202 except CommitDoesNotExistError:
203 except CommitDoesNotExistError:
203 log.exception('No such commit exists for this repository')
204 log.exception('No such commit exists for this repository')
204 h.flash(_('No such commit exists for this repository'), category='error')
205 h.flash(_('No such commit exists for this repository'), category='error')
205 raise HTTPNotFound()
206 raise HTTPNotFound()
206 except RepositoryError as e:
207 except RepositoryError as e:
207 log.warning('Repository error while fetching '
208 log.warning('Repository error while fetching '
208 'filenode `%s`. Err:%s', path, e)
209 'filenode `%s`. Err:%s', path, e)
209 h.flash(safe_str(h.escape(e)), category='error')
210 h.flash(safe_str(h.escape(e)), category='error')
210 raise HTTPNotFound()
211 raise HTTPNotFound()
211
212
212 return file_node
213 return file_node
213
214
214 def _is_valid_head(self, commit_id, repo):
215 def _is_valid_head(self, commit_id, repo):
215 branch_name = sha_commit_id = ''
216 branch_name = sha_commit_id = ''
216 is_head = False
217 is_head = False
218 log.debug('Checking if commit_id %s is a head.', commit_id)
217
219
218 if h.is_svn(repo) and not repo.is_empty():
220 if h.is_svn(repo) and not repo.is_empty():
219 # Note: Subversion only has one head.
221 # Note: Subversion only has one head.
220 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
222 if commit_id == repo.get_commit(commit_idx=-1).raw_id:
221 is_head = True
223 is_head = True
222 return branch_name, sha_commit_id, is_head
224 return branch_name, sha_commit_id, is_head
223
225
224 for _branch_name, branch_commit_id in repo.branches.items():
226 for _branch_name, branch_commit_id in repo.branches.items():
225 # simple case we pass in branch name, it's a HEAD
227 # simple case we pass in branch name, it's a HEAD
226 if commit_id == _branch_name:
228 if commit_id == _branch_name:
227 is_head = True
229 is_head = True
228 branch_name = _branch_name
230 branch_name = _branch_name
229 sha_commit_id = branch_commit_id
231 sha_commit_id = branch_commit_id
230 break
232 break
231 # case when we pass in full sha commit_id, which is a head
233 # case when we pass in full sha commit_id, which is a head
232 elif commit_id == branch_commit_id:
234 elif commit_id == branch_commit_id:
233 is_head = True
235 is_head = True
234 branch_name = _branch_name
236 branch_name = _branch_name
235 sha_commit_id = branch_commit_id
237 sha_commit_id = branch_commit_id
236 break
238 break
237
239
238 # checked branches, means we only need to try to get the branch/commit_sha
240 # checked branches, means we only need to try to get the branch/commit_sha
239 if not repo.is_empty():
241 if not repo.is_empty():
240 commit = repo.get_commit(commit_id=commit_id)
242 commit = repo.get_commit(commit_id=commit_id)
241 if commit:
243 if commit:
242 branch_name = commit.branch
244 branch_name = commit.branch
243 sha_commit_id = commit.raw_id
245 sha_commit_id = commit.raw_id
244
246
245 return branch_name, sha_commit_id, is_head
247 return branch_name, sha_commit_id, is_head
246
248
247 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False):
249 def _get_tree_at_commit(self, c, commit_id, f_path, full_load=False):
248
250
249 repo_id = self.db_repo.repo_id
251 repo_id = self.db_repo.repo_id
250 force_recache = self.get_recache_flag()
252 force_recache = self.get_recache_flag()
251
253
252 cache_seconds = safe_int(
254 cache_seconds = safe_int(
253 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
255 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
254 cache_on = not force_recache and cache_seconds > 0
256 cache_on = not force_recache and cache_seconds > 0
255 log.debug(
257 log.debug(
256 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
258 'Computing FILE TREE for repo_id %s commit_id `%s` and path `%s`'
257 'with caching: %s[TTL: %ss]' % (
259 'with caching: %s[TTL: %ss]' % (
258 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
260 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
259
261
260 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
262 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
261 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
263 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
262
264
263 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
265 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
264 condition=cache_on)
266 condition=cache_on)
265 def compute_file_tree(ver, repo_id, commit_id, f_path, full_load):
267 def compute_file_tree(ver, repo_id, commit_id, f_path, full_load):
266 log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
268 log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
267 ver, repo_id, commit_id, f_path)
269 ver, repo_id, commit_id, f_path)
268
270
269 c.full_load = full_load
271 c.full_load = full_load
270 return render(
272 return render(
271 'rhodecode:templates/files/files_browser_tree.mako',
273 'rhodecode:templates/files/files_browser_tree.mako',
272 self._get_template_context(c), self.request)
274 self._get_template_context(c), self.request)
273
275
274 return compute_file_tree('v1', self.db_repo.repo_id, commit_id, f_path, full_load)
276 return compute_file_tree('v1', self.db_repo.repo_id, commit_id, f_path, full_load)
275
277
276 def _get_archive_spec(self, fname):
278 def _get_archive_spec(self, fname):
277 log.debug('Detecting archive spec for: `%s`', fname)
279 log.debug('Detecting archive spec for: `%s`', fname)
278
280
279 fileformat = None
281 fileformat = None
280 ext = None
282 ext = None
281 content_type = None
283 content_type = None
282 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
284 for a_type, content_type, extension in settings.ARCHIVE_SPECS:
283
285
284 if fname.endswith(extension):
286 if fname.endswith(extension):
285 fileformat = a_type
287 fileformat = a_type
286 log.debug('archive is of type: %s', fileformat)
288 log.debug('archive is of type: %s', fileformat)
287 ext = extension
289 ext = extension
288 break
290 break
289
291
290 if not fileformat:
292 if not fileformat:
291 raise ValueError()
293 raise ValueError()
292
294
293 # left over part of whole fname is the commit
295 # left over part of whole fname is the commit
294 commit_id = fname[:-len(ext)]
296 commit_id = fname[:-len(ext)]
295
297
296 return commit_id, ext, fileformat, content_type
298 return commit_id, ext, fileformat, content_type
297
299
298 def create_pure_path(self, *parts):
300 def create_pure_path(self, *parts):
299 # Split paths and sanitize them, removing any ../ etc
301 # Split paths and sanitize them, removing any ../ etc
300 sanitized_path = [
302 sanitized_path = [
301 x for x in pathlib2.PurePath(*parts).parts
303 x for x in pathlib2.PurePath(*parts).parts
302 if x not in ['.', '..']]
304 if x not in ['.', '..']]
303
305
304 pure_path = pathlib2.PurePath(*sanitized_path)
306 pure_path = pathlib2.PurePath(*sanitized_path)
305 return pure_path
307 return pure_path
306
308
307 @LoginRequired()
309 @LoginRequired()
308 @HasRepoPermissionAnyDecorator(
310 @HasRepoPermissionAnyDecorator(
309 'repository.read', 'repository.write', 'repository.admin')
311 'repository.read', 'repository.write', 'repository.admin')
310 @view_config(
312 @view_config(
311 route_name='repo_archivefile', request_method='GET',
313 route_name='repo_archivefile', request_method='GET',
312 renderer=None)
314 renderer=None)
313 def repo_archivefile(self):
315 def repo_archivefile(self):
314 # archive cache config
316 # archive cache config
315 from rhodecode import CONFIG
317 from rhodecode import CONFIG
316 _ = self.request.translate
318 _ = self.request.translate
317 self.load_default_context()
319 self.load_default_context()
318 default_at_path = '/'
320 default_at_path = '/'
319 fname = self.request.matchdict['fname']
321 fname = self.request.matchdict['fname']
320 subrepos = self.request.GET.get('subrepos') == 'true'
322 subrepos = self.request.GET.get('subrepos') == 'true'
321 at_path = self.request.GET.get('at_path') or default_at_path
323 at_path = self.request.GET.get('at_path') or default_at_path
322
324
323 if not self.db_repo.enable_downloads:
325 if not self.db_repo.enable_downloads:
324 return Response(_('Downloads disabled'))
326 return Response(_('Downloads disabled'))
325
327
326 try:
328 try:
327 commit_id, ext, fileformat, content_type = \
329 commit_id, ext, fileformat, content_type = \
328 self._get_archive_spec(fname)
330 self._get_archive_spec(fname)
329 except ValueError:
331 except ValueError:
330 return Response(_('Unknown archive type for: `{}`').format(
332 return Response(_('Unknown archive type for: `{}`').format(
331 h.escape(fname)))
333 h.escape(fname)))
332
334
333 try:
335 try:
334 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
336 commit = self.rhodecode_vcs_repo.get_commit(commit_id)
335 except CommitDoesNotExistError:
337 except CommitDoesNotExistError:
336 return Response(_('Unknown commit_id {}').format(
338 return Response(_('Unknown commit_id {}').format(
337 h.escape(commit_id)))
339 h.escape(commit_id)))
338 except EmptyRepositoryError:
340 except EmptyRepositoryError:
339 return Response(_('Empty repository'))
341 return Response(_('Empty repository'))
340
342
341 try:
343 try:
342 at_path = commit.get_node(at_path).path or default_at_path
344 at_path = commit.get_node(at_path).path or default_at_path
343 except Exception:
345 except Exception:
344 return Response(_('No node at path {} for this repository').format(at_path))
346 return Response(_('No node at path {} for this repository').format(at_path))
345
347
346 path_sha = sha1(at_path)[:8]
348 path_sha = sha1(at_path)[:8]
347
349
348 # original backward compat name of archive
350 # original backward compat name of archive
349 clean_name = safe_str(self.db_repo_name.replace('/', '_'))
351 clean_name = safe_str(self.db_repo_name.replace('/', '_'))
350 short_sha = safe_str(commit.short_id)
352 short_sha = safe_str(commit.short_id)
351
353
352 if at_path == default_at_path:
354 if at_path == default_at_path:
353 archive_name = '{}-{}{}{}'.format(
355 archive_name = '{}-{}{}{}'.format(
354 clean_name,
356 clean_name,
355 '-sub' if subrepos else '',
357 '-sub' if subrepos else '',
356 short_sha,
358 short_sha,
357 ext)
359 ext)
358 # custom path and new name
360 # custom path and new name
359 else:
361 else:
360 archive_name = '{}-{}{}-{}{}'.format(
362 archive_name = '{}-{}{}-{}{}'.format(
361 clean_name,
363 clean_name,
362 '-sub' if subrepos else '',
364 '-sub' if subrepos else '',
363 short_sha,
365 short_sha,
364 path_sha,
366 path_sha,
365 ext)
367 ext)
366
368
367 use_cached_archive = False
369 use_cached_archive = False
368 archive_cache_enabled = CONFIG.get(
370 archive_cache_enabled = CONFIG.get(
369 'archive_cache_dir') and not self.request.GET.get('no_cache')
371 'archive_cache_dir') and not self.request.GET.get('no_cache')
370 cached_archive_path = None
372 cached_archive_path = None
371
373
372 if archive_cache_enabled:
374 if archive_cache_enabled:
373 # check if we it's ok to write
375 # check if we it's ok to write
374 if not os.path.isdir(CONFIG['archive_cache_dir']):
376 if not os.path.isdir(CONFIG['archive_cache_dir']):
375 os.makedirs(CONFIG['archive_cache_dir'])
377 os.makedirs(CONFIG['archive_cache_dir'])
376 cached_archive_path = os.path.join(
378 cached_archive_path = os.path.join(
377 CONFIG['archive_cache_dir'], archive_name)
379 CONFIG['archive_cache_dir'], archive_name)
378 if os.path.isfile(cached_archive_path):
380 if os.path.isfile(cached_archive_path):
379 log.debug('Found cached archive in %s', cached_archive_path)
381 log.debug('Found cached archive in %s', cached_archive_path)
380 fd, archive = None, cached_archive_path
382 fd, archive = None, cached_archive_path
381 use_cached_archive = True
383 use_cached_archive = True
382 else:
384 else:
383 log.debug('Archive %s is not yet cached', archive_name)
385 log.debug('Archive %s is not yet cached', archive_name)
384
386
385 if not use_cached_archive:
387 if not use_cached_archive:
386 # generate new archive
388 # generate new archive
387 fd, archive = tempfile.mkstemp()
389 fd, archive = tempfile.mkstemp()
388 log.debug('Creating new temp archive in %s', archive)
390 log.debug('Creating new temp archive in %s', archive)
389 try:
391 try:
390 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
392 commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
391 archive_at_path=at_path)
393 archive_at_path=at_path)
392 except ImproperArchiveTypeError:
394 except ImproperArchiveTypeError:
393 return _('Unknown archive type')
395 return _('Unknown archive type')
394 if archive_cache_enabled:
396 if archive_cache_enabled:
395 # if we generated the archive and we have cache enabled
397 # if we generated the archive and we have cache enabled
396 # let's use this for future
398 # let's use this for future
397 log.debug('Storing new archive in %s', cached_archive_path)
399 log.debug('Storing new archive in %s', cached_archive_path)
398 shutil.move(archive, cached_archive_path)
400 shutil.move(archive, cached_archive_path)
399 archive = cached_archive_path
401 archive = cached_archive_path
400
402
401 # store download action
403 # store download action
402 audit_logger.store_web(
404 audit_logger.store_web(
403 'repo.archive.download', action_data={
405 'repo.archive.download', action_data={
404 'user_agent': self.request.user_agent,
406 'user_agent': self.request.user_agent,
405 'archive_name': archive_name,
407 'archive_name': archive_name,
406 'archive_spec': fname,
408 'archive_spec': fname,
407 'archive_cached': use_cached_archive},
409 'archive_cached': use_cached_archive},
408 user=self._rhodecode_user,
410 user=self._rhodecode_user,
409 repo=self.db_repo,
411 repo=self.db_repo,
410 commit=True
412 commit=True
411 )
413 )
412
414
413 def get_chunked_archive(archive_path):
415 def get_chunked_archive(archive_path):
414 with open(archive_path, 'rb') as stream:
416 with open(archive_path, 'rb') as stream:
415 while True:
417 while True:
416 data = stream.read(16 * 1024)
418 data = stream.read(16 * 1024)
417 if not data:
419 if not data:
418 if fd: # fd means we used temporary file
420 if fd: # fd means we used temporary file
419 os.close(fd)
421 os.close(fd)
420 if not archive_cache_enabled:
422 if not archive_cache_enabled:
421 log.debug('Destroying temp archive %s', archive_path)
423 log.debug('Destroying temp archive %s', archive_path)
422 os.remove(archive_path)
424 os.remove(archive_path)
423 break
425 break
424 yield data
426 yield data
425
427
426 response = Response(app_iter=get_chunked_archive(archive))
428 response = Response(app_iter=get_chunked_archive(archive))
427 response.content_disposition = str(
429 response.content_disposition = str(
428 'attachment; filename=%s' % archive_name)
430 'attachment; filename=%s' % archive_name)
429 response.content_type = str(content_type)
431 response.content_type = str(content_type)
430
432
431 return response
433 return response
432
434
433 def _get_file_node(self, commit_id, f_path):
435 def _get_file_node(self, commit_id, f_path):
434 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
436 if commit_id not in ['', None, 'None', '0' * 12, '0' * 40]:
435 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
437 commit = self.rhodecode_vcs_repo.get_commit(commit_id=commit_id)
436 try:
438 try:
437 node = commit.get_node(f_path)
439 node = commit.get_node(f_path)
438 if node.is_dir():
440 if node.is_dir():
439 raise NodeError('%s path is a %s not a file'
441 raise NodeError('%s path is a %s not a file'
440 % (node, type(node)))
442 % (node, type(node)))
441 except NodeDoesNotExistError:
443 except NodeDoesNotExistError:
442 commit = EmptyCommit(
444 commit = EmptyCommit(
443 commit_id=commit_id,
445 commit_id=commit_id,
444 idx=commit.idx,
446 idx=commit.idx,
445 repo=commit.repository,
447 repo=commit.repository,
446 alias=commit.repository.alias,
448 alias=commit.repository.alias,
447 message=commit.message,
449 message=commit.message,
448 author=commit.author,
450 author=commit.author,
449 date=commit.date)
451 date=commit.date)
450 node = FileNode(f_path, '', commit=commit)
452 node = FileNode(f_path, '', commit=commit)
451 else:
453 else:
452 commit = EmptyCommit(
454 commit = EmptyCommit(
453 repo=self.rhodecode_vcs_repo,
455 repo=self.rhodecode_vcs_repo,
454 alias=self.rhodecode_vcs_repo.alias)
456 alias=self.rhodecode_vcs_repo.alias)
455 node = FileNode(f_path, '', commit=commit)
457 node = FileNode(f_path, '', commit=commit)
456 return node
458 return node
457
459
458 @LoginRequired()
460 @LoginRequired()
459 @HasRepoPermissionAnyDecorator(
461 @HasRepoPermissionAnyDecorator(
460 'repository.read', 'repository.write', 'repository.admin')
462 'repository.read', 'repository.write', 'repository.admin')
461 @view_config(
463 @view_config(
462 route_name='repo_files_diff', request_method='GET',
464 route_name='repo_files_diff', request_method='GET',
463 renderer=None)
465 renderer=None)
464 def repo_files_diff(self):
466 def repo_files_diff(self):
465 c = self.load_default_context()
467 c = self.load_default_context()
466 f_path = self._get_f_path(self.request.matchdict)
468 f_path = self._get_f_path(self.request.matchdict)
467 diff1 = self.request.GET.get('diff1', '')
469 diff1 = self.request.GET.get('diff1', '')
468 diff2 = self.request.GET.get('diff2', '')
470 diff2 = self.request.GET.get('diff2', '')
469
471
470 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
472 path1, diff1 = parse_path_ref(diff1, default_path=f_path)
471
473
472 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
474 ignore_whitespace = str2bool(self.request.GET.get('ignorews'))
473 line_context = self.request.GET.get('context', 3)
475 line_context = self.request.GET.get('context', 3)
474
476
475 if not any((diff1, diff2)):
477 if not any((diff1, diff2)):
476 h.flash(
478 h.flash(
477 'Need query parameter "diff1" or "diff2" to generate a diff.',
479 'Need query parameter "diff1" or "diff2" to generate a diff.',
478 category='error')
480 category='error')
479 raise HTTPBadRequest()
481 raise HTTPBadRequest()
480
482
481 c.action = self.request.GET.get('diff')
483 c.action = self.request.GET.get('diff')
482 if c.action not in ['download', 'raw']:
484 if c.action not in ['download', 'raw']:
483 compare_url = h.route_path(
485 compare_url = h.route_path(
484 'repo_compare',
486 'repo_compare',
485 repo_name=self.db_repo_name,
487 repo_name=self.db_repo_name,
486 source_ref_type='rev',
488 source_ref_type='rev',
487 source_ref=diff1,
489 source_ref=diff1,
488 target_repo=self.db_repo_name,
490 target_repo=self.db_repo_name,
489 target_ref_type='rev',
491 target_ref_type='rev',
490 target_ref=diff2,
492 target_ref=diff2,
491 _query=dict(f_path=f_path))
493 _query=dict(f_path=f_path))
492 # redirect to new view if we render diff
494 # redirect to new view if we render diff
493 raise HTTPFound(compare_url)
495 raise HTTPFound(compare_url)
494
496
495 try:
497 try:
496 node1 = self._get_file_node(diff1, path1)
498 node1 = self._get_file_node(diff1, path1)
497 node2 = self._get_file_node(diff2, f_path)
499 node2 = self._get_file_node(diff2, f_path)
498 except (RepositoryError, NodeError):
500 except (RepositoryError, NodeError):
499 log.exception("Exception while trying to get node from repository")
501 log.exception("Exception while trying to get node from repository")
500 raise HTTPFound(
502 raise HTTPFound(
501 h.route_path('repo_files', repo_name=self.db_repo_name,
503 h.route_path('repo_files', repo_name=self.db_repo_name,
502 commit_id='tip', f_path=f_path))
504 commit_id='tip', f_path=f_path))
503
505
504 if all(isinstance(node.commit, EmptyCommit)
506 if all(isinstance(node.commit, EmptyCommit)
505 for node in (node1, node2)):
507 for node in (node1, node2)):
506 raise HTTPNotFound()
508 raise HTTPNotFound()
507
509
508 c.commit_1 = node1.commit
510 c.commit_1 = node1.commit
509 c.commit_2 = node2.commit
511 c.commit_2 = node2.commit
510
512
511 if c.action == 'download':
513 if c.action == 'download':
512 _diff = diffs.get_gitdiff(node1, node2,
514 _diff = diffs.get_gitdiff(node1, node2,
513 ignore_whitespace=ignore_whitespace,
515 ignore_whitespace=ignore_whitespace,
514 context=line_context)
516 context=line_context)
515 diff = diffs.DiffProcessor(_diff, format='gitdiff')
517 diff = diffs.DiffProcessor(_diff, format='gitdiff')
516
518
517 response = Response(self.path_filter.get_raw_patch(diff))
519 response = Response(self.path_filter.get_raw_patch(diff))
518 response.content_type = 'text/plain'
520 response.content_type = 'text/plain'
519 response.content_disposition = (
521 response.content_disposition = (
520 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
522 'attachment; filename=%s_%s_vs_%s.diff' % (f_path, diff1, diff2)
521 )
523 )
522 charset = self._get_default_encoding(c)
524 charset = self._get_default_encoding(c)
523 if charset:
525 if charset:
524 response.charset = charset
526 response.charset = charset
525 return response
527 return response
526
528
527 elif c.action == 'raw':
529 elif c.action == 'raw':
528 _diff = diffs.get_gitdiff(node1, node2,
530 _diff = diffs.get_gitdiff(node1, node2,
529 ignore_whitespace=ignore_whitespace,
531 ignore_whitespace=ignore_whitespace,
530 context=line_context)
532 context=line_context)
531 diff = diffs.DiffProcessor(_diff, format='gitdiff')
533 diff = diffs.DiffProcessor(_diff, format='gitdiff')
532
534
533 response = Response(self.path_filter.get_raw_patch(diff))
535 response = Response(self.path_filter.get_raw_patch(diff))
534 response.content_type = 'text/plain'
536 response.content_type = 'text/plain'
535 charset = self._get_default_encoding(c)
537 charset = self._get_default_encoding(c)
536 if charset:
538 if charset:
537 response.charset = charset
539 response.charset = charset
538 return response
540 return response
539
541
540 # in case we ever end up here
542 # in case we ever end up here
541 raise HTTPNotFound()
543 raise HTTPNotFound()
542
544
543 @LoginRequired()
545 @LoginRequired()
544 @HasRepoPermissionAnyDecorator(
546 @HasRepoPermissionAnyDecorator(
545 'repository.read', 'repository.write', 'repository.admin')
547 'repository.read', 'repository.write', 'repository.admin')
546 @view_config(
548 @view_config(
547 route_name='repo_files_diff_2way_redirect', request_method='GET',
549 route_name='repo_files_diff_2way_redirect', request_method='GET',
548 renderer=None)
550 renderer=None)
549 def repo_files_diff_2way_redirect(self):
551 def repo_files_diff_2way_redirect(self):
550 """
552 """
551 Kept only to make OLD links work
553 Kept only to make OLD links work
552 """
554 """
553 f_path = self._get_f_path_unchecked(self.request.matchdict)
555 f_path = self._get_f_path_unchecked(self.request.matchdict)
554 diff1 = self.request.GET.get('diff1', '')
556 diff1 = self.request.GET.get('diff1', '')
555 diff2 = self.request.GET.get('diff2', '')
557 diff2 = self.request.GET.get('diff2', '')
556
558
557 if not any((diff1, diff2)):
559 if not any((diff1, diff2)):
558 h.flash(
560 h.flash(
559 'Need query parameter "diff1" or "diff2" to generate a diff.',
561 'Need query parameter "diff1" or "diff2" to generate a diff.',
560 category='error')
562 category='error')
561 raise HTTPBadRequest()
563 raise HTTPBadRequest()
562
564
563 compare_url = h.route_path(
565 compare_url = h.route_path(
564 'repo_compare',
566 'repo_compare',
565 repo_name=self.db_repo_name,
567 repo_name=self.db_repo_name,
566 source_ref_type='rev',
568 source_ref_type='rev',
567 source_ref=diff1,
569 source_ref=diff1,
568 target_ref_type='rev',
570 target_ref_type='rev',
569 target_ref=diff2,
571 target_ref=diff2,
570 _query=dict(f_path=f_path, diffmode='sideside',
572 _query=dict(f_path=f_path, diffmode='sideside',
571 target_repo=self.db_repo_name,))
573 target_repo=self.db_repo_name,))
572 raise HTTPFound(compare_url)
574 raise HTTPFound(compare_url)
573
575
574 @LoginRequired()
576 @LoginRequired()
575 @HasRepoPermissionAnyDecorator(
577 @HasRepoPermissionAnyDecorator(
576 'repository.read', 'repository.write', 'repository.admin')
578 'repository.read', 'repository.write', 'repository.admin')
577 @view_config(
579 @view_config(
578 route_name='repo_files', request_method='GET',
580 route_name='repo_files', request_method='GET',
579 renderer=None)
581 renderer=None)
580 @view_config(
582 @view_config(
581 route_name='repo_files:default_path', request_method='GET',
583 route_name='repo_files:default_path', request_method='GET',
582 renderer=None)
584 renderer=None)
583 @view_config(
585 @view_config(
584 route_name='repo_files:default_commit', request_method='GET',
586 route_name='repo_files:default_commit', request_method='GET',
585 renderer=None)
587 renderer=None)
586 @view_config(
588 @view_config(
587 route_name='repo_files:rendered', request_method='GET',
589 route_name='repo_files:rendered', request_method='GET',
588 renderer=None)
590 renderer=None)
589 @view_config(
591 @view_config(
590 route_name='repo_files:annotated', request_method='GET',
592 route_name='repo_files:annotated', request_method='GET',
591 renderer=None)
593 renderer=None)
592 def repo_files(self):
594 def repo_files(self):
593 c = self.load_default_context()
595 c = self.load_default_context()
594
596
595 view_name = getattr(self.request.matched_route, 'name', None)
597 view_name = getattr(self.request.matched_route, 'name', None)
596
598
597 c.annotate = view_name == 'repo_files:annotated'
599 c.annotate = view_name == 'repo_files:annotated'
598 # default is false, but .rst/.md files later are auto rendered, we can
600 # default is false, but .rst/.md files later are auto rendered, we can
599 # overwrite auto rendering by setting this GET flag
601 # overwrite auto rendering by setting this GET flag
600 c.renderer = view_name == 'repo_files:rendered' or \
602 c.renderer = view_name == 'repo_files:rendered' or \
601 not self.request.GET.get('no-render', False)
603 not self.request.GET.get('no-render', False)
602
604
603 # redirect to given commit_id from form if given
605 # redirect to given commit_id from form if given
604 get_commit_id = self.request.GET.get('at_rev', None)
606 get_commit_id = self.request.GET.get('at_rev', None)
605 if get_commit_id:
607 if get_commit_id:
606 self._get_commit_or_redirect(get_commit_id)
608 self._get_commit_or_redirect(get_commit_id)
607
609
608 commit_id, f_path = self._get_commit_and_path()
610 commit_id, f_path = self._get_commit_and_path()
609 c.commit = self._get_commit_or_redirect(commit_id)
611 c.commit = self._get_commit_or_redirect(commit_id)
610 c.branch = self.request.GET.get('branch', None)
612 c.branch = self.request.GET.get('branch', None)
611 c.f_path = f_path
613 c.f_path = f_path
612
614
613 # prev link
615 # prev link
614 try:
616 try:
615 prev_commit = c.commit.prev(c.branch)
617 prev_commit = c.commit.prev(c.branch)
616 c.prev_commit = prev_commit
618 c.prev_commit = prev_commit
617 c.url_prev = h.route_path(
619 c.url_prev = h.route_path(
618 'repo_files', repo_name=self.db_repo_name,
620 'repo_files', repo_name=self.db_repo_name,
619 commit_id=prev_commit.raw_id, f_path=f_path)
621 commit_id=prev_commit.raw_id, f_path=f_path)
620 if c.branch:
622 if c.branch:
621 c.url_prev += '?branch=%s' % c.branch
623 c.url_prev += '?branch=%s' % c.branch
622 except (CommitDoesNotExistError, VCSError):
624 except (CommitDoesNotExistError, VCSError):
623 c.url_prev = '#'
625 c.url_prev = '#'
624 c.prev_commit = EmptyCommit()
626 c.prev_commit = EmptyCommit()
625
627
626 # next link
628 # next link
627 try:
629 try:
628 next_commit = c.commit.next(c.branch)
630 next_commit = c.commit.next(c.branch)
629 c.next_commit = next_commit
631 c.next_commit = next_commit
630 c.url_next = h.route_path(
632 c.url_next = h.route_path(
631 'repo_files', repo_name=self.db_repo_name,
633 'repo_files', repo_name=self.db_repo_name,
632 commit_id=next_commit.raw_id, f_path=f_path)
634 commit_id=next_commit.raw_id, f_path=f_path)
633 if c.branch:
635 if c.branch:
634 c.url_next += '?branch=%s' % c.branch
636 c.url_next += '?branch=%s' % c.branch
635 except (CommitDoesNotExistError, VCSError):
637 except (CommitDoesNotExistError, VCSError):
636 c.url_next = '#'
638 c.url_next = '#'
637 c.next_commit = EmptyCommit()
639 c.next_commit = EmptyCommit()
638
640
639 # files or dirs
641 # files or dirs
640 try:
642 try:
641 c.file = c.commit.get_node(f_path)
643 c.file = c.commit.get_node(f_path)
642 c.file_author = True
644 c.file_author = True
643 c.file_tree = ''
645 c.file_tree = ''
644
646
645 # load file content
647 # load file content
646 if c.file.is_file():
648 if c.file.is_file():
647 c.lf_node = c.file.get_largefile_node()
649 c.lf_node = c.file.get_largefile_node()
648
650
649 c.file_source_page = 'true'
651 c.file_source_page = 'true'
650 c.file_last_commit = c.file.last_commit
652 c.file_last_commit = c.file.last_commit
651 if c.file.size < c.visual.cut_off_limit_diff:
653 if c.file.size < c.visual.cut_off_limit_diff:
652 if c.annotate: # annotation has precedence over renderer
654 if c.annotate: # annotation has precedence over renderer
653 c.annotated_lines = filenode_as_annotated_lines_tokens(
655 c.annotated_lines = filenode_as_annotated_lines_tokens(
654 c.file
656 c.file
655 )
657 )
656 else:
658 else:
657 c.renderer = (
659 c.renderer = (
658 c.renderer and h.renderer_from_filename(c.file.path)
660 c.renderer and h.renderer_from_filename(c.file.path)
659 )
661 )
660 if not c.renderer:
662 if not c.renderer:
661 c.lines = filenode_as_lines_tokens(c.file)
663 c.lines = filenode_as_lines_tokens(c.file)
662
664
663 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
665 _branch_name, _sha_commit_id, is_head = self._is_valid_head(
664 commit_id, self.rhodecode_vcs_repo)
666 commit_id, self.rhodecode_vcs_repo)
665 c.on_branch_head = is_head
667 c.on_branch_head = is_head
666
668
667 branch = c.commit.branch if (
669 branch = c.commit.branch if (
668 c.commit.branch and '/' not in c.commit.branch) else None
670 c.commit.branch and '/' not in c.commit.branch) else None
669 c.branch_or_raw_id = branch or c.commit.raw_id
671 c.branch_or_raw_id = branch or c.commit.raw_id
670 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
672 c.branch_name = c.commit.branch or h.short_id(c.commit.raw_id)
671
673
672 author = c.file_last_commit.author
674 author = c.file_last_commit.author
673 c.authors = [[
675 c.authors = [[
674 h.email(author),
676 h.email(author),
675 h.person(author, 'username_or_name_or_email'),
677 h.person(author, 'username_or_name_or_email'),
676 1
678 1
677 ]]
679 ]]
678
680
679 else: # load tree content at path
681 else: # load tree content at path
680 c.file_source_page = 'false'
682 c.file_source_page = 'false'
681 c.authors = []
683 c.authors = []
682 # this loads a simple tree without metadata to speed things up
684 # this loads a simple tree without metadata to speed things up
683 # later via ajax we call repo_nodetree_full and fetch whole
685 # later via ajax we call repo_nodetree_full and fetch whole
684 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path)
686 c.file_tree = self._get_tree_at_commit(c, c.commit.raw_id, f_path)
685
687
686 except RepositoryError as e:
688 except RepositoryError as e:
687 h.flash(safe_str(h.escape(e)), category='error')
689 h.flash(safe_str(h.escape(e)), category='error')
688 raise HTTPNotFound()
690 raise HTTPNotFound()
689
691
690 if self.request.environ.get('HTTP_X_PJAX'):
692 if self.request.environ.get('HTTP_X_PJAX'):
691 html = render('rhodecode:templates/files/files_pjax.mako',
693 html = render('rhodecode:templates/files/files_pjax.mako',
692 self._get_template_context(c), self.request)
694 self._get_template_context(c), self.request)
693 else:
695 else:
694 html = render('rhodecode:templates/files/files.mako',
696 html = render('rhodecode:templates/files/files.mako',
695 self._get_template_context(c), self.request)
697 self._get_template_context(c), self.request)
696 return Response(html)
698 return Response(html)
697
699
698 @HasRepoPermissionAnyDecorator(
700 @HasRepoPermissionAnyDecorator(
699 'repository.read', 'repository.write', 'repository.admin')
701 'repository.read', 'repository.write', 'repository.admin')
700 @view_config(
702 @view_config(
701 route_name='repo_files:annotated_previous', request_method='GET',
703 route_name='repo_files:annotated_previous', request_method='GET',
702 renderer=None)
704 renderer=None)
703 def repo_files_annotated_previous(self):
705 def repo_files_annotated_previous(self):
704 self.load_default_context()
706 self.load_default_context()
705
707
706 commit_id, f_path = self._get_commit_and_path()
708 commit_id, f_path = self._get_commit_and_path()
707 commit = self._get_commit_or_redirect(commit_id)
709 commit = self._get_commit_or_redirect(commit_id)
708 prev_commit_id = commit.raw_id
710 prev_commit_id = commit.raw_id
709 line_anchor = self.request.GET.get('line_anchor')
711 line_anchor = self.request.GET.get('line_anchor')
710 is_file = False
712 is_file = False
711 try:
713 try:
712 _file = commit.get_node(f_path)
714 _file = commit.get_node(f_path)
713 is_file = _file.is_file()
715 is_file = _file.is_file()
714 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
716 except (NodeDoesNotExistError, CommitDoesNotExistError, VCSError):
715 pass
717 pass
716
718
717 if is_file:
719 if is_file:
718 history = commit.get_path_history(f_path)
720 history = commit.get_path_history(f_path)
719 prev_commit_id = history[1].raw_id \
721 prev_commit_id = history[1].raw_id \
720 if len(history) > 1 else prev_commit_id
722 if len(history) > 1 else prev_commit_id
721 prev_url = h.route_path(
723 prev_url = h.route_path(
722 'repo_files:annotated', repo_name=self.db_repo_name,
724 'repo_files:annotated', repo_name=self.db_repo_name,
723 commit_id=prev_commit_id, f_path=f_path,
725 commit_id=prev_commit_id, f_path=f_path,
724 _anchor='L{}'.format(line_anchor))
726 _anchor='L{}'.format(line_anchor))
725
727
726 raise HTTPFound(prev_url)
728 raise HTTPFound(prev_url)
727
729
728 @LoginRequired()
730 @LoginRequired()
729 @HasRepoPermissionAnyDecorator(
731 @HasRepoPermissionAnyDecorator(
730 'repository.read', 'repository.write', 'repository.admin')
732 'repository.read', 'repository.write', 'repository.admin')
731 @view_config(
733 @view_config(
732 route_name='repo_nodetree_full', request_method='GET',
734 route_name='repo_nodetree_full', request_method='GET',
733 renderer=None, xhr=True)
735 renderer=None, xhr=True)
734 @view_config(
736 @view_config(
735 route_name='repo_nodetree_full:default_path', request_method='GET',
737 route_name='repo_nodetree_full:default_path', request_method='GET',
736 renderer=None, xhr=True)
738 renderer=None, xhr=True)
737 def repo_nodetree_full(self):
739 def repo_nodetree_full(self):
738 """
740 """
739 Returns rendered html of file tree that contains commit date,
741 Returns rendered html of file tree that contains commit date,
740 author, commit_id for the specified combination of
742 author, commit_id for the specified combination of
741 repo, commit_id and file path
743 repo, commit_id and file path
742 """
744 """
743 c = self.load_default_context()
745 c = self.load_default_context()
744
746
745 commit_id, f_path = self._get_commit_and_path()
747 commit_id, f_path = self._get_commit_and_path()
746 commit = self._get_commit_or_redirect(commit_id)
748 commit = self._get_commit_or_redirect(commit_id)
747 try:
749 try:
748 dir_node = commit.get_node(f_path)
750 dir_node = commit.get_node(f_path)
749 except RepositoryError as e:
751 except RepositoryError as e:
750 return Response('error: {}'.format(h.escape(safe_str(e))))
752 return Response('error: {}'.format(h.escape(safe_str(e))))
751
753
752 if dir_node.is_file():
754 if dir_node.is_file():
753 return Response('')
755 return Response('')
754
756
755 c.file = dir_node
757 c.file = dir_node
756 c.commit = commit
758 c.commit = commit
757
759
758 html = self._get_tree_at_commit(
760 html = self._get_tree_at_commit(
759 c, commit.raw_id, dir_node.path, full_load=True)
761 c, commit.raw_id, dir_node.path, full_load=True)
760
762
761 return Response(html)
763 return Response(html)
762
764
763 def _get_attachement_headers(self, f_path):
765 def _get_attachement_headers(self, f_path):
764 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
766 f_name = safe_str(f_path.split(Repository.NAME_SEP)[-1])
765 safe_path = f_name.replace('"', '\\"')
767 safe_path = f_name.replace('"', '\\"')
766 encoded_path = urllib.quote(f_name)
768 encoded_path = urllib.quote(f_name)
767
769
768 return "attachment; " \
770 return "attachment; " \
769 "filename=\"{}\"; " \
771 "filename=\"{}\"; " \
770 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
772 "filename*=UTF-8\'\'{}".format(safe_path, encoded_path)
771
773
772 @LoginRequired()
774 @LoginRequired()
773 @HasRepoPermissionAnyDecorator(
775 @HasRepoPermissionAnyDecorator(
774 'repository.read', 'repository.write', 'repository.admin')
776 'repository.read', 'repository.write', 'repository.admin')
775 @view_config(
777 @view_config(
776 route_name='repo_file_raw', request_method='GET',
778 route_name='repo_file_raw', request_method='GET',
777 renderer=None)
779 renderer=None)
778 def repo_file_raw(self):
780 def repo_file_raw(self):
779 """
781 """
780 Action for show as raw, some mimetypes are "rendered",
782 Action for show as raw, some mimetypes are "rendered",
781 those include images, icons.
783 those include images, icons.
782 """
784 """
783 c = self.load_default_context()
785 c = self.load_default_context()
784
786
785 commit_id, f_path = self._get_commit_and_path()
787 commit_id, f_path = self._get_commit_and_path()
786 commit = self._get_commit_or_redirect(commit_id)
788 commit = self._get_commit_or_redirect(commit_id)
787 file_node = self._get_filenode_or_redirect(commit, f_path)
789 file_node = self._get_filenode_or_redirect(commit, f_path)
788
790
789 raw_mimetype_mapping = {
791 raw_mimetype_mapping = {
790 # map original mimetype to a mimetype used for "show as raw"
792 # map original mimetype to a mimetype used for "show as raw"
791 # you can also provide a content-disposition to override the
793 # you can also provide a content-disposition to override the
792 # default "attachment" disposition.
794 # default "attachment" disposition.
793 # orig_type: (new_type, new_dispo)
795 # orig_type: (new_type, new_dispo)
794
796
795 # show images inline:
797 # show images inline:
796 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
798 # Do not re-add SVG: it is unsafe and permits XSS attacks. One can
797 # for example render an SVG with javascript inside or even render
799 # for example render an SVG with javascript inside or even render
798 # HTML.
800 # HTML.
799 'image/x-icon': ('image/x-icon', 'inline'),
801 'image/x-icon': ('image/x-icon', 'inline'),
800 'image/png': ('image/png', 'inline'),
802 'image/png': ('image/png', 'inline'),
801 'image/gif': ('image/gif', 'inline'),
803 'image/gif': ('image/gif', 'inline'),
802 'image/jpeg': ('image/jpeg', 'inline'),
804 'image/jpeg': ('image/jpeg', 'inline'),
803 'application/pdf': ('application/pdf', 'inline'),
805 'application/pdf': ('application/pdf', 'inline'),
804 }
806 }
805
807
806 mimetype = file_node.mimetype
808 mimetype = file_node.mimetype
807 try:
809 try:
808 mimetype, disposition = raw_mimetype_mapping[mimetype]
810 mimetype, disposition = raw_mimetype_mapping[mimetype]
809 except KeyError:
811 except KeyError:
810 # we don't know anything special about this, handle it safely
812 # we don't know anything special about this, handle it safely
811 if file_node.is_binary:
813 if file_node.is_binary:
812 # do same as download raw for binary files
814 # do same as download raw for binary files
813 mimetype, disposition = 'application/octet-stream', 'attachment'
815 mimetype, disposition = 'application/octet-stream', 'attachment'
814 else:
816 else:
815 # do not just use the original mimetype, but force text/plain,
817 # do not just use the original mimetype, but force text/plain,
816 # otherwise it would serve text/html and that might be unsafe.
818 # otherwise it would serve text/html and that might be unsafe.
817 # Note: underlying vcs library fakes text/plain mimetype if the
819 # Note: underlying vcs library fakes text/plain mimetype if the
818 # mimetype can not be determined and it thinks it is not
820 # mimetype can not be determined and it thinks it is not
819 # binary.This might lead to erroneous text display in some
821 # binary.This might lead to erroneous text display in some
820 # cases, but helps in other cases, like with text files
822 # cases, but helps in other cases, like with text files
821 # without extension.
823 # without extension.
822 mimetype, disposition = 'text/plain', 'inline'
824 mimetype, disposition = 'text/plain', 'inline'
823
825
824 if disposition == 'attachment':
826 if disposition == 'attachment':
825 disposition = self._get_attachement_headers(f_path)
827 disposition = self._get_attachement_headers(f_path)
826
828
827 def stream_node():
829 def stream_node():
828 yield file_node.raw_bytes
830 yield file_node.raw_bytes
829
831
830 response = Response(app_iter=stream_node())
832 response = Response(app_iter=stream_node())
831 response.content_disposition = disposition
833 response.content_disposition = disposition
832 response.content_type = mimetype
834 response.content_type = mimetype
833
835
834 charset = self._get_default_encoding(c)
836 charset = self._get_default_encoding(c)
835 if charset:
837 if charset:
836 response.charset = charset
838 response.charset = charset
837
839
838 return response
840 return response
839
841
840 @LoginRequired()
842 @LoginRequired()
841 @HasRepoPermissionAnyDecorator(
843 @HasRepoPermissionAnyDecorator(
842 'repository.read', 'repository.write', 'repository.admin')
844 'repository.read', 'repository.write', 'repository.admin')
843 @view_config(
845 @view_config(
844 route_name='repo_file_download', request_method='GET',
846 route_name='repo_file_download', request_method='GET',
845 renderer=None)
847 renderer=None)
846 @view_config(
848 @view_config(
847 route_name='repo_file_download:legacy', request_method='GET',
849 route_name='repo_file_download:legacy', request_method='GET',
848 renderer=None)
850 renderer=None)
849 def repo_file_download(self):
851 def repo_file_download(self):
850 c = self.load_default_context()
852 c = self.load_default_context()
851
853
852 commit_id, f_path = self._get_commit_and_path()
854 commit_id, f_path = self._get_commit_and_path()
853 commit = self._get_commit_or_redirect(commit_id)
855 commit = self._get_commit_or_redirect(commit_id)
854 file_node = self._get_filenode_or_redirect(commit, f_path)
856 file_node = self._get_filenode_or_redirect(commit, f_path)
855
857
856 if self.request.GET.get('lf'):
858 if self.request.GET.get('lf'):
857 # only if lf get flag is passed, we download this file
859 # only if lf get flag is passed, we download this file
858 # as LFS/Largefile
860 # as LFS/Largefile
859 lf_node = file_node.get_largefile_node()
861 lf_node = file_node.get_largefile_node()
860 if lf_node:
862 if lf_node:
861 # overwrite our pointer with the REAL large-file
863 # overwrite our pointer with the REAL large-file
862 file_node = lf_node
864 file_node = lf_node
863
865
864 disposition = self._get_attachement_headers(f_path)
866 disposition = self._get_attachement_headers(f_path)
865
867
866 def stream_node():
868 def stream_node():
867 yield file_node.raw_bytes
869 yield file_node.raw_bytes
868
870
869 response = Response(app_iter=stream_node())
871 response = Response(app_iter=stream_node())
870 response.content_disposition = disposition
872 response.content_disposition = disposition
871 response.content_type = file_node.mimetype
873 response.content_type = file_node.mimetype
872
874
873 charset = self._get_default_encoding(c)
875 charset = self._get_default_encoding(c)
874 if charset:
876 if charset:
875 response.charset = charset
877 response.charset = charset
876
878
877 return response
879 return response
878
880
879 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
881 def _get_nodelist_at_commit(self, repo_name, repo_id, commit_id, f_path):
880
882
881 cache_seconds = safe_int(
883 cache_seconds = safe_int(
882 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
884 rhodecode.CONFIG.get('rc_cache.cache_repo.expiration_time'))
883 cache_on = cache_seconds > 0
885 cache_on = cache_seconds > 0
884 log.debug(
886 log.debug(
885 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
887 'Computing FILE SEARCH for repo_id %s commit_id `%s` and path `%s`'
886 'with caching: %s[TTL: %ss]' % (
888 'with caching: %s[TTL: %ss]' % (
887 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
889 repo_id, commit_id, f_path, cache_on, cache_seconds or 0))
888
890
889 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
891 cache_namespace_uid = 'cache_repo.{}'.format(repo_id)
890 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
892 region = rc_cache.get_or_create_region('cache_repo', cache_namespace_uid)
891
893
892 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
894 @region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
893 condition=cache_on)
895 condition=cache_on)
894 def compute_file_search(repo_id, commit_id, f_path):
896 def compute_file_search(repo_id, commit_id, f_path):
895 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
897 log.debug('Generating cached nodelist for repo_id:%s, %s, %s',
896 repo_id, commit_id, f_path)
898 repo_id, commit_id, f_path)
897 try:
899 try:
898 _d, _f = ScmModel().get_nodes(
900 _d, _f = ScmModel().get_nodes(
899 repo_name, commit_id, f_path, flat=False)
901 repo_name, commit_id, f_path, flat=False)
900 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
902 except (RepositoryError, CommitDoesNotExistError, Exception) as e:
901 log.exception(safe_str(e))
903 log.exception(safe_str(e))
902 h.flash(safe_str(h.escape(e)), category='error')
904 h.flash(safe_str(h.escape(e)), category='error')
903 raise HTTPFound(h.route_path(
905 raise HTTPFound(h.route_path(
904 'repo_files', repo_name=self.db_repo_name,
906 'repo_files', repo_name=self.db_repo_name,
905 commit_id='tip', f_path='/'))
907 commit_id='tip', f_path='/'))
906 return _d + _f
908 return _d + _f
907
909
908 return compute_file_search(self.db_repo.repo_id, commit_id, f_path)
910 return compute_file_search(self.db_repo.repo_id, commit_id, f_path)
909
911
910 @LoginRequired()
912 @LoginRequired()
911 @HasRepoPermissionAnyDecorator(
913 @HasRepoPermissionAnyDecorator(
912 'repository.read', 'repository.write', 'repository.admin')
914 'repository.read', 'repository.write', 'repository.admin')
913 @view_config(
915 @view_config(
914 route_name='repo_files_nodelist', request_method='GET',
916 route_name='repo_files_nodelist', request_method='GET',
915 renderer='json_ext', xhr=True)
917 renderer='json_ext', xhr=True)
916 def repo_nodelist(self):
918 def repo_nodelist(self):
917 self.load_default_context()
919 self.load_default_context()
918
920
919 commit_id, f_path = self._get_commit_and_path()
921 commit_id, f_path = self._get_commit_and_path()
920 commit = self._get_commit_or_redirect(commit_id)
922 commit = self._get_commit_or_redirect(commit_id)
921
923
922 metadata = self._get_nodelist_at_commit(
924 metadata = self._get_nodelist_at_commit(
923 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
925 self.db_repo_name, self.db_repo.repo_id, commit.raw_id, f_path)
924 return {'nodes': metadata}
926 return {'nodes': metadata}
925
927
926 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
928 def _create_references(self, branches_or_tags, symbolic_reference, f_path, ref_type):
927 items = []
929 items = []
928 for name, commit_id in branches_or_tags.items():
930 for name, commit_id in branches_or_tags.items():
929 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
931 sym_ref = symbolic_reference(commit_id, name, f_path, ref_type)
930 items.append((sym_ref, name, ref_type))
932 items.append((sym_ref, name, ref_type))
931 return items
933 return items
932
934
933 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
935 def _symbolic_reference(self, commit_id, name, f_path, ref_type):
934 return commit_id
936 return commit_id
935
937
936 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
938 def _symbolic_reference_svn(self, commit_id, name, f_path, ref_type):
937 new_f_path = vcspath.join(name, f_path)
939 new_f_path = vcspath.join(name, f_path)
938 return u'%s@%s' % (new_f_path, commit_id)
940 return u'%s@%s' % (new_f_path, commit_id)
939
941
940 def _get_node_history(self, commit_obj, f_path, commits=None):
942 def _get_node_history(self, commit_obj, f_path, commits=None):
941 """
943 """
942 get commit history for given node
944 get commit history for given node
943
945
944 :param commit_obj: commit to calculate history
946 :param commit_obj: commit to calculate history
945 :param f_path: path for node to calculate history for
947 :param f_path: path for node to calculate history for
946 :param commits: if passed don't calculate history and take
948 :param commits: if passed don't calculate history and take
947 commits defined in this list
949 commits defined in this list
948 """
950 """
949 _ = self.request.translate
951 _ = self.request.translate
950
952
951 # calculate history based on tip
953 # calculate history based on tip
952 tip = self.rhodecode_vcs_repo.get_commit()
954 tip = self.rhodecode_vcs_repo.get_commit()
953 if commits is None:
955 if commits is None:
954 pre_load = ["author", "branch"]
956 pre_load = ["author", "branch"]
955 try:
957 try:
956 commits = tip.get_path_history(f_path, pre_load=pre_load)
958 commits = tip.get_path_history(f_path, pre_load=pre_load)
957 except (NodeDoesNotExistError, CommitError):
959 except (NodeDoesNotExistError, CommitError):
958 # this node is not present at tip!
960 # this node is not present at tip!
959 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
961 commits = commit_obj.get_path_history(f_path, pre_load=pre_load)
960
962
961 history = []
963 history = []
962 commits_group = ([], _("Changesets"))
964 commits_group = ([], _("Changesets"))
963 for commit in commits:
965 for commit in commits:
964 branch = ' (%s)' % commit.branch if commit.branch else ''
966 branch = ' (%s)' % commit.branch if commit.branch else ''
965 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
967 n_desc = 'r%s:%s%s' % (commit.idx, commit.short_id, branch)
966 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
968 commits_group[0].append((commit.raw_id, n_desc, 'sha'))
967 history.append(commits_group)
969 history.append(commits_group)
968
970
969 symbolic_reference = self._symbolic_reference
971 symbolic_reference = self._symbolic_reference
970
972
971 if self.rhodecode_vcs_repo.alias == 'svn':
973 if self.rhodecode_vcs_repo.alias == 'svn':
972 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
974 adjusted_f_path = RepoFilesView.adjust_file_path_for_svn(
973 f_path, self.rhodecode_vcs_repo)
975 f_path, self.rhodecode_vcs_repo)
974 if adjusted_f_path != f_path:
976 if adjusted_f_path != f_path:
975 log.debug(
977 log.debug(
976 'Recognized svn tag or branch in file "%s", using svn '
978 'Recognized svn tag or branch in file "%s", using svn '
977 'specific symbolic references', f_path)
979 'specific symbolic references', f_path)
978 f_path = adjusted_f_path
980 f_path = adjusted_f_path
979 symbolic_reference = self._symbolic_reference_svn
981 symbolic_reference = self._symbolic_reference_svn
980
982
981 branches = self._create_references(
983 branches = self._create_references(
982 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
984 self.rhodecode_vcs_repo.branches, symbolic_reference, f_path, 'branch')
983 branches_group = (branches, _("Branches"))
985 branches_group = (branches, _("Branches"))
984
986
985 tags = self._create_references(
987 tags = self._create_references(
986 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
988 self.rhodecode_vcs_repo.tags, symbolic_reference, f_path, 'tag')
987 tags_group = (tags, _("Tags"))
989 tags_group = (tags, _("Tags"))
988
990
989 history.append(branches_group)
991 history.append(branches_group)
990 history.append(tags_group)
992 history.append(tags_group)
991
993
992 return history, commits
994 return history, commits
993
995
994 @LoginRequired()
996 @LoginRequired()
995 @HasRepoPermissionAnyDecorator(
997 @HasRepoPermissionAnyDecorator(
996 'repository.read', 'repository.write', 'repository.admin')
998 'repository.read', 'repository.write', 'repository.admin')
997 @view_config(
999 @view_config(
998 route_name='repo_file_history', request_method='GET',
1000 route_name='repo_file_history', request_method='GET',
999 renderer='json_ext')
1001 renderer='json_ext')
1000 def repo_file_history(self):
1002 def repo_file_history(self):
1001 self.load_default_context()
1003 self.load_default_context()
1002
1004
1003 commit_id, f_path = self._get_commit_and_path()
1005 commit_id, f_path = self._get_commit_and_path()
1004 commit = self._get_commit_or_redirect(commit_id)
1006 commit = self._get_commit_or_redirect(commit_id)
1005 file_node = self._get_filenode_or_redirect(commit, f_path)
1007 file_node = self._get_filenode_or_redirect(commit, f_path)
1006
1008
1007 if file_node.is_file():
1009 if file_node.is_file():
1008 file_history, _hist = self._get_node_history(commit, f_path)
1010 file_history, _hist = self._get_node_history(commit, f_path)
1009
1011
1010 res = []
1012 res = []
1011 for obj in file_history:
1013 for obj in file_history:
1012 res.append({
1014 res.append({
1013 'text': obj[1],
1015 'text': obj[1],
1014 'children': [{'id': o[0], 'text': o[1], 'type': o[2]} for o in obj[0]]
1016 'children': [{'id': o[0], 'text': o[1], 'type': o[2]} for o in obj[0]]
1015 })
1017 })
1016
1018
1017 data = {
1019 data = {
1018 'more': False,
1020 'more': False,
1019 'results': res
1021 'results': res
1020 }
1022 }
1021 return data
1023 return data
1022
1024
1023 log.warning('Cannot fetch history for directory')
1025 log.warning('Cannot fetch history for directory')
1024 raise HTTPBadRequest()
1026 raise HTTPBadRequest()
1025
1027
1026 @LoginRequired()
1028 @LoginRequired()
1027 @HasRepoPermissionAnyDecorator(
1029 @HasRepoPermissionAnyDecorator(
1028 'repository.read', 'repository.write', 'repository.admin')
1030 'repository.read', 'repository.write', 'repository.admin')
1029 @view_config(
1031 @view_config(
1030 route_name='repo_file_authors', request_method='GET',
1032 route_name='repo_file_authors', request_method='GET',
1031 renderer='rhodecode:templates/files/file_authors_box.mako')
1033 renderer='rhodecode:templates/files/file_authors_box.mako')
1032 def repo_file_authors(self):
1034 def repo_file_authors(self):
1033 c = self.load_default_context()
1035 c = self.load_default_context()
1034
1036
1035 commit_id, f_path = self._get_commit_and_path()
1037 commit_id, f_path = self._get_commit_and_path()
1036 commit = self._get_commit_or_redirect(commit_id)
1038 commit = self._get_commit_or_redirect(commit_id)
1037 file_node = self._get_filenode_or_redirect(commit, f_path)
1039 file_node = self._get_filenode_or_redirect(commit, f_path)
1038
1040
1039 if not file_node.is_file():
1041 if not file_node.is_file():
1040 raise HTTPBadRequest()
1042 raise HTTPBadRequest()
1041
1043
1042 c.file_last_commit = file_node.last_commit
1044 c.file_last_commit = file_node.last_commit
1043 if self.request.GET.get('annotate') == '1':
1045 if self.request.GET.get('annotate') == '1':
1044 # use _hist from annotation if annotation mode is on
1046 # use _hist from annotation if annotation mode is on
1045 commit_ids = set(x[1] for x in file_node.annotate)
1047 commit_ids = set(x[1] for x in file_node.annotate)
1046 _hist = (
1048 _hist = (
1047 self.rhodecode_vcs_repo.get_commit(commit_id)
1049 self.rhodecode_vcs_repo.get_commit(commit_id)
1048 for commit_id in commit_ids)
1050 for commit_id in commit_ids)
1049 else:
1051 else:
1050 _f_history, _hist = self._get_node_history(commit, f_path)
1052 _f_history, _hist = self._get_node_history(commit, f_path)
1051 c.file_author = False
1053 c.file_author = False
1052
1054
1053 unique = collections.OrderedDict()
1055 unique = collections.OrderedDict()
1054 for commit in _hist:
1056 for commit in _hist:
1055 author = commit.author
1057 author = commit.author
1056 if author not in unique:
1058 if author not in unique:
1057 unique[commit.author] = [
1059 unique[commit.author] = [
1058 h.email(author),
1060 h.email(author),
1059 h.person(author, 'username_or_name_or_email'),
1061 h.person(author, 'username_or_name_or_email'),
1060 1 # counter
1062 1 # counter
1061 ]
1063 ]
1062
1064
1063 else:
1065 else:
1064 # increase counter
1066 # increase counter
1065 unique[commit.author][2] += 1
1067 unique[commit.author][2] += 1
1066
1068
1067 c.authors = [val for val in unique.values()]
1069 c.authors = [val for val in unique.values()]
1068
1070
1069 return self._get_template_context(c)
1071 return self._get_template_context(c)
1070
1072
1071 @LoginRequired()
1073 @LoginRequired()
1072 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1074 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1073 @view_config(
1075 @view_config(
1074 route_name='repo_files_remove_file', request_method='GET',
1076 route_name='repo_files_remove_file', request_method='GET',
1075 renderer='rhodecode:templates/files/files_delete.mako')
1077 renderer='rhodecode:templates/files/files_delete.mako')
1076 def repo_files_remove_file(self):
1078 def repo_files_remove_file(self):
1077 _ = self.request.translate
1079 _ = self.request.translate
1078 c = self.load_default_context()
1080 c = self.load_default_context()
1079 commit_id, f_path = self._get_commit_and_path()
1081 commit_id, f_path = self._get_commit_and_path()
1080
1082
1081 self._ensure_not_locked()
1083 self._ensure_not_locked()
1082 _branch_name, _sha_commit_id, is_head = \
1084 _branch_name, _sha_commit_id, is_head = \
1083 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1085 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1084
1086
1085 self.forbid_non_head(is_head, f_path)
1087 self.forbid_non_head(is_head, f_path)
1086 self.check_branch_permission(_branch_name)
1088 self.check_branch_permission(_branch_name)
1087
1089
1088 c.commit = self._get_commit_or_redirect(commit_id)
1090 c.commit = self._get_commit_or_redirect(commit_id)
1089 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1091 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1090
1092
1091 c.default_message = _(
1093 c.default_message = _(
1092 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1094 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1093 c.f_path = f_path
1095 c.f_path = f_path
1094
1096
1095 return self._get_template_context(c)
1097 return self._get_template_context(c)
1096
1098
1097 @LoginRequired()
1099 @LoginRequired()
1098 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1100 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1099 @CSRFRequired()
1101 @CSRFRequired()
1100 @view_config(
1102 @view_config(
1101 route_name='repo_files_delete_file', request_method='POST',
1103 route_name='repo_files_delete_file', request_method='POST',
1102 renderer=None)
1104 renderer=None)
1103 def repo_files_delete_file(self):
1105 def repo_files_delete_file(self):
1104 _ = self.request.translate
1106 _ = self.request.translate
1105
1107
1106 c = self.load_default_context()
1108 c = self.load_default_context()
1107 commit_id, f_path = self._get_commit_and_path()
1109 commit_id, f_path = self._get_commit_and_path()
1108
1110
1109 self._ensure_not_locked()
1111 self._ensure_not_locked()
1110 _branch_name, _sha_commit_id, is_head = \
1112 _branch_name, _sha_commit_id, is_head = \
1111 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1113 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1112
1114
1113 self.forbid_non_head(is_head, f_path)
1115 self.forbid_non_head(is_head, f_path)
1114 self.check_branch_permission(_branch_name)
1116 self.check_branch_permission(_branch_name)
1115
1117
1116 c.commit = self._get_commit_or_redirect(commit_id)
1118 c.commit = self._get_commit_or_redirect(commit_id)
1117 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1119 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1118
1120
1119 c.default_message = _(
1121 c.default_message = _(
1120 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1122 'Deleted file {} via RhodeCode Enterprise').format(f_path)
1121 c.f_path = f_path
1123 c.f_path = f_path
1122 node_path = f_path
1124 node_path = f_path
1123 author = self._rhodecode_db_user.full_contact
1125 author = self._rhodecode_db_user.full_contact
1124 message = self.request.POST.get('message') or c.default_message
1126 message = self.request.POST.get('message') or c.default_message
1125 try:
1127 try:
1126 nodes = {
1128 nodes = {
1127 node_path: {
1129 node_path: {
1128 'content': ''
1130 'content': ''
1129 }
1131 }
1130 }
1132 }
1131 ScmModel().delete_nodes(
1133 ScmModel().delete_nodes(
1132 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1134 user=self._rhodecode_db_user.user_id, repo=self.db_repo,
1133 message=message,
1135 message=message,
1134 nodes=nodes,
1136 nodes=nodes,
1135 parent_commit=c.commit,
1137 parent_commit=c.commit,
1136 author=author,
1138 author=author,
1137 )
1139 )
1138
1140
1139 h.flash(
1141 h.flash(
1140 _('Successfully deleted file `{}`').format(
1142 _('Successfully deleted file `{}`').format(
1141 h.escape(f_path)), category='success')
1143 h.escape(f_path)), category='success')
1142 except Exception:
1144 except Exception:
1143 log.exception('Error during commit operation')
1145 log.exception('Error during commit operation')
1144 h.flash(_('Error occurred during commit'), category='error')
1146 h.flash(_('Error occurred during commit'), category='error')
1145 raise HTTPFound(
1147 raise HTTPFound(
1146 h.route_path('repo_commit', repo_name=self.db_repo_name,
1148 h.route_path('repo_commit', repo_name=self.db_repo_name,
1147 commit_id='tip'))
1149 commit_id='tip'))
1148
1150
1149 @LoginRequired()
1151 @LoginRequired()
1150 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1152 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1151 @view_config(
1153 @view_config(
1152 route_name='repo_files_edit_file', request_method='GET',
1154 route_name='repo_files_edit_file', request_method='GET',
1153 renderer='rhodecode:templates/files/files_edit.mako')
1155 renderer='rhodecode:templates/files/files_edit.mako')
1154 def repo_files_edit_file(self):
1156 def repo_files_edit_file(self):
1155 _ = self.request.translate
1157 _ = self.request.translate
1156 c = self.load_default_context()
1158 c = self.load_default_context()
1157 commit_id, f_path = self._get_commit_and_path()
1159 commit_id, f_path = self._get_commit_and_path()
1158
1160
1159 self._ensure_not_locked()
1161 self._ensure_not_locked()
1160 _branch_name, _sha_commit_id, is_head = \
1162 _branch_name, _sha_commit_id, is_head = \
1161 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1163 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1162
1164
1163 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1165 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1164 self.check_branch_permission(_branch_name, commit_id=commit_id)
1166 self.check_branch_permission(_branch_name, commit_id=commit_id)
1165
1167
1166 c.commit = self._get_commit_or_redirect(commit_id)
1168 c.commit = self._get_commit_or_redirect(commit_id)
1167 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1169 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1168
1170
1169 if c.file.is_binary:
1171 if c.file.is_binary:
1170 files_url = h.route_path(
1172 files_url = h.route_path(
1171 'repo_files',
1173 'repo_files',
1172 repo_name=self.db_repo_name,
1174 repo_name=self.db_repo_name,
1173 commit_id=c.commit.raw_id, f_path=f_path)
1175 commit_id=c.commit.raw_id, f_path=f_path)
1174 raise HTTPFound(files_url)
1176 raise HTTPFound(files_url)
1175
1177
1176 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1178 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1177 c.f_path = f_path
1179 c.f_path = f_path
1178
1180
1179 return self._get_template_context(c)
1181 return self._get_template_context(c)
1180
1182
1181 @LoginRequired()
1183 @LoginRequired()
1182 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1184 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1183 @CSRFRequired()
1185 @CSRFRequired()
1184 @view_config(
1186 @view_config(
1185 route_name='repo_files_update_file', request_method='POST',
1187 route_name='repo_files_update_file', request_method='POST',
1186 renderer=None)
1188 renderer=None)
1187 def repo_files_update_file(self):
1189 def repo_files_update_file(self):
1188 _ = self.request.translate
1190 _ = self.request.translate
1189 c = self.load_default_context()
1191 c = self.load_default_context()
1190 commit_id, f_path = self._get_commit_and_path()
1192 commit_id, f_path = self._get_commit_and_path()
1191
1193
1192 self._ensure_not_locked()
1194 self._ensure_not_locked()
1193
1195
1194 c.commit = self._get_commit_or_redirect(commit_id)
1196 c.commit = self._get_commit_or_redirect(commit_id)
1195 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1197 c.file = self._get_filenode_or_redirect(c.commit, f_path)
1196
1198
1197 if c.file.is_binary:
1199 if c.file.is_binary:
1198 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1200 raise HTTPFound(h.route_path('repo_files', repo_name=self.db_repo_name,
1199 commit_id=c.commit.raw_id, f_path=f_path))
1201 commit_id=c.commit.raw_id, f_path=f_path))
1200
1202
1201 _branch_name, _sha_commit_id, is_head = \
1203 _branch_name, _sha_commit_id, is_head = \
1202 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1204 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1203
1205
1204 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1206 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1205 self.check_branch_permission(_branch_name, commit_id=commit_id)
1207 self.check_branch_permission(_branch_name, commit_id=commit_id)
1206
1208
1207 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1209 c.default_message = _('Edited file {} via RhodeCode Enterprise').format(f_path)
1208 c.f_path = f_path
1210 c.f_path = f_path
1209
1211
1210 old_content = c.file.content
1212 old_content = c.file.content
1211 sl = old_content.splitlines(1)
1213 sl = old_content.splitlines(1)
1212 first_line = sl[0] if sl else ''
1214 first_line = sl[0] if sl else ''
1213
1215
1214 r_post = self.request.POST
1216 r_post = self.request.POST
1215 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1217 # line endings: 0 - Unix, 1 - Mac, 2 - DOS
1216 line_ending_mode = detect_mode(first_line, 0)
1218 line_ending_mode = detect_mode(first_line, 0)
1217 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1219 content = convert_line_endings(r_post.get('content', ''), line_ending_mode)
1218
1220
1219 message = r_post.get('message') or c.default_message
1221 message = r_post.get('message') or c.default_message
1220 org_node_path = c.file.unicode_path
1222 org_node_path = c.file.unicode_path
1221 filename = r_post['filename']
1223 filename = r_post['filename']
1222
1224
1223 root_path = c.file.dir_path
1225 root_path = c.file.dir_path
1224 pure_path = self.create_pure_path(root_path, filename)
1226 pure_path = self.create_pure_path(root_path, filename)
1225 node_path = safe_unicode(bytes(pure_path))
1227 node_path = safe_unicode(bytes(pure_path))
1226
1228
1227 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1229 default_redirect_url = h.route_path('repo_commit', repo_name=self.db_repo_name,
1228 commit_id=commit_id)
1230 commit_id=commit_id)
1229 if content == old_content and node_path == org_node_path:
1231 if content == old_content and node_path == org_node_path:
1230 h.flash(_('No changes detected on {}').format(org_node_path),
1232 h.flash(_('No changes detected on {}').format(org_node_path),
1231 category='warning')
1233 category='warning')
1232 raise HTTPFound(default_redirect_url)
1234 raise HTTPFound(default_redirect_url)
1233
1235
1234 try:
1236 try:
1235 mapping = {
1237 mapping = {
1236 org_node_path: {
1238 org_node_path: {
1237 'org_filename': org_node_path,
1239 'org_filename': org_node_path,
1238 'filename': node_path,
1240 'filename': node_path,
1239 'content': content,
1241 'content': content,
1240 'lexer': '',
1242 'lexer': '',
1241 'op': 'mod',
1243 'op': 'mod',
1242 'mode': c.file.mode
1244 'mode': c.file.mode
1243 }
1245 }
1244 }
1246 }
1245
1247
1246 commit = ScmModel().update_nodes(
1248 commit = ScmModel().update_nodes(
1247 user=self._rhodecode_db_user.user_id,
1249 user=self._rhodecode_db_user.user_id,
1248 repo=self.db_repo,
1250 repo=self.db_repo,
1249 message=message,
1251 message=message,
1250 nodes=mapping,
1252 nodes=mapping,
1251 parent_commit=c.commit,
1253 parent_commit=c.commit,
1252 )
1254 )
1253
1255
1254 h.flash(_('Successfully committed changes to file `{}`').format(
1256 h.flash(_('Successfully committed changes to file `{}`').format(
1255 h.escape(f_path)), category='success')
1257 h.escape(f_path)), category='success')
1256 default_redirect_url = h.route_path(
1258 default_redirect_url = h.route_path(
1257 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1259 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1258
1260
1259 except Exception:
1261 except Exception:
1260 log.exception('Error occurred during commit')
1262 log.exception('Error occurred during commit')
1261 h.flash(_('Error occurred during commit'), category='error')
1263 h.flash(_('Error occurred during commit'), category='error')
1262
1264
1263 raise HTTPFound(default_redirect_url)
1265 raise HTTPFound(default_redirect_url)
1264
1266
1265 @LoginRequired()
1267 @LoginRequired()
1266 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1268 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1267 @view_config(
1269 @view_config(
1268 route_name='repo_files_add_file', request_method='GET',
1270 route_name='repo_files_add_file', request_method='GET',
1269 renderer='rhodecode:templates/files/files_add.mako')
1271 renderer='rhodecode:templates/files/files_add.mako')
1270 @view_config(
1272 @view_config(
1271 route_name='repo_files_upload_file', request_method='GET',
1273 route_name='repo_files_upload_file', request_method='GET',
1272 renderer='rhodecode:templates/files/files_upload.mako')
1274 renderer='rhodecode:templates/files/files_upload.mako')
1273 def repo_files_add_file(self):
1275 def repo_files_add_file(self):
1274 _ = self.request.translate
1276 _ = self.request.translate
1275 c = self.load_default_context()
1277 c = self.load_default_context()
1276 commit_id, f_path = self._get_commit_and_path()
1278 commit_id, f_path = self._get_commit_and_path()
1277
1279
1278 self._ensure_not_locked()
1280 self._ensure_not_locked()
1279
1281
1280 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1282 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1281 if c.commit is None:
1283 if c.commit is None:
1282 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1284 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1283
1285
1284 if self.rhodecode_vcs_repo.is_empty():
1286 if self.rhodecode_vcs_repo.is_empty():
1285 # for empty repository we cannot check for current branch, we rely on
1287 # for empty repository we cannot check for current branch, we rely on
1286 # c.commit.branch instead
1288 # c.commit.branch instead
1287 _branch_name = c.commit.branch
1289 _branch_name = c.commit.branch
1288 is_head = True
1290 is_head = True
1289 else:
1291 else:
1290 _branch_name, _sha_commit_id, is_head = \
1292 _branch_name, _sha_commit_id, is_head = \
1291 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1293 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1292
1294
1293 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1295 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1294 self.check_branch_permission(_branch_name, commit_id=commit_id)
1296 self.check_branch_permission(_branch_name, commit_id=commit_id)
1295
1297
1296 c.default_message = (_('Added file via RhodeCode Enterprise'))
1298 c.default_message = (_('Added file via RhodeCode Enterprise'))
1297 c.f_path = f_path.lstrip('/') # ensure not relative path
1299 c.f_path = f_path.lstrip('/') # ensure not relative path
1298
1300
1299 return self._get_template_context(c)
1301 return self._get_template_context(c)
1300
1302
1301 @LoginRequired()
1303 @LoginRequired()
1302 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1304 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1303 @CSRFRequired()
1305 @CSRFRequired()
1304 @view_config(
1306 @view_config(
1305 route_name='repo_files_create_file', request_method='POST',
1307 route_name='repo_files_create_file', request_method='POST',
1306 renderer=None)
1308 renderer=None)
1307 def repo_files_create_file(self):
1309 def repo_files_create_file(self):
1308 _ = self.request.translate
1310 _ = self.request.translate
1309 c = self.load_default_context()
1311 c = self.load_default_context()
1310 commit_id, f_path = self._get_commit_and_path()
1312 commit_id, f_path = self._get_commit_and_path()
1311
1313
1312 self._ensure_not_locked()
1314 self._ensure_not_locked()
1313
1315
1314 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1316 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1315 if c.commit is None:
1317 if c.commit is None:
1316 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1318 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1317
1319
1318 # calculate redirect URL
1320 # calculate redirect URL
1319 if self.rhodecode_vcs_repo.is_empty():
1321 if self.rhodecode_vcs_repo.is_empty():
1320 default_redirect_url = h.route_path(
1322 default_redirect_url = h.route_path(
1321 'repo_summary', repo_name=self.db_repo_name)
1323 'repo_summary', repo_name=self.db_repo_name)
1322 else:
1324 else:
1323 default_redirect_url = h.route_path(
1325 default_redirect_url = h.route_path(
1324 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1326 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1325
1327
1326 if self.rhodecode_vcs_repo.is_empty():
1328 if self.rhodecode_vcs_repo.is_empty():
1327 # for empty repository we cannot check for current branch, we rely on
1329 # for empty repository we cannot check for current branch, we rely on
1328 # c.commit.branch instead
1330 # c.commit.branch instead
1329 _branch_name = c.commit.branch
1331 _branch_name = c.commit.branch
1330 is_head = True
1332 is_head = True
1331 else:
1333 else:
1332 _branch_name, _sha_commit_id, is_head = \
1334 _branch_name, _sha_commit_id, is_head = \
1333 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1335 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1334
1336
1335 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1337 self.forbid_non_head(is_head, f_path, commit_id=commit_id)
1336 self.check_branch_permission(_branch_name, commit_id=commit_id)
1338 self.check_branch_permission(_branch_name, commit_id=commit_id)
1337
1339
1338 c.default_message = (_('Added file via RhodeCode Enterprise'))
1340 c.default_message = (_('Added file via RhodeCode Enterprise'))
1339 c.f_path = f_path
1341 c.f_path = f_path
1340
1342
1341 r_post = self.request.POST
1343 r_post = self.request.POST
1342 message = r_post.get('message') or c.default_message
1344 message = r_post.get('message') or c.default_message
1343 filename = r_post.get('filename')
1345 filename = r_post.get('filename')
1344 unix_mode = 0
1346 unix_mode = 0
1345 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1347 content = convert_line_endings(r_post.get('content', ''), unix_mode)
1346
1348
1347 if not filename:
1349 if not filename:
1348 # If there's no commit, redirect to repo summary
1350 # If there's no commit, redirect to repo summary
1349 if type(c.commit) is EmptyCommit:
1351 if type(c.commit) is EmptyCommit:
1350 redirect_url = h.route_path(
1352 redirect_url = h.route_path(
1351 'repo_summary', repo_name=self.db_repo_name)
1353 'repo_summary', repo_name=self.db_repo_name)
1352 else:
1354 else:
1353 redirect_url = default_redirect_url
1355 redirect_url = default_redirect_url
1354 h.flash(_('No filename specified'), category='warning')
1356 h.flash(_('No filename specified'), category='warning')
1355 raise HTTPFound(redirect_url)
1357 raise HTTPFound(redirect_url)
1356
1358
1357 root_path = f_path
1359 root_path = f_path
1358 pure_path = self.create_pure_path(root_path, filename)
1360 pure_path = self.create_pure_path(root_path, filename)
1359 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1361 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1360
1362
1361 author = self._rhodecode_db_user.full_contact
1363 author = self._rhodecode_db_user.full_contact
1362 nodes = {
1364 nodes = {
1363 node_path: {
1365 node_path: {
1364 'content': content
1366 'content': content
1365 }
1367 }
1366 }
1368 }
1367
1369
1368 try:
1370 try:
1369
1371
1370 commit = ScmModel().create_nodes(
1372 commit = ScmModel().create_nodes(
1371 user=self._rhodecode_db_user.user_id,
1373 user=self._rhodecode_db_user.user_id,
1372 repo=self.db_repo,
1374 repo=self.db_repo,
1373 message=message,
1375 message=message,
1374 nodes=nodes,
1376 nodes=nodes,
1375 parent_commit=c.commit,
1377 parent_commit=c.commit,
1376 author=author,
1378 author=author,
1377 )
1379 )
1378
1380
1379 h.flash(_('Successfully committed new file `{}`').format(
1381 h.flash(_('Successfully committed new file `{}`').format(
1380 h.escape(node_path)), category='success')
1382 h.escape(node_path)), category='success')
1381
1383
1382 default_redirect_url = h.route_path(
1384 default_redirect_url = h.route_path(
1383 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1385 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1384
1386
1385 except NonRelativePathError:
1387 except NonRelativePathError:
1386 log.exception('Non Relative path found')
1388 log.exception('Non Relative path found')
1387 h.flash(_('The location specified must be a relative path and must not '
1389 h.flash(_('The location specified must be a relative path and must not '
1388 'contain .. in the path'), category='warning')
1390 'contain .. in the path'), category='warning')
1389 raise HTTPFound(default_redirect_url)
1391 raise HTTPFound(default_redirect_url)
1390 except (NodeError, NodeAlreadyExistsError) as e:
1392 except (NodeError, NodeAlreadyExistsError) as e:
1391 h.flash(_(h.escape(e)), category='error')
1393 h.flash(_(h.escape(e)), category='error')
1392 except Exception:
1394 except Exception:
1393 log.exception('Error occurred during commit')
1395 log.exception('Error occurred during commit')
1394 h.flash(_('Error occurred during commit'), category='error')
1396 h.flash(_('Error occurred during commit'), category='error')
1395
1397
1396 raise HTTPFound(default_redirect_url)
1398 raise HTTPFound(default_redirect_url)
1397
1399
1398 @LoginRequired()
1400 @LoginRequired()
1399 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1401 @HasRepoPermissionAnyDecorator('repository.write', 'repository.admin')
1400 @CSRFRequired()
1402 @CSRFRequired()
1401 @view_config(
1403 @view_config(
1402 route_name='repo_files_upload_file', request_method='POST',
1404 route_name='repo_files_upload_file', request_method='POST',
1403 renderer='json_ext')
1405 renderer='json_ext')
1404 def repo_files_upload_file(self):
1406 def repo_files_upload_file(self):
1405 _ = self.request.translate
1407 _ = self.request.translate
1406 c = self.load_default_context()
1408 c = self.load_default_context()
1407 commit_id, f_path = self._get_commit_and_path()
1409 commit_id, f_path = self._get_commit_and_path()
1408
1410
1409 self._ensure_not_locked()
1411 self._ensure_not_locked()
1410
1412
1411 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1413 c.commit = self._get_commit_or_redirect(commit_id, redirect_after=False)
1412 if c.commit is None:
1414 if c.commit is None:
1413 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1415 c.commit = EmptyCommit(alias=self.rhodecode_vcs_repo.alias)
1414
1416
1415 # calculate redirect URL
1417 # calculate redirect URL
1416 if self.rhodecode_vcs_repo.is_empty():
1418 if self.rhodecode_vcs_repo.is_empty():
1417 default_redirect_url = h.route_path(
1419 default_redirect_url = h.route_path(
1418 'repo_summary', repo_name=self.db_repo_name)
1420 'repo_summary', repo_name=self.db_repo_name)
1419 else:
1421 else:
1420 default_redirect_url = h.route_path(
1422 default_redirect_url = h.route_path(
1421 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1423 'repo_commit', repo_name=self.db_repo_name, commit_id='tip')
1422
1424
1423 if self.rhodecode_vcs_repo.is_empty():
1425 if self.rhodecode_vcs_repo.is_empty():
1424 # for empty repository we cannot check for current branch, we rely on
1426 # for empty repository we cannot check for current branch, we rely on
1425 # c.commit.branch instead
1427 # c.commit.branch instead
1426 _branch_name = c.commit.branch
1428 _branch_name = c.commit.branch
1427 is_head = True
1429 is_head = True
1428 else:
1430 else:
1429 _branch_name, _sha_commit_id, is_head = \
1431 _branch_name, _sha_commit_id, is_head = \
1430 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1432 self._is_valid_head(commit_id, self.rhodecode_vcs_repo)
1431
1433
1432 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1434 error = self.forbid_non_head(is_head, f_path, json_mode=True)
1433 if error:
1435 if error:
1434 return {
1436 return {
1435 'error': error,
1437 'error': error,
1436 'redirect_url': default_redirect_url
1438 'redirect_url': default_redirect_url
1437 }
1439 }
1438 error = self.check_branch_permission(_branch_name, json_mode=True)
1440 error = self.check_branch_permission(_branch_name, json_mode=True)
1439 if error:
1441 if error:
1440 return {
1442 return {
1441 'error': error,
1443 'error': error,
1442 'redirect_url': default_redirect_url
1444 'redirect_url': default_redirect_url
1443 }
1445 }
1444
1446
1445 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1447 c.default_message = (_('Uploaded file via RhodeCode Enterprise'))
1446 c.f_path = f_path
1448 c.f_path = f_path
1447
1449
1448 r_post = self.request.POST
1450 r_post = self.request.POST
1449
1451
1450 message = c.default_message
1452 message = c.default_message
1451 user_message = r_post.getall('message')
1453 user_message = r_post.getall('message')
1452 if isinstance(user_message, list) and user_message:
1454 if isinstance(user_message, list) and user_message:
1453 # we take the first from duplicated results if it's not empty
1455 # we take the first from duplicated results if it's not empty
1454 message = user_message[0] if user_message[0] else message
1456 message = user_message[0] if user_message[0] else message
1455
1457
1456 nodes = {}
1458 nodes = {}
1457
1459
1458 for file_obj in r_post.getall('files_upload') or []:
1460 for file_obj in r_post.getall('files_upload') or []:
1459 content = file_obj.file
1461 content = file_obj.file
1460 filename = file_obj.filename
1462 filename = file_obj.filename
1461
1463
1462 root_path = f_path
1464 root_path = f_path
1463 pure_path = self.create_pure_path(root_path, filename)
1465 pure_path = self.create_pure_path(root_path, filename)
1464 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1466 node_path = safe_unicode(bytes(pure_path).lstrip('/'))
1465
1467
1466 nodes[node_path] = {
1468 nodes[node_path] = {
1467 'content': content
1469 'content': content
1468 }
1470 }
1469
1471
1470 if not nodes:
1472 if not nodes:
1471 error = 'missing files'
1473 error = 'missing files'
1472 return {
1474 return {
1473 'error': error,
1475 'error': error,
1474 'redirect_url': default_redirect_url
1476 'redirect_url': default_redirect_url
1475 }
1477 }
1476
1478
1477 author = self._rhodecode_db_user.full_contact
1479 author = self._rhodecode_db_user.full_contact
1478
1480
1479 try:
1481 try:
1480 commit = ScmModel().create_nodes(
1482 commit = ScmModel().create_nodes(
1481 user=self._rhodecode_db_user.user_id,
1483 user=self._rhodecode_db_user.user_id,
1482 repo=self.db_repo,
1484 repo=self.db_repo,
1483 message=message,
1485 message=message,
1484 nodes=nodes,
1486 nodes=nodes,
1485 parent_commit=c.commit,
1487 parent_commit=c.commit,
1486 author=author,
1488 author=author,
1487 )
1489 )
1488 if len(nodes) == 1:
1490 if len(nodes) == 1:
1489 flash_message = _('Successfully committed {} new files').format(len(nodes))
1491 flash_message = _('Successfully committed {} new files').format(len(nodes))
1490 else:
1492 else:
1491 flash_message = _('Successfully committed 1 new file')
1493 flash_message = _('Successfully committed 1 new file')
1492
1494
1493 h.flash(flash_message, category='success')
1495 h.flash(flash_message, category='success')
1494
1496
1495 default_redirect_url = h.route_path(
1497 default_redirect_url = h.route_path(
1496 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1498 'repo_commit', repo_name=self.db_repo_name, commit_id=commit.raw_id)
1497
1499
1498 except NonRelativePathError:
1500 except NonRelativePathError:
1499 log.exception('Non Relative path found')
1501 log.exception('Non Relative path found')
1500 error = _('The location specified must be a relative path and must not '
1502 error = _('The location specified must be a relative path and must not '
1501 'contain .. in the path')
1503 'contain .. in the path')
1502 h.flash(error, category='warning')
1504 h.flash(error, category='warning')
1503
1505
1504 return {
1506 return {
1505 'error': error,
1507 'error': error,
1506 'redirect_url': default_redirect_url
1508 'redirect_url': default_redirect_url
1507 }
1509 }
1508 except (NodeError, NodeAlreadyExistsError) as e:
1510 except (NodeError, NodeAlreadyExistsError) as e:
1509 error = h.escape(e)
1511 error = h.escape(e)
1510 h.flash(error, category='error')
1512 h.flash(error, category='error')
1511
1513
1512 return {
1514 return {
1513 'error': error,
1515 'error': error,
1514 'redirect_url': default_redirect_url
1516 'redirect_url': default_redirect_url
1515 }
1517 }
1516 except Exception:
1518 except Exception:
1517 log.exception('Error occurred during commit')
1519 log.exception('Error occurred during commit')
1518 error = _('Error occurred during commit')
1520 error = _('Error occurred during commit')
1519 h.flash(error, category='error')
1521 h.flash(error, category='error')
1520 return {
1522 return {
1521 'error': error,
1523 'error': error,
1522 'redirect_url': default_redirect_url
1524 'redirect_url': default_redirect_url
1523 }
1525 }
1524
1526
1525 return {
1527 return {
1526 'error': None,
1528 'error': None,
1527 'redirect_url': default_redirect_url
1529 'redirect_url': default_redirect_url
1528 }
1530 }
@@ -1,151 +1,167 b''
1 ## -*- coding: utf-8 -*-
1 ## -*- coding: utf-8 -*-
2 <%namespace name="base" file="/base/base.mako"/>
2 <%namespace name="base" file="/base/base.mako"/>
3 %if c.repo_commits:
3 %if c.repo_commits:
4 <table class="rctable repo_summary table_disp">
4 <table class="rctable repo_summary table_disp">
5 <tr>
5 <tr>
6
6
7 <th class="status"></th>
7 <th class="status"></th>
8 <th>${_('Commit')}</th>
8 <th>${_('Commit')}</th>
9 <th>${_('Commit message')}</th>
9 <th>${_('Commit message')}</th>
10 <th>${_('Age')}</th>
10 <th>${_('Age')}</th>
11 <th>${_('Author')}</th>
11 <th>${_('Author')}</th>
12 <th colspan="2">${_('Refs')}</th>
12 <th colspan="2">${_('Refs')}</th>
13 </tr>
13 </tr>
14
14
15 ## to speed up lookups cache some functions before the loop
15 ## to speed up lookups cache some functions before the loop
16 <%
16 <%
17 active_patterns = h.get_active_pattern_entries(c.repo_name)
17 active_patterns = h.get_active_pattern_entries(c.repo_name)
18 urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns)
18 urlify_commit_message = h.partial(h.urlify_commit_message, active_pattern_entries=active_patterns)
19 %>
19 %>
20 %for cnt,cs in enumerate(c.repo_commits):
20 %for cnt,cs in enumerate(c.repo_commits):
21 <tr class="parity${cnt%2}">
21 <tr class="parity${cnt%2}">
22
22
23 <td class="td-status">
23 <td class="td-status">
24 %if c.statuses.get(cs.raw_id):
24 %if c.statuses.get(cs.raw_id):
25 <div class="changeset-status-ico shortlog">
25 <div class="changeset-status-ico shortlog">
26 %if c.statuses.get(cs.raw_id)[2]:
26 %if c.statuses.get(cs.raw_id)[2]:
27 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.route_path('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
27 <a class="tooltip" title="${_('Commit status: %s\nClick to open associated pull request #%s') % (c.statuses.get(cs.raw_id)[0], c.statuses.get(cs.raw_id)[2])}" href="${h.route_path('pullrequest_show',repo_name=c.statuses.get(cs.raw_id)[3],pull_request_id=c.statuses.get(cs.raw_id)[2])}">
28 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
28 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
29 </a>
29 </a>
30 %else:
30 %else:
31 <a class="tooltip" title="${_('Commit status: {}').format(h.commit_status_lbl(c.statuses.get(cs.raw_id)[0]))}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id,_anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
31 <a class="tooltip" title="${_('Commit status: {}').format(h.commit_status_lbl(c.statuses.get(cs.raw_id)[0]))}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id,_anchor='comment-%s' % c.comments[cs.raw_id][0].comment_id)}">
32 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
32 <div class="${'flag_status {}'.format(c.statuses.get(cs.raw_id)[0])}"></div>
33 </a>
33 </a>
34 %endif
34 %endif
35 </div>
35 </div>
36 %else:
36 %else:
37 <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
37 <div class="tooltip flag_status not_reviewed" title="${_('Commit status: Not Reviewed')}"></div>
38 %endif
38 %endif
39 </td>
39 </td>
40 <td class="td-commit">
40 <td class="td-commit">
41 <code>
41 <code>
42 <a href="${h.route_path('repo_commit', repo_name=c.repo_name, commit_id=cs.raw_id)}">${h.show_id(cs)}</a>
42 <a href="${h.route_path('repo_commit', repo_name=c.repo_name, commit_id=cs.raw_id)}">${h.show_id(cs)}</a>
43 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${cs.raw_id}" title="${_('Copy the full commit id')}"></i>
43 <i class="tooltip icon-clipboard clipboard-action" data-clipboard-text="${cs.raw_id}" title="${_('Copy the full commit id')}"></i>
44 </code>
44 </code>
45 </td>
45 </td>
46
46
47 <td class="td-description mid">
47 <td class="td-description mid">
48 <div class="log-container truncate-wrap">
48 <div class="log-container truncate-wrap">
49 <div class="message truncate" id="c-${cs.raw_id}">${urlify_commit_message(cs.message, c.repo_name)}</div>
49 <div class="message truncate" id="c-${cs.raw_id}">${urlify_commit_message(cs.message, c.repo_name)}</div>
50 </div>
50 </div>
51 </td>
51 </td>
52
52
53 <td class="td-time">
53 <td class="td-time">
54 ${h.age_component(cs.date)}
54 ${h.age_component(cs.date)}
55 </td>
55 </td>
56 <td class="td-user author">
56 <td class="td-user author">
57 ${base.gravatar_with_user(cs.author)}
57 ${base.gravatar_with_user(cs.author)}
58 </td>
58 </td>
59
59
60 <td class="td-tags">
60 <td class="td-tags">
61 <div class="autoexpand">
61 <div class="autoexpand">
62 %if h.is_hg(c.rhodecode_repo):
62 %if h.is_hg(c.rhodecode_repo):
63 %for book in cs.bookmarks:
63 %for book in cs.bookmarks:
64 <span class="booktag tag" title="${h.tooltip(_('Bookmark %s') % book)}">
64 <span class="booktag tag" title="${h.tooltip(_('Bookmark %s') % book)}">
65 <a href="${h.route_path('repo_files:default_path',repo_name=c.repo_name,commit_id=cs.raw_id, _query=dict(at=book))}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
65 <a href="${h.route_path('repo_files:default_path',repo_name=c.repo_name,commit_id=cs.raw_id, _query=dict(at=book))}"><i class="icon-bookmark"></i>${h.shorter(book)}</a>
66 </span>
66 </span>
67 %endfor
67 %endfor
68 %endif
68 %endif
69 ## tags
69 ## tags
70 %for tag in cs.tags:
70 %for tag in cs.tags:
71 <span class="tagtag tag" title="${h.tooltip(_('Tag %s') % tag)}">
71 <span class="tagtag tag" title="${h.tooltip(_('Tag %s') % tag)}">
72 <a href="${h.route_path('repo_files:default_path',repo_name=c.repo_name,commit_id=cs.raw_id, _query=dict(at=tag))}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
72 <a href="${h.route_path('repo_files:default_path',repo_name=c.repo_name,commit_id=cs.raw_id, _query=dict(at=tag))}"><i class="icon-tag"></i>${h.shorter(tag)}</a>
73 </span>
73 </span>
74 %endfor
74 %endfor
75
75
76 ## branch
76 ## branch
77 %if cs.branch:
77 %if cs.branch:
78 <span class="branchtag tag" title="${h.tooltip(_('Branch %s') % cs.branch)}">
78 <span class="branchtag tag" title="${h.tooltip(_('Branch %s') % cs.branch)}">
79 <a href="${h.route_path('repo_commits',repo_name=c.repo_name,_query=dict(branch=cs.branch))}"><i class="icon-code-fork"></i>${h.shorter(cs.branch)}</a>
79 <a href="${h.route_path('repo_commits',repo_name=c.repo_name,_query=dict(branch=cs.branch))}"><i class="icon-code-fork"></i>${h.shorter(cs.branch)}</a>
80 </span>
80 </span>
81 %endif
81 %endif
82 </div>
82 </div>
83 </td>
83 </td>
84 <td class="td-comments">
84 <td class="td-comments">
85 <% cs_comments = c.comments.get(cs.raw_id,[]) %>
85 <% cs_comments = c.comments.get(cs.raw_id,[]) %>
86 % if cs_comments:
86 % if cs_comments:
87 <a title="${_('Commit has comments')}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id,_anchor='comment-%s' % cs_comments[0].comment_id)}">
87 <a title="${_('Commit has comments')}" href="${h.route_path('repo_commit',repo_name=c.repo_name,commit_id=cs.raw_id,_anchor='comment-%s' % cs_comments[0].comment_id)}">
88 <i class="icon-comment"></i> ${len(cs_comments)}
88 <i class="icon-comment"></i> ${len(cs_comments)}
89 </a>
89 </a>
90 % else:
90 % else:
91 <i class="icon-comment"></i> ${len(cs_comments)}
91 <i class="icon-comment"></i> ${len(cs_comments)}
92 % endif
92 % endif
93 </td>
93 </td>
94 </tr>
94 </tr>
95 %endfor
95 %endfor
96
96
97 </table>
97 </table>
98
98
99 <script type="text/javascript">
99 <script type="text/javascript">
100 $(document).pjax('#shortlog_data .pager_link','#shortlog_data', {timeout: 5000, scrollTo: false, push: false});
100 $(document).pjax('#shortlog_data .pager_link','#shortlog_data', {timeout: 5000, scrollTo: false, push: false});
101 $(document).on('pjax:success', function(){ timeagoActivate(); });
101 $(document).on('pjax:success', function(){ timeagoActivate(); });
102 $(document).on('pjax:timeout', function(event) {
102 $(document).on('pjax:timeout', function(event) {
103 // Prevent default timeout redirection behavior
103 // Prevent default timeout redirection behavior
104 event.preventDefault()
104 event.preventDefault()
105 })
105 })
106
106
107 </script>
107 </script>
108
108
109 <div class="pagination-wh pagination-left">
109 <div class="pagination-wh pagination-left">
110 ${c.repo_commits.pager('$link_previous ~2~ $link_next')}
110 ${c.repo_commits.pager('$link_previous ~2~ $link_next')}
111 </div>
111 </div>
112 %else:
112 %else:
113
113
114 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
114 %if h.HasRepoPermissionAny('repository.write','repository.admin')(c.repo_name):
115 <div class="quick_start">
115 <div class="quick_start">
116 <div class="fieldset">
116 <div class="fieldset">
117 <p><b>${_('Add or upload files directly via RhodeCode:')}</b></p>
117 <p><b>${_('Add or upload files directly via RhodeCode:')}</b></p>
118 <div class="pull-left">
118 <div class="pull-left">
119 <a href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=0, f_path='')}" class="btn btn-default">${_('Add New File')}</a>
119 <a href="${h.route_path('repo_files_add_file',repo_name=c.repo_name,commit_id=0, f_path='')}" class="btn btn-default">${_('Add New File')}</a>
120 </div>
120 </div>
121 <div class="pull-left">
121 <div class="pull-left">
122 <a href="${h.route_path('repo_files_upload_file',repo_name=c.repo_name,commit_id=0, f_path='')}" class="btn btn-default">${_('Upload New File')}</a>
122 <a href="${h.route_path('repo_files_upload_file',repo_name=c.repo_name,commit_id=0, f_path='')}" class="btn btn-default">${_('Upload New File')}</a>
123 </div>
123 </div>
124 %endif
124 %endif
125 </div>
125 </div>
126
126
127 %if not h.is_svn(c.rhodecode_repo):
128 <div class="fieldset">
127 <div class="fieldset">
129 <p><b>${_('Push new repo:')}</b></p>
128 <p><b>${_('Push new repo:')}</b></p>
130 <pre>
129 <pre>
131 ${c.rhodecode_repo.alias} clone ${c.clone_repo_url}
130 %if h.is_git(c.rhodecode_repo):
132 ${c.rhodecode_repo.alias} add README # add first file
131 git clone ${c.clone_repo_url}
133 ${c.rhodecode_repo.alias} commit -m "Initial" # commit with message
132 git add README # add first file
134 ${c.rhodecode_repo.alias} push ${'origin master' if h.is_git(c.rhodecode_repo) else ''} # push changes back
133 git commit -m "Initial commit" # commit with message
134 git remote add origin ${c.clone_repo_url}
135 git push -u origin master # push changes back to default master branch
136 %elif h.is_hg(c.rhodecode_repo):
137 hg clone ${c.clone_repo_url}
138 hg add README # add first file
139 hg commit -m "Initial commit" # commit with message
140 hg push ${c.clone_repo_url}
141 %elif h.is_svn(c.rhodecode_repo):
142 svn co ${c.clone_repo_url}
143 svn add README # add first file
144 svn commit -m "Initial commit"
145 svn commit # send changes back to the server
146 %endif
135 </pre>
147 </pre>
136 </div>
148 </div>
137
149
138 <div class="fieldset">
150 <div class="fieldset">
139 <p><b>${_('Existing repository?')}</b></p>
151 <p><b>${_('Existing repository?')}</b></p>
140 <pre>
152 <pre>
141 %if h.is_git(c.rhodecode_repo):
153 %if h.is_git(c.rhodecode_repo):
142 git remote add origin ${c.clone_repo_url}
154 git remote add origin ${c.clone_repo_url}
143 git push -u origin master
155 git push -u origin master
144 %else:
156 %elif h.is_hg(c.rhodecode_repo):
145 hg push ${c.clone_repo_url}
157 hg push ${c.clone_repo_url}
158 %elif h.is_svn(c.rhodecode_repo):
159 svn co ${c.clone_repo_url}
146 %endif
160 %endif
147 </pre>
161 </pre>
162
163 </div>
164
165
148 </div>
166 </div>
149 %endif
167 %endif
150 </div>
151 %endif
General Comments 0
You need to be logged in to leave comments. Login now