changeset 3490:c0ac34b8eb07 beta

initial version of #788 tarball cache
author Marcin Kuzminski <marcin@python-works.com>
date Wed, 06 Mar 2013 18:47:59 +0100
parents d997a314d18a
children bdb997400835
files development.ini production.ini rhodecode/config/deployment.ini_tmpl rhodecode/controllers/files.py test.ini
diffstat 5 files changed, 48 insertions(+), 9 deletions(-) [+]
line wrap: on
line diff
--- a/development.ini	Wed Mar 06 18:12:09 2013 +0100
+++ b/development.ini	Wed Mar 06 18:47:59 2013 +0100
@@ -65,6 +65,8 @@
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
+# set this path to use archive download cache
+#archive_cache_dir = /tmp/rhodecode_tarballcache
 app_instance_uuid = rc-develop
 cut_off_limit = 256000
 vcs_full_cache = True
--- a/production.ini	Wed Mar 06 18:12:09 2013 +0100
+++ b/production.ini	Wed Mar 06 18:47:59 2013 +0100
@@ -65,6 +65,8 @@
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
+# set this path to use archive download cache
+#archive_cache_dir = /tmp/rhodecode_tarballcache
 app_instance_uuid = rc-production
 cut_off_limit = 256000
 vcs_full_cache = True
--- a/rhodecode/config/deployment.ini_tmpl	Wed Mar 06 18:12:09 2013 +0100
+++ b/rhodecode/config/deployment.ini_tmpl	Wed Mar 06 18:47:59 2013 +0100
@@ -65,6 +65,8 @@
 lang = en
 cache_dir = %(here)s/data
 index_dir = %(here)s/data/index
+# set this path to use archive download cache
+#archive_cache_dir = /tmp/rhodecode_tarballcache
 app_instance_uuid = ${app_instance_uuid}
 cut_off_limit = 256000
 vcs_full_cache = True
--- a/rhodecode/controllers/files.py	Wed Mar 06 18:12:09 2013 +0100
+++ b/rhodecode/controllers/files.py	Wed Mar 06 18:47:59 2013 +0100
@@ -27,6 +27,7 @@
 import logging
 import traceback
 import tempfile
+import shutil
 
 from pylons import request, response, tmpl_context as c, url
 from pylons.i18n.translation import _
@@ -429,11 +430,40 @@
             return _('Empty repository')
         except (ImproperArchiveTypeError, KeyError):
             return _('Unknown archive type')
+        # archive cache
+        from rhodecode import CONFIG
+        rev_name = cs.raw_id[:12]
+        archive_name = '%s-%s%s' % (safe_str(repo_name.replace('/', '_')),
+                                    safe_str(rev_name), ext)
 
-        fd, archive = tempfile.mkstemp()
-        t = open(archive, 'wb')
-        cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
-        t.close()
+        use_cached_archive = False  # defines if we use cached version of archive
+        archive_cache_enabled = CONFIG.get('archive_cache_dir')
+        if not subrepos and archive_cache_enabled:
+            #check if we it's ok to write
+            if not os.path.isdir(CONFIG['archive_cache_dir']):
+                os.makedirs(CONFIG['archive_cache_dir'])
+            cached_archive_path = os.path.join(CONFIG['archive_cache_dir'], archive_name)
+            if os.path.isfile(cached_archive_path):
+                log.debug('Found cached archive in %s' % cached_archive_path)
+                fd, archive = None, cached_archive_path
+                use_cached_archive = True
+            else:
+                log.debug('Archive %s is not yet cached' % (archive_name))
+
+        if not use_cached_archive:
+            #generate new archive
+            try:
+                fd, archive = tempfile.mkstemp()
+                t = open(archive, 'wb')
+                log.debug('Creating new temp archive in %s' % archive)
+                cs.fill_archive(stream=t, kind=fileformat, subrepos=subrepos)
+                if archive_cache_enabled:
+                    #if we generated the archive and use cache rename that
+                    log.debug('Storing new archive in %s' % cached_archive_path)
+                    shutil.move(archive, cached_archive_path)
+                    archive = cached_archive_path
+            finally:
+                t.close()
 
         def get_chunked_archive(archive):
             stream = open(archive, 'rb')
@@ -441,14 +471,15 @@
                 data = stream.read(16 * 1024)
                 if not data:
                     stream.close()
-                    os.close(fd)
-                    os.remove(archive)
+                    if fd:  # fd means we used temporary file
+                        os.close(fd)
+                    if not archive_cache_enabled:
+                        log.debug('Destroing temp archive %s' % archive)
+                        os.remove(archive)
                     break
                 yield data
 
-        response.content_disposition = str('attachment; filename=%s-%s%s' \
-                                           % (safe_str(repo_name),
-                                              safe_str(revision), ext))
+        response.content_disposition = str('attachment; filename=%s' % (archive_name))
         response.content_type = str(content_type)
         return get_chunked_archive(archive)
 
--- a/test.ini	Wed Mar 06 18:12:09 2013 +0100
+++ b/test.ini	Wed Mar 06 18:47:59 2013 +0100
@@ -65,6 +65,8 @@
 lang = en
 cache_dir = /tmp/rc/data
 index_dir = /tmp/rc/index
+# set this path to use archive download cache
+#archive_cache_dir = /tmp/rhodecode_tarballcache
 app_instance_uuid = develop-test
 cut_off_limit = 256000
 vcs_full_cache = False