diff rhodecode/model/gist.py @ 3840:dc4644865e8b beta

Implemented simple gist functionality ref #530. - creation of public/private gists with given lifetime - rhodecode-gist CLI for quick gist creation
author Marcin Kuzminski <marcin@python-works.com>
date Sat, 11 May 2013 20:24:02 +0200
parents
children 979edf6a2990
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rhodecode/model/gist.py	Sat May 11 20:24:02 2013 +0200
@@ -0,0 +1,161 @@
+# -*- coding: utf-8 -*-
+"""
+    rhodecode.model.gist
+    ~~~~~~~~~~~~~~~~~~~~
+
+    gist model for RhodeCode
+
+    :created_on: May 9, 2013
+    :author: marcink
+    :copyright: (C) 2011-2013 Marcin Kuzminski <marcin@python-works.com>
+    :license: GPLv3, see COPYING for more details.
+"""
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import time
+import logging
+import traceback
+import shutil
+
+from pylons.i18n.translation import _
+from rhodecode.lib.utils2 import safe_unicode, unique_id, safe_int, \
+    time_to_datetime, safe_str, AttributeDict
+from rhodecode.lib import helpers as h
+from rhodecode.model import BaseModel
+from rhodecode.model.db import Gist
+from rhodecode.model.repo import RepoModel
+from rhodecode.model.scm import ScmModel
+from rhodecode.lib.vcs import get_repo
+
+log = logging.getLogger(__name__)
+
+GIST_STORE_LOC = '.gist_store'
+
+
+class GistModel(BaseModel):
+
+    def _get_gist(self, gist):
+        """
+        Helper method to get gist by ID, or gist_access_id as a fallback
+
+        :param gist: GistID, gist_access_id, or Gist instance
+        """
+        return self._get_instance(Gist, gist,
+                                  callback=Gist.get_by_access_id)
+
+    def __delete_gist(self, gist):
+        """
+        removes gist from filesystem
+
+        :param gist: gist object
+        """
+        root_path = RepoModel().repos_path
+        rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
+        log.info("Removing %s" % (rm_path))
+        shutil.rmtree(rm_path)
+
+    def get_gist_files(self, gist_access_id):
+        """
+        Get files for given gist
+
+        :param gist_access_id:
+        """
+        root_path = RepoModel().repos_path
+        r = get_repo(os.path.join(*map(safe_str,
+                                [root_path, GIST_STORE_LOC, gist_access_id])))
+        cs = r.get_changeset()
+        return (
+         cs, [n for n in cs.get_node('/')]
+        )
+
+    def create(self, description, owner, gist_mapping,
+               gist_type=Gist.GIST_PUBLIC, lifetime=-1):
+        """
+
+        :param description: description of the gist
+        :param owner: user who created this gist
+        :param gist_mapping: mapping {filename:{'content':content},...}
+        :param gist_type: type of gist private/public
+        :param lifetime: in minutes, -1 == forever
+        """
+        gist_id = safe_unicode(unique_id(20))
+        lifetime = safe_int(lifetime, -1)
+        gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
+        log.debug('set GIST expiration date to: %s'
+                  % (time_to_datetime(gist_expires)
+                   if gist_expires != -1 else 'forever'))
+        #create the Database version
+        gist = Gist()
+        gist.gist_description = description
+        gist.gist_access_id = gist_id
+        gist.gist_owner = owner.user_id
+        gist.gist_expires = gist_expires
+        gist.gist_type = safe_unicode(gist_type)
+        self.sa.add(gist)
+        self.sa.flush()
+        if gist_type == Gist.GIST_PUBLIC:
+            # use DB ID for easy to use GIST ID
+            gist_id = safe_unicode(gist.gist_id)
+            gist.gist_access_id = gist_id
+            self.sa.add(gist)
+
+        gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
+        log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path))
+        repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg',
+                                        parent=None)
+
+        processed_mapping = {}
+        for filename in gist_mapping:
+            content = gist_mapping[filename]['content']
+            #TODO: expand support for setting explicit lexers
+#             if lexer is None:
+#                 try:
+#                     lexer = pygments.lexers.guess_lexer_for_filename(filename,content)
+#                 except pygments.util.ClassNotFound:
+#                     lexer = 'text'
+            processed_mapping[filename] = {'content': content}
+
+        # now create single multifile commit
+        message = 'added file'
+        message += 's: ' if len(processed_mapping) > 1 else ': '
+        message += ', '.join([x for x in processed_mapping])
+
+        #fake RhodeCode Repository object
+        fake_repo = AttributeDict(dict(
+            repo_name=gist_repo_path,
+            scm_instance_no_cache=lambda: repo,
+        ))
+        ScmModel().create_nodes(
+            user=owner.user_id, repo=fake_repo,
+            message=message,
+            nodes=processed_mapping,
+            trigger_push_hook=False
+        )
+
+        return gist
+
+    def delete(self, gist, fs_remove=True):
+        gist = self._get_gist(gist)
+
+        try:
+            self.sa.delete(gist)
+            if fs_remove:
+                self.__delete_gist(gist)
+            else:
+                log.debug('skipping removal from filesystem')
+
+        except Exception:
+            log.error(traceback.format_exc())
+            raise