##// END OF EJS Templates
Prefix gist storage with rc, and store some metadata info into...
marcink -
r3841:979edf6a beta
parent child Browse files
Show More
@@ -1,161 +1,173 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.gist
3 rhodecode.model.gist
4 ~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~
5
5
6 gist model for RhodeCode
6 gist model for RhodeCode
7
7
8 :created_on: May 9, 2013
8 :created_on: May 9, 2013
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2011-2013 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2011-2013 Marcin Kuzminski <marcin@python-works.com>
11 :license: GPLv3, see COPYING for more details.
11 :license: GPLv3, see COPYING for more details.
12 """
12 """
13 # This program is free software: you can redistribute it and/or modify
13 # This program is free software: you can redistribute it and/or modify
14 # it under the terms of the GNU General Public License as published by
14 # it under the terms of the GNU General Public License as published by
15 # the Free Software Foundation, either version 3 of the License, or
15 # the Free Software Foundation, either version 3 of the License, or
16 # (at your option) any later version.
16 # (at your option) any later version.
17 #
17 #
18 # This program is distributed in the hope that it will be useful,
18 # This program is distributed in the hope that it will be useful,
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # but WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 # GNU General Public License for more details.
21 # GNU General Public License for more details.
22 #
22 #
23 # You should have received a copy of the GNU General Public License
23 # You should have received a copy of the GNU General Public License
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
24 # along with this program. If not, see <http://www.gnu.org/licenses/>.
25
25 from __future__ import with_statement
26 import os
26 import os
27 import time
27 import time
28 import logging
28 import logging
29 import traceback
29 import traceback
30 import shutil
30 import shutil
31
31
32 from pylons.i18n.translation import _
32 from pylons.i18n.translation import _
33 from rhodecode.lib.utils2 import safe_unicode, unique_id, safe_int, \
33 from rhodecode.lib.utils2 import safe_unicode, unique_id, safe_int, \
34 time_to_datetime, safe_str, AttributeDict
34 time_to_datetime, safe_str, AttributeDict
35 from rhodecode.lib.compat import json
35 from rhodecode.lib import helpers as h
36 from rhodecode.lib import helpers as h
36 from rhodecode.model import BaseModel
37 from rhodecode.model import BaseModel
37 from rhodecode.model.db import Gist
38 from rhodecode.model.db import Gist
38 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.repo import RepoModel
39 from rhodecode.model.scm import ScmModel
40 from rhodecode.model.scm import ScmModel
40 from rhodecode.lib.vcs import get_repo
41 from rhodecode.lib.vcs import get_repo
41
42
42 log = logging.getLogger(__name__)
43 log = logging.getLogger(__name__)
43
44
44 GIST_STORE_LOC = '.gist_store'
45 GIST_STORE_LOC = '.rc_gist_store'
46 GIST_METADATA_FILE = '.rc_gist_metadata'
45
47
46
48
47 class GistModel(BaseModel):
49 class GistModel(BaseModel):
48
50
49 def _get_gist(self, gist):
51 def _get_gist(self, gist):
50 """
52 """
51 Helper method to get gist by ID, or gist_access_id as a fallback
53 Helper method to get gist by ID, or gist_access_id as a fallback
52
54
53 :param gist: GistID, gist_access_id, or Gist instance
55 :param gist: GistID, gist_access_id, or Gist instance
54 """
56 """
55 return self._get_instance(Gist, gist,
57 return self._get_instance(Gist, gist,
56 callback=Gist.get_by_access_id)
58 callback=Gist.get_by_access_id)
57
59
58 def __delete_gist(self, gist):
60 def __delete_gist(self, gist):
59 """
61 """
60 removes gist from filesystem
62 removes gist from filesystem
61
63
62 :param gist: gist object
64 :param gist: gist object
63 """
65 """
64 root_path = RepoModel().repos_path
66 root_path = RepoModel().repos_path
65 rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
67 rm_path = os.path.join(root_path, GIST_STORE_LOC, gist.gist_access_id)
66 log.info("Removing %s" % (rm_path))
68 log.info("Removing %s" % (rm_path))
67 shutil.rmtree(rm_path)
69 shutil.rmtree(rm_path)
68
70
69 def get_gist_files(self, gist_access_id):
71 def get_gist_files(self, gist_access_id):
70 """
72 """
71 Get files for given gist
73 Get files for given gist
72
74
73 :param gist_access_id:
75 :param gist_access_id:
74 """
76 """
75 root_path = RepoModel().repos_path
77 root_path = RepoModel().repos_path
76 r = get_repo(os.path.join(*map(safe_str,
78 r = get_repo(os.path.join(*map(safe_str,
77 [root_path, GIST_STORE_LOC, gist_access_id])))
79 [root_path, GIST_STORE_LOC, gist_access_id])))
78 cs = r.get_changeset()
80 cs = r.get_changeset()
79 return (
81 return (
80 cs, [n for n in cs.get_node('/')]
82 cs, [n for n in cs.get_node('/')]
81 )
83 )
82
84
83 def create(self, description, owner, gist_mapping,
85 def create(self, description, owner, gist_mapping,
84 gist_type=Gist.GIST_PUBLIC, lifetime=-1):
86 gist_type=Gist.GIST_PUBLIC, lifetime=-1):
85 """
87 """
86
88
87 :param description: description of the gist
89 :param description: description of the gist
88 :param owner: user who created this gist
90 :param owner: user who created this gist
89 :param gist_mapping: mapping {filename:{'content':content},...}
91 :param gist_mapping: mapping {filename:{'content':content},...}
90 :param gist_type: type of gist private/public
92 :param gist_type: type of gist private/public
91 :param lifetime: in minutes, -1 == forever
93 :param lifetime: in minutes, -1 == forever
92 """
94 """
93 gist_id = safe_unicode(unique_id(20))
95 gist_id = safe_unicode(unique_id(20))
94 lifetime = safe_int(lifetime, -1)
96 lifetime = safe_int(lifetime, -1)
95 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
97 gist_expires = time.time() + (lifetime * 60) if lifetime != -1 else -1
96 log.debug('set GIST expiration date to: %s'
98 log.debug('set GIST expiration date to: %s'
97 % (time_to_datetime(gist_expires)
99 % (time_to_datetime(gist_expires)
98 if gist_expires != -1 else 'forever'))
100 if gist_expires != -1 else 'forever'))
99 #create the Database version
101 #create the Database version
100 gist = Gist()
102 gist = Gist()
101 gist.gist_description = description
103 gist.gist_description = description
102 gist.gist_access_id = gist_id
104 gist.gist_access_id = gist_id
103 gist.gist_owner = owner.user_id
105 gist.gist_owner = owner.user_id
104 gist.gist_expires = gist_expires
106 gist.gist_expires = gist_expires
105 gist.gist_type = safe_unicode(gist_type)
107 gist.gist_type = safe_unicode(gist_type)
106 self.sa.add(gist)
108 self.sa.add(gist)
107 self.sa.flush()
109 self.sa.flush()
108 if gist_type == Gist.GIST_PUBLIC:
110 if gist_type == Gist.GIST_PUBLIC:
109 # use DB ID for easy to use GIST ID
111 # use DB ID for easy to use GIST ID
110 gist_id = safe_unicode(gist.gist_id)
112 gist_id = safe_unicode(gist.gist_id)
111 gist.gist_access_id = gist_id
113 gist.gist_access_id = gist_id
112 self.sa.add(gist)
114 self.sa.add(gist)
113
115
114 gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
116 gist_repo_path = os.path.join(GIST_STORE_LOC, gist_id)
115 log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path))
117 log.debug('Creating new %s GIST repo in %s' % (gist_type, gist_repo_path))
116 repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg',
118 repo = RepoModel()._create_repo(repo_name=gist_repo_path, alias='hg',
117 parent=None)
119 parent=None)
118
120
119 processed_mapping = {}
121 processed_mapping = {}
120 for filename in gist_mapping:
122 for filename in gist_mapping:
121 content = gist_mapping[filename]['content']
123 content = gist_mapping[filename]['content']
122 #TODO: expand support for setting explicit lexers
124 #TODO: expand support for setting explicit lexers
123 # if lexer is None:
125 # if lexer is None:
124 # try:
126 # try:
125 # lexer = pygments.lexers.guess_lexer_for_filename(filename,content)
127 # lexer = pygments.lexers.guess_lexer_for_filename(filename,content)
126 # except pygments.util.ClassNotFound:
128 # except pygments.util.ClassNotFound:
127 # lexer = 'text'
129 # lexer = 'text'
128 processed_mapping[filename] = {'content': content}
130 processed_mapping[filename] = {'content': content}
129
131
130 # now create single multifile commit
132 # now create single multifile commit
131 message = 'added file'
133 message = 'added file'
132 message += 's: ' if len(processed_mapping) > 1 else ': '
134 message += 's: ' if len(processed_mapping) > 1 else ': '
133 message += ', '.join([x for x in processed_mapping])
135 message += ', '.join([x for x in processed_mapping])
134
136
135 #fake RhodeCode Repository object
137 #fake RhodeCode Repository object
136 fake_repo = AttributeDict(dict(
138 fake_repo = AttributeDict(dict(
137 repo_name=gist_repo_path,
139 repo_name=gist_repo_path,
138 scm_instance_no_cache=lambda: repo,
140 scm_instance_no_cache=lambda: repo,
139 ))
141 ))
140 ScmModel().create_nodes(
142 ScmModel().create_nodes(
141 user=owner.user_id, repo=fake_repo,
143 user=owner.user_id, repo=fake_repo,
142 message=message,
144 message=message,
143 nodes=processed_mapping,
145 nodes=processed_mapping,
144 trigger_push_hook=False
146 trigger_push_hook=False
145 )
147 )
146
148 # store metadata inside the gist, this can be later used for imports
149 # or gist identification
150 metadata = {
151 'gist_db_id': gist.gist_id,
152 'gist_access_id': gist.gist_access_id,
153 'gist_owner_id': owner.user_id,
154 'gist_type': gist.gist_type,
155 'gist_exipres': gist.gist_expires
156 }
157 with open(os.path.join(repo.path, '.hg', GIST_METADATA_FILE), 'wb') as f:
158 f.write(json.dumps(metadata))
147 return gist
159 return gist
148
160
149 def delete(self, gist, fs_remove=True):
161 def delete(self, gist, fs_remove=True):
150 gist = self._get_gist(gist)
162 gist = self._get_gist(gist)
151
163
152 try:
164 try:
153 self.sa.delete(gist)
165 self.sa.delete(gist)
154 if fs_remove:
166 if fs_remove:
155 self.__delete_gist(gist)
167 self.__delete_gist(gist)
156 else:
168 else:
157 log.debug('skipping removal from filesystem')
169 log.debug('skipping removal from filesystem')
158
170
159 except Exception:
171 except Exception:
160 log.error(traceback.format_exc())
172 log.error(traceback.format_exc())
161 raise
173 raise
General Comments 0
You need to be logged in to leave comments. Login now