Mercurial > kallithea
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