diff --git a/rhodecode/apps/repository/views/repo_files.py b/rhodecode/apps/repository/views/repo_files.py --- a/rhodecode/apps/repository/views/repo_files.py +++ b/rhodecode/apps/repository/views/repo_files.py @@ -325,6 +325,21 @@ class RepoFilesView(RepoAppView): return lf_enabled + def _get_archive_name(self, db_repo_name, commit_sha, ext, subrepos=False, path_sha=''): + # original backward compat name of archive + clean_name = safe_str(db_repo_name.replace('/', '_')) + + # e.g vcsserver.zip + # e.g vcsserver-abcdefgh.zip + # e.g vcsserver-abcdefgh-defghijk.zip + archive_name = '{}{}{}{}{}'.format( + clean_name, + '-sub' if subrepos else '', + commit_sha, + '-{}'.format(path_sha) if path_sha else '', + ext) + return archive_name + @LoginRequired() @HasRepoPermissionAnyDecorator( 'repository.read', 'repository.write', 'repository.admin') @@ -339,6 +354,7 @@ class RepoFilesView(RepoAppView): default_at_path = '/' fname = self.request.matchdict['fname'] subrepos = self.request.GET.get('subrepos') == 'true' + with_hash = str2bool(self.request.GET.get('with_hash', '1')) at_path = self.request.GET.get('at_path') or default_at_path if not self.db_repo.enable_downloads: @@ -364,26 +380,26 @@ class RepoFilesView(RepoAppView): except Exception: return Response(_('No node at path {} for this repository').format(at_path)) - path_sha = sha1(at_path)[:8] - - # original backward compat name of archive - clean_name = safe_str(self.db_repo_name.replace('/', '_')) - short_sha = safe_str(commit.short_id) + # path sha is part of subdir + path_sha = '' + if at_path != default_at_path: + path_sha = sha1(at_path)[:8] + short_sha = '-{}'.format(safe_str(commit.short_id)) + # used for cache etc + archive_name = self._get_archive_name( + self.db_repo_name, commit_sha=short_sha, ext=ext, subrepos=subrepos, + path_sha=path_sha) - if at_path == default_at_path: - archive_name = '{}-{}{}{}'.format( - clean_name, - '-sub' if subrepos else '', - short_sha, - ext) - # custom path and new name - else: - archive_name = '{}-{}{}-{}{}'.format( - clean_name, - '-sub' if subrepos else '', - short_sha, - path_sha, - ext) + if not with_hash: + short_sha = '' + path_sha = '' + + # what end client gets served + response_archive_name = self._get_archive_name( + self.db_repo_name, commit_sha=short_sha, ext=ext, subrepos=subrepos, + path_sha=path_sha) + # remove extension from our archive directory name + archive_dir_name = response_archive_name[:-len(ext)] use_cached_archive = False archive_cache_enabled = CONFIG.get( @@ -403,13 +419,15 @@ class RepoFilesView(RepoAppView): else: log.debug('Archive %s is not yet cached', archive_name) + # generate new archive, as previous was not found in the cache if not use_cached_archive: - # generate new archive + fd, archive = tempfile.mkstemp() log.debug('Creating new temp archive in %s', archive) try: - commit.archive_repo(archive, kind=fileformat, subrepos=subrepos, - archive_at_path=at_path) + commit.archive_repo(archive, archive_dir_name=archive_dir_name, + kind=fileformat, subrepos=subrepos, + archive_at_path=at_path, with_hash=with_hash) except ImproperArchiveTypeError: return _('Unknown archive type') if archive_cache_enabled: @@ -445,8 +463,7 @@ class RepoFilesView(RepoAppView): yield data response = Response(app_iter=get_chunked_archive(archive)) - response.content_disposition = str( - 'attachment; filename=%s' % archive_name) + response.content_disposition = str('attachment; filename=%s' % response_archive_name) response.content_type = str(content_type) return response diff --git a/rhodecode/lib/vcs/backends/base.py b/rhodecode/lib/vcs/backends/base.py --- a/rhodecode/lib/vcs/backends/base.py +++ b/rhodecode/lib/vcs/backends/base.py @@ -1192,13 +1192,14 @@ class BaseCommit(object): return None def archive_repo(self, archive_dest_path, kind='tgz', subrepos=None, - prefix=None, write_metadata=False, mtime=None, archive_at_path='/'): + archive_dir_name=None, write_metadata=False, mtime=None, + archive_at_path='/', with_hash=True): """ Creates an archive containing the contents of the repository. :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. + :param archive_dir_name: name of root directory in archive. Default is repository name and commit's short_id joined with dash: ``"{repo_name}-{short_id}"``. :param write_metadata: write a metadata file into archive. @@ -1214,7 +1215,7 @@ class BaseCommit(object): 'Archive kind (%s) not supported use one of %s' % (kind, allowed_kinds)) - prefix = self._validate_archive_prefix(prefix) + archive_dir_name = self._validate_archive_prefix(archive_dir_name) mtime = mtime is not None or time.mktime(self.date.timetuple()) @@ -1222,7 +1223,7 @@ class BaseCommit(object): cur_rev = self.repository.get_commit(commit_id=self.raw_id) for _r, _d, files in cur_rev.walk(archive_at_path): for f in files: - f_path = os.path.join(prefix, f.path) + f_path = os.path.join(archive_dir_name, f.path) file_info.append( (f_path, f.mode, f.is_link(), f.raw_bytes)) @@ -1239,18 +1240,18 @@ class BaseCommit(object): connection.Hg.archive_repo(archive_dest_path, mtime, file_info, kind) - def _validate_archive_prefix(self, prefix): - if prefix is None: - prefix = self._ARCHIVE_PREFIX_TEMPLATE.format( + def _validate_archive_prefix(self, archive_dir_name): + if archive_dir_name is None: + archive_dir_name = self._ARCHIVE_PREFIX_TEMPLATE.format( repo_name=safe_str(self.repository.name), short_id=self.short_id) - elif not isinstance(prefix, str): - raise ValueError("prefix not a bytes object: %s" % repr(prefix)) - elif prefix.startswith('/'): + elif not isinstance(archive_dir_name, str): + raise ValueError("prefix not a bytes object: %s" % repr(archive_dir_name)) + elif archive_dir_name.startswith('/'): raise VCSError("Prefix cannot start with leading slash") - elif prefix.strip() == '': + elif archive_dir_name.strip() == '': raise VCSError("Prefix cannot be empty") - return prefix + return archive_dir_name @LazyProperty def root(self): diff --git a/rhodecode/templates/files/files_browser.mako b/rhodecode/templates/files/files_browser.mako --- a/rhodecode/templates/files/files_browser.mako +++ b/rhodecode/templates/files/files_browser.mako @@ -51,7 +51,7 @@ ${_('Download full tree ZIP')} % else: - + ${_('Download this tree ZIP')} % endif diff --git a/rhodecode/templates/summary/components.mako b/rhodecode/templates/summary/components.mako --- a/rhodecode/templates/summary/components.mako +++ b/rhodecode/templates/summary/components.mako @@ -187,7 +187,7 @@