files: allow partial tree downloads

This commit is contained in:
Marcin Kuzminski 2019-05-30 14:46:07 +02:00
parent 38689f31f9
commit 6e5c2a96a2
4 changed files with 28 additions and 15 deletions

View file

@ -42,7 +42,7 @@ from rhodecode.lib.exceptions import NonRelativePathError
from rhodecode.lib.codeblocks import (
filenode_as_lines_tokens, filenode_as_annotated_lines_tokens)
from rhodecode.lib.utils2 import (
convert_line_endings, detect_mode, safe_str, str2bool, safe_int)
convert_line_endings, detect_mode, safe_str, str2bool, safe_int, sha1)
from rhodecode.lib.auth import (
LoginRequired, HasRepoPermissionAnyDecorator, CSRFRequired)
from rhodecode.lib.vcs import path as vcspath
@ -243,16 +243,16 @@ class RepoFilesView(RepoAppView):
@region.conditional_cache_on_arguments(namespace=cache_namespace_uid,
condition=cache_on)
def compute_file_tree(repo_id, commit_id, f_path, full_load):
log.debug('Generating cached file tree for repo_id: %s, %s, %s',
repo_id, commit_id, f_path)
def compute_file_tree(ver, repo_id, commit_id, f_path, full_load):
log.debug('Generating cached file tree at ver:%s for repo_id: %s, %s, %s',
ver, repo_id, commit_id, f_path)
c.full_load = full_load
return render(
'rhodecode:templates/files/files_browser_tree.mako',
self._get_template_context(c), self.request)
return compute_file_tree(self.db_repo.repo_id, commit_id, f_path, full_load)
return compute_file_tree('v1', self.db_repo.repo_id, commit_id, f_path, full_load)
def _get_archive_spec(self, fname):
log.debug('Detecting archive spec for: `%s`', fname)
@ -291,6 +291,7 @@ class RepoFilesView(RepoAppView):
fname = self.request.matchdict['fname']
subrepos = self.request.GET.get('subrepos') == 'true'
at_path = self.request.GET.get('at_path') or '/'
if not self.db_repo.enable_downloads:
return Response(_('Downloads disabled'))
@ -310,10 +311,19 @@ class RepoFilesView(RepoAppView):
except EmptyRepositoryError:
return Response(_('Empty repository'))
archive_name = '%s-%s%s%s' % (
try:
at_path = commit.get_node(at_path).path
except Exception:
return Response(_('No node at path {} for this repository').format(at_path))
path_sha = sha1(at_path)[:8]
archive_name = '{}-{}{}-{}{}'.format(
safe_str(self.db_repo_name.replace('/', '_')),
'-sub' if subrepos else '',
safe_str(commit.short_id), ext)
safe_str(commit.short_id),
path_sha,
ext)
use_cached_archive = False
archive_cache_enabled = CONFIG.get(
@ -338,7 +348,8 @@ class RepoFilesView(RepoAppView):
fd, archive = tempfile.mkstemp()
log.debug('Creating new temp archive in %s', archive)
try:
commit.archive_repo(archive, kind=fileformat, subrepos=subrepos)
commit.archive_repo(archive, kind=fileformat, subrepos=subrepos,
archive_at_path=at_path)
except ImproperArchiveTypeError:
return _('Unknown archive type')
if archive_cache_enabled:

View file

@ -1094,12 +1094,12 @@ class BaseCommit(object):
"""
return None
def archive_repo(self, file_path, kind='tgz', subrepos=None,
prefix=None, write_metadata=False, mtime=None):
def archive_repo(self, archive_dest_path, kind='tgz', subrepos=None,
prefix=None, write_metadata=False, mtime=None, archive_at_path='/'):
"""
Creates an archive containing the contents of the repository.
:param file_path: path to the file which to create the archive.
:param archive_dest_path: path to the file which to create the archive.
:param kind: one of following: ``"tbz2"``, ``"tgz"``, ``"zip"``.
:param prefix: name of root directory in archive.
Default is repository name and commit's short_id joined with dash:
@ -1107,6 +1107,7 @@ class BaseCommit(object):
:param write_metadata: write a metadata file into archive.
:param mtime: custom modification time for archive creation, defaults
to time.time() if not given.
:param archive_at_path: pack files at this path (default '/')
:raise VCSError: If prefix has a problem.
"""
@ -1122,7 +1123,7 @@ class BaseCommit(object):
file_info = []
cur_rev = self.repository.get_commit(commit_id=self.raw_id)
for _r, _d, files in cur_rev.walk('/'):
for _r, _d, files in cur_rev.walk(archive_at_path):
for f in files:
f_path = os.path.join(prefix, f.path)
file_info.append(
@ -1131,6 +1132,7 @@ class BaseCommit(object):
if write_metadata:
metadata = [
('repo_name', self.repository.name),
('commit_id', self.raw_id),
('rev', self.raw_id),
('create_time', mtime),
('branch', self.branch),
@ -1139,7 +1141,7 @@ class BaseCommit(object):
meta = ["%s:%s" % (f_name, value) for f_name, value in metadata]
file_info.append(('.archival.txt', 0o644, False, '\n'.join(meta)))
connection.Hg.archive_repo(file_path, mtime, file_info, kind)
connection.Hg.archive_repo(archive_dest_path, mtime, file_info, kind)
def _validate_archive_prefix(self, prefix):
if prefix is None:

View file

@ -35,7 +35,7 @@
</td>
<td class="td-actions">
<a href="${h.route_path('repo_compare',repo_name=c.repo_name, source_ref_type="rev", source_ref=cs.raw_id,target_ref_type="rev", target_ref=c.commit_id,_query=dict(merge='1',f_path=c.changelog_for_path))}">
${_('Diff File')}
<span title="${'Diff {} vs {}'.format(cs.raw_id[:8],c.commit_id[:8])}">${_('Diff File')}</span>
</a>
</td>
</tr>

View file

@ -35,7 +35,7 @@
${_('Download full tree ZIP')}
</a>
% else:
<a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id))}">
<a href="${h.route_path('repo_archivefile',repo_name=c.repo_name, fname='{}.zip'.format(c.commit.raw_id), _query={'at_path':c.f_path})}">
${_('Download this tree ZIP')}
</a>
% endif