diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py --- a/rhodecode/api/views/repo_api.py +++ b/rhodecode/api/views/repo_api.py @@ -504,7 +504,8 @@ def get_repo_nodes(request, apiuser, rep @jsonrpc_method() def get_repo_file(request, apiuser, repoid, commit_id, file_path, - max_file_bytes=Optional(None), details=Optional('basic')): + max_file_bytes=Optional(None), details=Optional('basic'), + cache=Optional(True)): """ Returns a single file from repository at given revision. @@ -523,8 +524,10 @@ def get_repo_file(request, apiuser, repo The valid options are ``minimal`` ``basic`` and ``full``. :type details: Optional(str) :param max_file_bytes: Only return file content under this file size bytes - :type details: Optional(int) - + :type max_file_bytes: Optional(int) + :param cache: Use internal caches for fetching files. If disabled fetching + files is slower but more memory efficient + :type cache: Optional(bool) Example output: .. code-block:: bash @@ -549,6 +552,7 @@ def get_repo_file(request, apiuser, repo _perms = ('repository.admin', 'repository.write', 'repository.read',) validate_repo_permissions(apiuser, repoid, repo, _perms) + cache = Optional.extract(cache, binary=True) details = Optional.extract(details) _extended_types = ['minimal', 'minimal+search', 'basic', 'full'] if details not in _extended_types: @@ -574,7 +578,7 @@ def get_repo_file(request, apiuser, repo node = ScmModel().get_node( repo, commit_id, file_path, extended_info=extended_info, - content=content, max_file_bytes=max_file_bytes) + content=content, max_file_bytes=max_file_bytes, cache=cache) except Exception: log.exception("Exception occurred while trying to get repo node") diff --git a/rhodecode/lib/vcs/nodes.py b/rhodecode/lib/vcs/nodes.py --- a/rhodecode/lib/vcs/nodes.py +++ b/rhodecode/lib/vcs/nodes.py @@ -381,16 +381,25 @@ class FileNode(Node): Returns md5, binary flag of the file node, without any cache usage. """ - if self.commit: - content = self.commit.get_file_content(self.path) - else: - content = self._content + content = self.content_uncached() is_binary = content and '\0' in content size = 0 if content: size = len(content) - return is_binary, md5(content), size + + return is_binary, md5(content), size, content + + def content_uncached(self): + """ + Returns lazily content of the FileNode. If possible, would try to + decode content from UTF-8. + """ + if self.commit: + content = self.commit.get_file_content(self.path) + else: + content = self._content + return content @LazyProperty def content(self): diff --git a/rhodecode/model/scm.py b/rhodecode/model/scm.py --- a/rhodecode/model/scm.py +++ b/rhodecode/model/scm.py @@ -583,7 +583,7 @@ class ScmModel(BaseModel): return _dirs, _files def get_node(self, repo_name, commit_id, file_path, - extended_info=False, content=False, max_file_bytes=None): + extended_info=False, content=False, max_file_bytes=None, cache=True): """ retrieve single node from commit """ @@ -606,12 +606,21 @@ class ScmModel(BaseModel): if extended_info: file_data.update({ - "md5": file_node.md5, - "binary": file_node.is_binary, - "size": file_node.size, "extension": file_node.extension, "mimetype": file_node.mimetype, - "lines": file_node.lines()[0] + }) + + if cache: + md5 = file_node.md5 + is_binary = file_node.is_binary + size = file_node.size + else: + is_binary, md5, size, _content = file_node.metadata_uncached() + + file_data.update({ + "md5": md5, + "binary": is_binary, + "size": size, }) if content: @@ -619,7 +628,13 @@ class ScmModel(BaseModel): and file_node.size > max_file_bytes) full_content = None if not file_node.is_binary and not over_size_limit: - full_content = safe_str(file_node.content) + if cache: + full_content = safe_str(file_node.content) + else: + if _content is None: + is_binary, md5, size, _content = \ + file_node.metadata_uncached() + full_content = safe_str(_content) file_data.update({ "content": full_content, @@ -647,7 +662,7 @@ class ScmModel(BaseModel): for f in files: _content = None _data = f_name = f.unicode_path - is_binary, md5, size = f.metadata_uncached() + is_binary, md5, size, _content = f.metadata_uncached() _data = { "name": h.escape(f_name), "md5": md5,