##// END OF EJS Templates
simplified boolean expressions
marcink -
r3888:7aa0ff5b beta
parent child Browse files
Show More
@@ -1,98 +1,98 b''
1 import rhodecode
1 import rhodecode
2 from rhodecode.lib.utils import BasePasterCommand, Command, load_rcextensions
2 from rhodecode.lib.utils import BasePasterCommand, Command, load_rcextensions
3 from celery.app import app_or_default
3 from celery.app import app_or_default
4 from celery.bin import camqadm, celerybeat, celeryd, celeryev
4 from celery.bin import camqadm, celerybeat, celeryd, celeryev
5
5
6 from rhodecode.lib.utils2 import str2bool
6 from rhodecode.lib.utils2 import str2bool
7
7
8 __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
8 __all__ = ['CeleryDaemonCommand', 'CeleryBeatCommand',
9 'CAMQPAdminCommand', 'CeleryEventCommand']
9 'CAMQPAdminCommand', 'CeleryEventCommand']
10
10
11
11
12 class CeleryCommand(BasePasterCommand):
12 class CeleryCommand(BasePasterCommand):
13 """Abstract class implements run methods needed for celery
13 """Abstract class implements run methods needed for celery
14
14
15 Starts the celery worker that uses a paste.deploy configuration
15 Starts the celery worker that uses a paste.deploy configuration
16 file.
16 file.
17 """
17 """
18
18
19 def update_parser(self):
19 def update_parser(self):
20 """
20 """
21 Abstract method. Allows for the class's parser to be updated
21 Abstract method. Allows for the class's parser to be updated
22 before the superclass's `run` method is called. Necessary to
22 before the superclass's `run` method is called. Necessary to
23 allow options/arguments to be passed through to the underlying
23 allow options/arguments to be passed through to the underlying
24 celery command.
24 celery command.
25 """
25 """
26
26
27 cmd = self.celery_command(app_or_default())
27 cmd = self.celery_command(app_or_default())
28 for x in cmd.get_options():
28 for x in cmd.get_options():
29 self.parser.add_option(x)
29 self.parser.add_option(x)
30
30
31 def command(self):
31 def command(self):
32 from pylons import config
32 from pylons import config
33 try:
33 try:
34 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
34 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
35 except KeyError:
35 except KeyError:
36 CELERY_ON = False
36 CELERY_ON = False
37
37
38 if CELERY_ON == False:
38 if not CELERY_ON:
39 raise Exception('Please enable celery_on in .ini config '
39 raise Exception('Please enable celery_on in .ini config '
40 'file before running celeryd')
40 'file before running celeryd')
41 rhodecode.CELERY_ON = CELERY_ON
41 rhodecode.CELERY_ON = CELERY_ON
42 load_rcextensions(config['here'])
42 load_rcextensions(config['here'])
43 cmd = self.celery_command(app_or_default())
43 cmd = self.celery_command(app_or_default())
44 return cmd.run(**vars(self.options))
44 return cmd.run(**vars(self.options))
45
45
46
46
47 class CeleryDaemonCommand(CeleryCommand):
47 class CeleryDaemonCommand(CeleryCommand):
48 """Start the celery worker
48 """Start the celery worker
49
49
50 Starts the celery worker that uses a paste.deploy configuration
50 Starts the celery worker that uses a paste.deploy configuration
51 file.
51 file.
52 """
52 """
53 usage = 'CONFIG_FILE [celeryd options...]'
53 usage = 'CONFIG_FILE [celeryd options...]'
54 summary = __doc__.splitlines()[0]
54 summary = __doc__.splitlines()[0]
55 description = "".join(__doc__.splitlines()[2:])
55 description = "".join(__doc__.splitlines()[2:])
56
56
57 parser = Command.standard_parser(quiet=True)
57 parser = Command.standard_parser(quiet=True)
58 celery_command = celeryd.WorkerCommand
58 celery_command = celeryd.WorkerCommand
59
59
60
60
61 class CeleryBeatCommand(CeleryCommand):
61 class CeleryBeatCommand(CeleryCommand):
62 """Start the celery beat server
62 """Start the celery beat server
63
63
64 Starts the celery beat server using a paste.deploy configuration
64 Starts the celery beat server using a paste.deploy configuration
65 file.
65 file.
66 """
66 """
67 usage = 'CONFIG_FILE [celerybeat options...]'
67 usage = 'CONFIG_FILE [celerybeat options...]'
68 summary = __doc__.splitlines()[0]
68 summary = __doc__.splitlines()[0]
69 description = "".join(__doc__.splitlines()[2:])
69 description = "".join(__doc__.splitlines()[2:])
70
70
71 parser = Command.standard_parser(quiet=True)
71 parser = Command.standard_parser(quiet=True)
72 celery_command = celerybeat.BeatCommand
72 celery_command = celerybeat.BeatCommand
73
73
74
74
75 class CAMQPAdminCommand(CeleryCommand):
75 class CAMQPAdminCommand(CeleryCommand):
76 """CAMQP Admin
76 """CAMQP Admin
77
77
78 CAMQP celery admin tool.
78 CAMQP celery admin tool.
79 """
79 """
80 usage = 'CONFIG_FILE [camqadm options...]'
80 usage = 'CONFIG_FILE [camqadm options...]'
81 summary = __doc__.splitlines()[0]
81 summary = __doc__.splitlines()[0]
82 description = "".join(__doc__.splitlines()[2:])
82 description = "".join(__doc__.splitlines()[2:])
83
83
84 parser = Command.standard_parser(quiet=True)
84 parser = Command.standard_parser(quiet=True)
85 celery_command = camqadm.AMQPAdminCommand
85 celery_command = camqadm.AMQPAdminCommand
86
86
87
87
88 class CeleryEventCommand(CeleryCommand):
88 class CeleryEventCommand(CeleryCommand):
89 """Celery event command.
89 """Celery event command.
90
90
91 Capture celery events.
91 Capture celery events.
92 """
92 """
93 usage = 'CONFIG_FILE [celeryev options...]'
93 usage = 'CONFIG_FILE [celeryev options...]'
94 summary = __doc__.splitlines()[0]
94 summary = __doc__.splitlines()[0]
95 description = "".join(__doc__.splitlines()[2:])
95 description = "".join(__doc__.splitlines()[2:])
96
96
97 parser = Command.standard_parser(quiet=True)
97 parser = Command.standard_parser(quiet=True)
98 celery_command = celeryev.EvCommand
98 celery_command = celeryev.EvCommand
@@ -1,238 +1,238 b''
1 #!/usr/bin/env python
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
2 # -*- coding: utf-8 -*-
3
3
4 import os
4 import os
5 import re
5 import re
6 import shutil
6 import shutil
7 import logging
7 import logging
8
8
9 from rhodecode.lib.dbmigrate.migrate import exceptions
9 from rhodecode.lib.dbmigrate.migrate import exceptions
10 from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
10 from rhodecode.lib.dbmigrate.migrate.versioning import pathed, script
11 from datetime import datetime
11 from datetime import datetime
12
12
13
13
14 log = logging.getLogger(__name__)
14 log = logging.getLogger(__name__)
15
15
16 class VerNum(object):
16 class VerNum(object):
17 """A version number that behaves like a string and int at the same time"""
17 """A version number that behaves like a string and int at the same time"""
18
18
19 _instances = dict()
19 _instances = dict()
20
20
21 def __new__(cls, value):
21 def __new__(cls, value):
22 val = str(value)
22 val = str(value)
23 if val not in cls._instances:
23 if val not in cls._instances:
24 cls._instances[val] = super(VerNum, cls).__new__(cls)
24 cls._instances[val] = super(VerNum, cls).__new__(cls)
25 ret = cls._instances[val]
25 ret = cls._instances[val]
26 return ret
26 return ret
27
27
28 def __init__(self,value):
28 def __init__(self,value):
29 self.value = str(int(value))
29 self.value = str(int(value))
30 if self < 0:
30 if self < 0:
31 raise ValueError("Version number cannot be negative")
31 raise ValueError("Version number cannot be negative")
32
32
33 def __add__(self, value):
33 def __add__(self, value):
34 ret = int(self) + int(value)
34 ret = int(self) + int(value)
35 return VerNum(ret)
35 return VerNum(ret)
36
36
37 def __sub__(self, value):
37 def __sub__(self, value):
38 return self + (int(value) * -1)
38 return self + (int(value) * -1)
39
39
40 def __cmp__(self, value):
40 def __cmp__(self, value):
41 return int(self) - int(value)
41 return int(self) - int(value)
42
42
43 def __repr__(self):
43 def __repr__(self):
44 return "<VerNum(%s)>" % self.value
44 return "<VerNum(%s)>" % self.value
45
45
46 def __str__(self):
46 def __str__(self):
47 return str(self.value)
47 return str(self.value)
48
48
49 def __int__(self):
49 def __int__(self):
50 return int(self.value)
50 return int(self.value)
51
51
52
52
53 class Collection(pathed.Pathed):
53 class Collection(pathed.Pathed):
54 """A collection of versioning scripts in a repository"""
54 """A collection of versioning scripts in a repository"""
55
55
56 FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
56 FILENAME_WITH_VERSION = re.compile(r'^(\d{3,}).*')
57
57
58 def __init__(self, path):
58 def __init__(self, path):
59 """Collect current version scripts in repository
59 """Collect current version scripts in repository
60 and store them in self.versions
60 and store them in self.versions
61 """
61 """
62 super(Collection, self).__init__(path)
62 super(Collection, self).__init__(path)
63
63
64 # Create temporary list of files, allowing skipped version numbers.
64 # Create temporary list of files, allowing skipped version numbers.
65 files = os.listdir(path)
65 files = os.listdir(path)
66 if '1' in files:
66 if '1' in files:
67 # deprecation
67 # deprecation
68 raise Exception('It looks like you have a repository in the old '
68 raise Exception('It looks like you have a repository in the old '
69 'format (with directories for each version). '
69 'format (with directories for each version). '
70 'Please convert repository before proceeding.')
70 'Please convert repository before proceeding.')
71
71
72 tempVersions = dict()
72 tempVersions = dict()
73 for filename in files:
73 for filename in files:
74 match = self.FILENAME_WITH_VERSION.match(filename)
74 match = self.FILENAME_WITH_VERSION.match(filename)
75 if match:
75 if match:
76 num = int(match.group(1))
76 num = int(match.group(1))
77 tempVersions.setdefault(num, []).append(filename)
77 tempVersions.setdefault(num, []).append(filename)
78 else:
78 else:
79 pass # Must be a helper file or something, let's ignore it.
79 pass # Must be a helper file or something, let's ignore it.
80
80
81 # Create the versions member where the keys
81 # Create the versions member where the keys
82 # are VerNum's and the values are Version's.
82 # are VerNum's and the values are Version's.
83 self.versions = dict()
83 self.versions = dict()
84 for num, files in tempVersions.items():
84 for num, files in tempVersions.items():
85 self.versions[VerNum(num)] = Version(num, path, files)
85 self.versions[VerNum(num)] = Version(num, path, files)
86
86
87 @property
87 @property
88 def latest(self):
88 def latest(self):
89 """:returns: Latest version in Collection"""
89 """:returns: Latest version in Collection"""
90 return max([VerNum(0)] + self.versions.keys())
90 return max([VerNum(0)] + self.versions.keys())
91
91
92 def _next_ver_num(self, use_timestamp_numbering):
92 def _next_ver_num(self, use_timestamp_numbering):
93 if use_timestamp_numbering == True:
93 if use_timestamp_numbering:
94 return VerNum(int(datetime.utcnow().strftime('%Y%m%d%H%M%S')))
94 return VerNum(int(datetime.utcnow().strftime('%Y%m%d%H%M%S')))
95 else:
95 else:
96 return self.latest + 1
96 return self.latest + 1
97
97
98 def create_new_python_version(self, description, **k):
98 def create_new_python_version(self, description, **k):
99 """Create Python files for new version"""
99 """Create Python files for new version"""
100 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
100 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
101 extra = str_to_filename(description)
101 extra = str_to_filename(description)
102
102
103 if extra:
103 if extra:
104 if extra == '_':
104 if extra == '_':
105 extra = ''
105 extra = ''
106 elif not extra.startswith('_'):
106 elif not extra.startswith('_'):
107 extra = '_%s' % extra
107 extra = '_%s' % extra
108
108
109 filename = '%03d%s.py' % (ver, extra)
109 filename = '%03d%s.py' % (ver, extra)
110 filepath = self._version_path(filename)
110 filepath = self._version_path(filename)
111
111
112 script.PythonScript.create(filepath, **k)
112 script.PythonScript.create(filepath, **k)
113 self.versions[ver] = Version(ver, self.path, [filename])
113 self.versions[ver] = Version(ver, self.path, [filename])
114
114
115 def create_new_sql_version(self, database, description, **k):
115 def create_new_sql_version(self, database, description, **k):
116 """Create SQL files for new version"""
116 """Create SQL files for new version"""
117 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
117 ver = self._next_ver_num(k.pop('use_timestamp_numbering', False))
118 self.versions[ver] = Version(ver, self.path, [])
118 self.versions[ver] = Version(ver, self.path, [])
119
119
120 extra = str_to_filename(description)
120 extra = str_to_filename(description)
121
121
122 if extra:
122 if extra:
123 if extra == '_':
123 if extra == '_':
124 extra = ''
124 extra = ''
125 elif not extra.startswith('_'):
125 elif not extra.startswith('_'):
126 extra = '_%s' % extra
126 extra = '_%s' % extra
127
127
128 # Create new files.
128 # Create new files.
129 for op in ('upgrade', 'downgrade'):
129 for op in ('upgrade', 'downgrade'):
130 filename = '%03d%s_%s_%s.sql' % (ver, extra, database, op)
130 filename = '%03d%s_%s_%s.sql' % (ver, extra, database, op)
131 filepath = self._version_path(filename)
131 filepath = self._version_path(filename)
132 script.SqlScript.create(filepath, **k)
132 script.SqlScript.create(filepath, **k)
133 self.versions[ver].add_script(filepath)
133 self.versions[ver].add_script(filepath)
134
134
135 def version(self, vernum=None):
135 def version(self, vernum=None):
136 """Returns latest Version if vernum is not given.
136 """Returns latest Version if vernum is not given.
137 Otherwise, returns wanted version"""
137 Otherwise, returns wanted version"""
138 if vernum is None:
138 if vernum is None:
139 vernum = self.latest
139 vernum = self.latest
140 return self.versions[VerNum(vernum)]
140 return self.versions[VerNum(vernum)]
141
141
142 @classmethod
142 @classmethod
143 def clear(cls):
143 def clear(cls):
144 super(Collection, cls).clear()
144 super(Collection, cls).clear()
145
145
146 def _version_path(self, ver):
146 def _version_path(self, ver):
147 """Returns path of file in versions repository"""
147 """Returns path of file in versions repository"""
148 return os.path.join(self.path, str(ver))
148 return os.path.join(self.path, str(ver))
149
149
150
150
151 class Version(object):
151 class Version(object):
152 """A single version in a collection
152 """A single version in a collection
153 :param vernum: Version Number
153 :param vernum: Version Number
154 :param path: Path to script files
154 :param path: Path to script files
155 :param filelist: List of scripts
155 :param filelist: List of scripts
156 :type vernum: int, VerNum
156 :type vernum: int, VerNum
157 :type path: string
157 :type path: string
158 :type filelist: list
158 :type filelist: list
159 """
159 """
160
160
161 def __init__(self, vernum, path, filelist):
161 def __init__(self, vernum, path, filelist):
162 self.version = VerNum(vernum)
162 self.version = VerNum(vernum)
163
163
164 # Collect scripts in this folder
164 # Collect scripts in this folder
165 self.sql = dict()
165 self.sql = dict()
166 self.python = None
166 self.python = None
167
167
168 for script in filelist:
168 for script in filelist:
169 self.add_script(os.path.join(path, script))
169 self.add_script(os.path.join(path, script))
170
170
171 def script(self, database=None, operation=None):
171 def script(self, database=None, operation=None):
172 """Returns SQL or Python Script"""
172 """Returns SQL or Python Script"""
173 for db in (database, 'default'):
173 for db in (database, 'default'):
174 # Try to return a .sql script first
174 # Try to return a .sql script first
175 try:
175 try:
176 return self.sql[db][operation]
176 return self.sql[db][operation]
177 except KeyError:
177 except KeyError:
178 continue # No .sql script exists
178 continue # No .sql script exists
179
179
180 # TODO: maybe add force Python parameter?
180 # TODO: maybe add force Python parameter?
181 ret = self.python
181 ret = self.python
182
182
183 assert ret is not None, \
183 assert ret is not None, \
184 "There is no script for %d version" % self.version
184 "There is no script for %d version" % self.version
185 return ret
185 return ret
186
186
187 def add_script(self, path):
187 def add_script(self, path):
188 """Add script to Collection/Version"""
188 """Add script to Collection/Version"""
189 if path.endswith(Extensions.py):
189 if path.endswith(Extensions.py):
190 self._add_script_py(path)
190 self._add_script_py(path)
191 elif path.endswith(Extensions.sql):
191 elif path.endswith(Extensions.sql):
192 self._add_script_sql(path)
192 self._add_script_sql(path)
193
193
194 SQL_FILENAME = re.compile(r'^.*\.sql')
194 SQL_FILENAME = re.compile(r'^.*\.sql')
195
195
196 def _add_script_sql(self, path):
196 def _add_script_sql(self, path):
197 basename = os.path.basename(path)
197 basename = os.path.basename(path)
198 match = self.SQL_FILENAME.match(basename)
198 match = self.SQL_FILENAME.match(basename)
199
199
200 if match:
200 if match:
201 basename = basename.replace('.sql', '')
201 basename = basename.replace('.sql', '')
202 parts = basename.split('_')
202 parts = basename.split('_')
203 if len(parts) < 3:
203 if len(parts) < 3:
204 raise exceptions.ScriptError(
204 raise exceptions.ScriptError(
205 "Invalid SQL script name %s " % basename + \
205 "Invalid SQL script name %s " % basename + \
206 "(needs to be ###_description_database_operation.sql)")
206 "(needs to be ###_description_database_operation.sql)")
207 version = parts[0]
207 version = parts[0]
208 op = parts[-1]
208 op = parts[-1]
209 dbms = parts[-2]
209 dbms = parts[-2]
210 else:
210 else:
211 raise exceptions.ScriptError(
211 raise exceptions.ScriptError(
212 "Invalid SQL script name %s " % basename + \
212 "Invalid SQL script name %s " % basename + \
213 "(needs to be ###_description_database_operation.sql)")
213 "(needs to be ###_description_database_operation.sql)")
214
214
215 # File the script into a dictionary
215 # File the script into a dictionary
216 self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
216 self.sql.setdefault(dbms, {})[op] = script.SqlScript(path)
217
217
218 def _add_script_py(self, path):
218 def _add_script_py(self, path):
219 if self.python is not None:
219 if self.python is not None:
220 raise exceptions.ScriptError('You can only have one Python script '
220 raise exceptions.ScriptError('You can only have one Python script '
221 'per version, but you have: %s and %s' % (self.python, path))
221 'per version, but you have: %s and %s' % (self.python, path))
222 self.python = script.PythonScript(path)
222 self.python = script.PythonScript(path)
223
223
224
224
225 class Extensions:
225 class Extensions:
226 """A namespace for file extensions"""
226 """A namespace for file extensions"""
227 py = 'py'
227 py = 'py'
228 sql = 'sql'
228 sql = 'sql'
229
229
230 def str_to_filename(s):
230 def str_to_filename(s):
231 """Replaces spaces, (double and single) quotes
231 """Replaces spaces, (double and single) quotes
232 and double underscores to underscores
232 and double underscores to underscores
233 """
233 """
234
234
235 s = s.replace(' ', '_').replace('"', '_').replace("'", '_').replace(".", "_")
235 s = s.replace(' ', '_').replace('"', '_').replace("'", '_').replace(".", "_")
236 while '__' in s:
236 while '__' in s:
237 s = s.replace('__', '_')
237 s = s.replace('__', '_')
238 return s
238 return s
@@ -1,816 +1,816 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.lib.utils
3 rhodecode.lib.utils
4 ~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~
5
5
6 Utilities library for RhodeCode
6 Utilities library for RhodeCode
7
7
8 :created_on: Apr 18, 2010
8 :created_on: Apr 18, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 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
26 import os
26 import os
27 import re
27 import re
28 import logging
28 import logging
29 import datetime
29 import datetime
30 import traceback
30 import traceback
31 import paste
31 import paste
32 import beaker
32 import beaker
33 import tarfile
33 import tarfile
34 import shutil
34 import shutil
35 import decorator
35 import decorator
36 import warnings
36 import warnings
37 from os.path import abspath
37 from os.path import abspath
38 from os.path import dirname as dn, join as jn
38 from os.path import dirname as dn, join as jn
39
39
40 from paste.script.command import Command, BadCommand
40 from paste.script.command import Command, BadCommand
41
41
42 from mercurial import ui, config
42 from mercurial import ui, config
43
43
44 from webhelpers.text import collapse, remove_formatting, strip_tags
44 from webhelpers.text import collapse, remove_formatting, strip_tags
45
45
46 from rhodecode.lib.vcs import get_backend
46 from rhodecode.lib.vcs import get_backend
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
47 from rhodecode.lib.vcs.backends.base import BaseChangeset
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
48 from rhodecode.lib.vcs.utils.lazy import LazyProperty
49 from rhodecode.lib.vcs.utils.helpers import get_scm
49 from rhodecode.lib.vcs.utils.helpers import get_scm
50 from rhodecode.lib.vcs.exceptions import VCSError
50 from rhodecode.lib.vcs.exceptions import VCSError
51
51
52 from rhodecode.lib.caching_query import FromCache
52 from rhodecode.lib.caching_query import FromCache
53
53
54 from rhodecode.model import meta
54 from rhodecode.model import meta
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
55 from rhodecode.model.db import Repository, User, RhodeCodeUi, \
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
56 UserLog, RepoGroup, RhodeCodeSetting, CacheInvalidation, UserGroup
57 from rhodecode.model.meta import Session
57 from rhodecode.model.meta import Session
58 from rhodecode.model.repos_group import ReposGroupModel
58 from rhodecode.model.repos_group import ReposGroupModel
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
59 from rhodecode.lib.utils2 import safe_str, safe_unicode
60 from rhodecode.lib.vcs.utils.fakemod import create_module
60 from rhodecode.lib.vcs.utils.fakemod import create_module
61 from rhodecode.model.users_group import UserGroupModel
61 from rhodecode.model.users_group import UserGroupModel
62
62
63 log = logging.getLogger(__name__)
63 log = logging.getLogger(__name__)
64
64
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
65 REMOVED_REPO_PAT = re.compile(r'rm__\d{8}_\d{6}_\d{6}__.*')
66
66
67
67
68 def recursive_replace(str_, replace=' '):
68 def recursive_replace(str_, replace=' '):
69 """
69 """
70 Recursive replace of given sign to just one instance
70 Recursive replace of given sign to just one instance
71
71
72 :param str_: given string
72 :param str_: given string
73 :param replace: char to find and replace multiple instances
73 :param replace: char to find and replace multiple instances
74
74
75 Examples::
75 Examples::
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
76 >>> recursive_replace("Mighty---Mighty-Bo--sstones",'-')
77 'Mighty-Mighty-Bo-sstones'
77 'Mighty-Mighty-Bo-sstones'
78 """
78 """
79
79
80 if str_.find(replace * 2) == -1:
80 if str_.find(replace * 2) == -1:
81 return str_
81 return str_
82 else:
82 else:
83 str_ = str_.replace(replace * 2, replace)
83 str_ = str_.replace(replace * 2, replace)
84 return recursive_replace(str_, replace)
84 return recursive_replace(str_, replace)
85
85
86
86
87 def repo_name_slug(value):
87 def repo_name_slug(value):
88 """
88 """
89 Return slug of name of repository
89 Return slug of name of repository
90 This function is called on each creation/modification
90 This function is called on each creation/modification
91 of repository to prevent bad names in repo
91 of repository to prevent bad names in repo
92 """
92 """
93
93
94 slug = remove_formatting(value)
94 slug = remove_formatting(value)
95 slug = strip_tags(slug)
95 slug = strip_tags(slug)
96
96
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
97 for c in """`?=[]\;'"<>,/~!@#$%^&*()+{}|: """:
98 slug = slug.replace(c, '-')
98 slug = slug.replace(c, '-')
99 slug = recursive_replace(slug, '-')
99 slug = recursive_replace(slug, '-')
100 slug = collapse(slug, '-')
100 slug = collapse(slug, '-')
101 return slug
101 return slug
102
102
103
103
104 #==============================================================================
104 #==============================================================================
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
105 # PERM DECORATOR HELPERS FOR EXTRACTING NAMES FOR PERM CHECKS
106 #==============================================================================
106 #==============================================================================
107 def get_repo_slug(request):
107 def get_repo_slug(request):
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
108 _repo = request.environ['pylons.routes_dict'].get('repo_name')
109 if _repo:
109 if _repo:
110 _repo = _repo.rstrip('/')
110 _repo = _repo.rstrip('/')
111 return _repo
111 return _repo
112
112
113
113
114 def get_repos_group_slug(request):
114 def get_repos_group_slug(request):
115 _group = request.environ['pylons.routes_dict'].get('group_name')
115 _group = request.environ['pylons.routes_dict'].get('group_name')
116 if _group:
116 if _group:
117 _group = _group.rstrip('/')
117 _group = _group.rstrip('/')
118 return _group
118 return _group
119
119
120
120
121 def get_user_group_slug(request):
121 def get_user_group_slug(request):
122 _group = request.environ['pylons.routes_dict'].get('id')
122 _group = request.environ['pylons.routes_dict'].get('id')
123 try:
123 try:
124 _group = UserGroup.get(_group)
124 _group = UserGroup.get(_group)
125 if _group:
125 if _group:
126 _group = _group.users_group_name
126 _group = _group.users_group_name
127 except Exception:
127 except Exception:
128 log.debug(traceback.format_exc())
128 log.debug(traceback.format_exc())
129 #catch all failures here
129 #catch all failures here
130 pass
130 pass
131
131
132 return _group
132 return _group
133
133
134
134
135 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
135 def action_logger(user, action, repo, ipaddr='', sa=None, commit=False):
136 """
136 """
137 Action logger for various actions made by users
137 Action logger for various actions made by users
138
138
139 :param user: user that made this action, can be a unique username string or
139 :param user: user that made this action, can be a unique username string or
140 object containing user_id attribute
140 object containing user_id attribute
141 :param action: action to log, should be on of predefined unique actions for
141 :param action: action to log, should be on of predefined unique actions for
142 easy translations
142 easy translations
143 :param repo: string name of repository or object containing repo_id,
143 :param repo: string name of repository or object containing repo_id,
144 that action was made on
144 that action was made on
145 :param ipaddr: optional ip address from what the action was made
145 :param ipaddr: optional ip address from what the action was made
146 :param sa: optional sqlalchemy session
146 :param sa: optional sqlalchemy session
147
147
148 """
148 """
149
149
150 if not sa:
150 if not sa:
151 sa = meta.Session()
151 sa = meta.Session()
152
152
153 try:
153 try:
154 if hasattr(user, 'user_id'):
154 if hasattr(user, 'user_id'):
155 user_obj = User.get(user.user_id)
155 user_obj = User.get(user.user_id)
156 elif isinstance(user, basestring):
156 elif isinstance(user, basestring):
157 user_obj = User.get_by_username(user)
157 user_obj = User.get_by_username(user)
158 else:
158 else:
159 raise Exception('You have to provide a user object or a username')
159 raise Exception('You have to provide a user object or a username')
160
160
161 if hasattr(repo, 'repo_id'):
161 if hasattr(repo, 'repo_id'):
162 repo_obj = Repository.get(repo.repo_id)
162 repo_obj = Repository.get(repo.repo_id)
163 repo_name = repo_obj.repo_name
163 repo_name = repo_obj.repo_name
164 elif isinstance(repo, basestring):
164 elif isinstance(repo, basestring):
165 repo_name = repo.lstrip('/')
165 repo_name = repo.lstrip('/')
166 repo_obj = Repository.get_by_repo_name(repo_name)
166 repo_obj = Repository.get_by_repo_name(repo_name)
167 else:
167 else:
168 repo_obj = None
168 repo_obj = None
169 repo_name = ''
169 repo_name = ''
170
170
171 user_log = UserLog()
171 user_log = UserLog()
172 user_log.user_id = user_obj.user_id
172 user_log.user_id = user_obj.user_id
173 user_log.username = user_obj.username
173 user_log.username = user_obj.username
174 user_log.action = safe_unicode(action)
174 user_log.action = safe_unicode(action)
175
175
176 user_log.repository = repo_obj
176 user_log.repository = repo_obj
177 user_log.repository_name = repo_name
177 user_log.repository_name = repo_name
178
178
179 user_log.action_date = datetime.datetime.now()
179 user_log.action_date = datetime.datetime.now()
180 user_log.user_ip = ipaddr
180 user_log.user_ip = ipaddr
181 sa.add(user_log)
181 sa.add(user_log)
182
182
183 log.info('Logging action:%s on %s by user:%s ip:%s' %
183 log.info('Logging action:%s on %s by user:%s ip:%s' %
184 (action, safe_unicode(repo), user_obj, ipaddr))
184 (action, safe_unicode(repo), user_obj, ipaddr))
185 if commit:
185 if commit:
186 sa.commit()
186 sa.commit()
187 except Exception:
187 except Exception:
188 log.error(traceback.format_exc())
188 log.error(traceback.format_exc())
189 raise
189 raise
190
190
191
191
192 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
192 def get_filesystem_repos(path, recursive=False, skip_removed_repos=True):
193 """
193 """
194 Scans given path for repos and return (name,(type,path)) tuple
194 Scans given path for repos and return (name,(type,path)) tuple
195
195
196 :param path: path to scan for repositories
196 :param path: path to scan for repositories
197 :param recursive: recursive search and return names with subdirs in front
197 :param recursive: recursive search and return names with subdirs in front
198 """
198 """
199
199
200 # remove ending slash for better results
200 # remove ending slash for better results
201 path = path.rstrip(os.sep)
201 path = path.rstrip(os.sep)
202 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
202 log.debug('now scanning in %s location recursive:%s...' % (path, recursive))
203
203
204 def _get_repos(p):
204 def _get_repos(p):
205 if not os.access(p, os.W_OK):
205 if not os.access(p, os.W_OK):
206 log.warn('ignoring repo path without write access: %s', p)
206 log.warn('ignoring repo path without write access: %s', p)
207 return
207 return
208 for dirpath in os.listdir(p):
208 for dirpath in os.listdir(p):
209 if os.path.isfile(os.path.join(p, dirpath)):
209 if os.path.isfile(os.path.join(p, dirpath)):
210 continue
210 continue
211 cur_path = os.path.join(p, dirpath)
211 cur_path = os.path.join(p, dirpath)
212
212
213 # skip removed repos
213 # skip removed repos
214 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
214 if skip_removed_repos and REMOVED_REPO_PAT.match(dirpath):
215 continue
215 continue
216
216
217 #skip .<somethin> dirs
217 #skip .<somethin> dirs
218 if dirpath.startswith('.'):
218 if dirpath.startswith('.'):
219 continue
219 continue
220
220
221 try:
221 try:
222 scm_info = get_scm(cur_path)
222 scm_info = get_scm(cur_path)
223 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
223 yield scm_info[1].split(path, 1)[-1].lstrip(os.sep), scm_info
224 except VCSError:
224 except VCSError:
225 if not recursive:
225 if not recursive:
226 continue
226 continue
227 #check if this dir containts other repos for recursive scan
227 #check if this dir containts other repos for recursive scan
228 rec_path = os.path.join(p, dirpath)
228 rec_path = os.path.join(p, dirpath)
229 if os.path.isdir(rec_path):
229 if os.path.isdir(rec_path):
230 for inner_scm in _get_repos(rec_path):
230 for inner_scm in _get_repos(rec_path):
231 yield inner_scm
231 yield inner_scm
232
232
233 return _get_repos(path)
233 return _get_repos(path)
234
234
235
235
236 def is_valid_repo(repo_name, base_path, scm=None):
236 def is_valid_repo(repo_name, base_path, scm=None):
237 """
237 """
238 Returns True if given path is a valid repository False otherwise.
238 Returns True if given path is a valid repository False otherwise.
239 If scm param is given also compare if given scm is the same as expected
239 If scm param is given also compare if given scm is the same as expected
240 from scm parameter
240 from scm parameter
241
241
242 :param repo_name:
242 :param repo_name:
243 :param base_path:
243 :param base_path:
244 :param scm:
244 :param scm:
245
245
246 :return True: if given path is a valid repository
246 :return True: if given path is a valid repository
247 """
247 """
248 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
248 full_path = os.path.join(safe_str(base_path), safe_str(repo_name))
249
249
250 try:
250 try:
251 scm_ = get_scm(full_path)
251 scm_ = get_scm(full_path)
252 if scm:
252 if scm:
253 return scm_[0] == scm
253 return scm_[0] == scm
254 return True
254 return True
255 except VCSError:
255 except VCSError:
256 return False
256 return False
257
257
258
258
259 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
259 def is_valid_repos_group(repos_group_name, base_path, skip_path_check=False):
260 """
260 """
261 Returns True if given path is a repository group False otherwise
261 Returns True if given path is a repository group False otherwise
262
262
263 :param repo_name:
263 :param repo_name:
264 :param base_path:
264 :param base_path:
265 """
265 """
266 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
266 full_path = os.path.join(safe_str(base_path), safe_str(repos_group_name))
267
267
268 # check if it's not a repo
268 # check if it's not a repo
269 if is_valid_repo(repos_group_name, base_path):
269 if is_valid_repo(repos_group_name, base_path):
270 return False
270 return False
271
271
272 try:
272 try:
273 # we need to check bare git repos at higher level
273 # we need to check bare git repos at higher level
274 # since we might match branches/hooks/info/objects or possible
274 # since we might match branches/hooks/info/objects or possible
275 # other things inside bare git repo
275 # other things inside bare git repo
276 get_scm(os.path.dirname(full_path))
276 get_scm(os.path.dirname(full_path))
277 return False
277 return False
278 except VCSError:
278 except VCSError:
279 pass
279 pass
280
280
281 # check if it's a valid path
281 # check if it's a valid path
282 if skip_path_check or os.path.isdir(full_path):
282 if skip_path_check or os.path.isdir(full_path):
283 return True
283 return True
284
284
285 return False
285 return False
286
286
287
287
288 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
288 def ask_ok(prompt, retries=4, complaint='Yes or no please!'):
289 while True:
289 while True:
290 ok = raw_input(prompt)
290 ok = raw_input(prompt)
291 if ok in ('y', 'ye', 'yes'):
291 if ok in ('y', 'ye', 'yes'):
292 return True
292 return True
293 if ok in ('n', 'no', 'nop', 'nope'):
293 if ok in ('n', 'no', 'nop', 'nope'):
294 return False
294 return False
295 retries = retries - 1
295 retries = retries - 1
296 if retries < 0:
296 if retries < 0:
297 raise IOError
297 raise IOError
298 print complaint
298 print complaint
299
299
300 #propagated from mercurial documentation
300 #propagated from mercurial documentation
301 ui_sections = ['alias', 'auth',
301 ui_sections = ['alias', 'auth',
302 'decode/encode', 'defaults',
302 'decode/encode', 'defaults',
303 'diff', 'email',
303 'diff', 'email',
304 'extensions', 'format',
304 'extensions', 'format',
305 'merge-patterns', 'merge-tools',
305 'merge-patterns', 'merge-tools',
306 'hooks', 'http_proxy',
306 'hooks', 'http_proxy',
307 'smtp', 'patch',
307 'smtp', 'patch',
308 'paths', 'profiling',
308 'paths', 'profiling',
309 'server', 'trusted',
309 'server', 'trusted',
310 'ui', 'web', ]
310 'ui', 'web', ]
311
311
312
312
313 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
313 def make_ui(read_from='file', path=None, checkpaths=True, clear_session=True):
314 """
314 """
315 A function that will read python rc files or database
315 A function that will read python rc files or database
316 and make an mercurial ui object from read options
316 and make an mercurial ui object from read options
317
317
318 :param path: path to mercurial config file
318 :param path: path to mercurial config file
319 :param checkpaths: check the path
319 :param checkpaths: check the path
320 :param read_from: read from 'file' or 'db'
320 :param read_from: read from 'file' or 'db'
321 """
321 """
322
322
323 baseui = ui.ui()
323 baseui = ui.ui()
324
324
325 # clean the baseui object
325 # clean the baseui object
326 baseui._ocfg = config.config()
326 baseui._ocfg = config.config()
327 baseui._ucfg = config.config()
327 baseui._ucfg = config.config()
328 baseui._tcfg = config.config()
328 baseui._tcfg = config.config()
329
329
330 if read_from == 'file':
330 if read_from == 'file':
331 if not os.path.isfile(path):
331 if not os.path.isfile(path):
332 log.debug('hgrc file is not present at %s, skipping...' % path)
332 log.debug('hgrc file is not present at %s, skipping...' % path)
333 return False
333 return False
334 log.debug('reading hgrc from %s' % path)
334 log.debug('reading hgrc from %s' % path)
335 cfg = config.config()
335 cfg = config.config()
336 cfg.read(path)
336 cfg.read(path)
337 for section in ui_sections:
337 for section in ui_sections:
338 for k, v in cfg.items(section):
338 for k, v in cfg.items(section):
339 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
339 log.debug('settings ui from file: [%s] %s=%s' % (section, k, v))
340 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
340 baseui.setconfig(safe_str(section), safe_str(k), safe_str(v))
341
341
342 elif read_from == 'db':
342 elif read_from == 'db':
343 sa = meta.Session()
343 sa = meta.Session()
344 ret = sa.query(RhodeCodeUi)\
344 ret = sa.query(RhodeCodeUi)\
345 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
345 .options(FromCache("sql_cache_short", "get_hg_ui_settings"))\
346 .all()
346 .all()
347
347
348 hg_ui = ret
348 hg_ui = ret
349 for ui_ in hg_ui:
349 for ui_ in hg_ui:
350 if ui_.ui_active:
350 if ui_.ui_active:
351 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
351 log.debug('settings ui from db: [%s] %s=%s', ui_.ui_section,
352 ui_.ui_key, ui_.ui_value)
352 ui_.ui_key, ui_.ui_value)
353 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
353 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
354 safe_str(ui_.ui_value))
354 safe_str(ui_.ui_value))
355 if ui_.ui_key == 'push_ssl':
355 if ui_.ui_key == 'push_ssl':
356 # force set push_ssl requirement to False, rhodecode
356 # force set push_ssl requirement to False, rhodecode
357 # handles that
357 # handles that
358 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
358 baseui.setconfig(safe_str(ui_.ui_section), safe_str(ui_.ui_key),
359 False)
359 False)
360 if clear_session:
360 if clear_session:
361 meta.Session.remove()
361 meta.Session.remove()
362 return baseui
362 return baseui
363
363
364
364
365 def set_rhodecode_config(config):
365 def set_rhodecode_config(config):
366 """
366 """
367 Updates pylons config with new settings from database
367 Updates pylons config with new settings from database
368
368
369 :param config:
369 :param config:
370 """
370 """
371 hgsettings = RhodeCodeSetting.get_app_settings()
371 hgsettings = RhodeCodeSetting.get_app_settings()
372
372
373 for k, v in hgsettings.items():
373 for k, v in hgsettings.items():
374 config[k] = v
374 config[k] = v
375
375
376
376
377 def set_vcs_config(config):
377 def set_vcs_config(config):
378 """
378 """
379 Patch VCS config with some RhodeCode specific stuff
379 Patch VCS config with some RhodeCode specific stuff
380
380
381 :param config: rhodecode.CONFIG
381 :param config: rhodecode.CONFIG
382 """
382 """
383 import rhodecode
383 import rhodecode
384 from rhodecode.lib.vcs import conf
384 from rhodecode.lib.vcs import conf
385 from rhodecode.lib.utils2 import aslist
385 from rhodecode.lib.utils2 import aslist
386 conf.settings.BACKENDS = {
386 conf.settings.BACKENDS = {
387 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
387 'hg': 'rhodecode.lib.vcs.backends.hg.MercurialRepository',
388 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
388 'git': 'rhodecode.lib.vcs.backends.git.GitRepository',
389 }
389 }
390
390
391 conf.settings.GIT_EXECUTABLE_PATH = config.get('git_path', 'git')
391 conf.settings.GIT_EXECUTABLE_PATH = config.get('git_path', 'git')
392 conf.settings.GIT_REV_FILTER = config.get('git_rev_filter', '--all').strip()
392 conf.settings.GIT_REV_FILTER = config.get('git_rev_filter', '--all').strip()
393 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
393 conf.settings.DEFAULT_ENCODINGS = aslist(config.get('default_encoding',
394 'utf8'), sep=',')
394 'utf8'), sep=',')
395
395
396
396
397 def map_groups(path):
397 def map_groups(path):
398 """
398 """
399 Given a full path to a repository, create all nested groups that this
399 Given a full path to a repository, create all nested groups that this
400 repo is inside. This function creates parent-child relationships between
400 repo is inside. This function creates parent-child relationships between
401 groups and creates default perms for all new groups.
401 groups and creates default perms for all new groups.
402
402
403 :param paths: full path to repository
403 :param paths: full path to repository
404 """
404 """
405 sa = meta.Session()
405 sa = meta.Session()
406 groups = path.split(Repository.url_sep())
406 groups = path.split(Repository.url_sep())
407 parent = None
407 parent = None
408 group = None
408 group = None
409
409
410 # last element is repo in nested groups structure
410 # last element is repo in nested groups structure
411 groups = groups[:-1]
411 groups = groups[:-1]
412 rgm = ReposGroupModel(sa)
412 rgm = ReposGroupModel(sa)
413 owner = User.get_first_admin()
413 owner = User.get_first_admin()
414 for lvl, group_name in enumerate(groups):
414 for lvl, group_name in enumerate(groups):
415 group_name = '/'.join(groups[:lvl] + [group_name])
415 group_name = '/'.join(groups[:lvl] + [group_name])
416 group = RepoGroup.get_by_group_name(group_name)
416 group = RepoGroup.get_by_group_name(group_name)
417 desc = '%s group' % group_name
417 desc = '%s group' % group_name
418
418
419 # skip folders that are now removed repos
419 # skip folders that are now removed repos
420 if REMOVED_REPO_PAT.match(group_name):
420 if REMOVED_REPO_PAT.match(group_name):
421 break
421 break
422
422
423 if group is None:
423 if group is None:
424 log.debug('creating group level: %s group_name: %s'
424 log.debug('creating group level: %s group_name: %s'
425 % (lvl, group_name))
425 % (lvl, group_name))
426 group = RepoGroup(group_name, parent)
426 group = RepoGroup(group_name, parent)
427 group.group_description = desc
427 group.group_description = desc
428 group.user = owner
428 group.user = owner
429 sa.add(group)
429 sa.add(group)
430 perm_obj = rgm._create_default_perms(group)
430 perm_obj = rgm._create_default_perms(group)
431 sa.add(perm_obj)
431 sa.add(perm_obj)
432 sa.flush()
432 sa.flush()
433
433
434 parent = group
434 parent = group
435 return group
435 return group
436
436
437
437
438 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
438 def repo2db_mapper(initial_repo_list, remove_obsolete=False,
439 install_git_hook=False):
439 install_git_hook=False):
440 """
440 """
441 maps all repos given in initial_repo_list, non existing repositories
441 maps all repos given in initial_repo_list, non existing repositories
442 are created, if remove_obsolete is True it also check for db entries
442 are created, if remove_obsolete is True it also check for db entries
443 that are not in initial_repo_list and removes them.
443 that are not in initial_repo_list and removes them.
444
444
445 :param initial_repo_list: list of repositories found by scanning methods
445 :param initial_repo_list: list of repositories found by scanning methods
446 :param remove_obsolete: check for obsolete entries in database
446 :param remove_obsolete: check for obsolete entries in database
447 :param install_git_hook: if this is True, also check and install githook
447 :param install_git_hook: if this is True, also check and install githook
448 for a repo if missing
448 for a repo if missing
449 """
449 """
450 from rhodecode.model.repo import RepoModel
450 from rhodecode.model.repo import RepoModel
451 from rhodecode.model.scm import ScmModel
451 from rhodecode.model.scm import ScmModel
452 sa = meta.Session()
452 sa = meta.Session()
453 rm = RepoModel()
453 rm = RepoModel()
454 user = User.get_first_admin()
454 user = User.get_first_admin()
455 added = []
455 added = []
456
456
457 ##creation defaults
457 ##creation defaults
458 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
458 defs = RhodeCodeSetting.get_default_repo_settings(strip_prefix=True)
459 enable_statistics = defs.get('repo_enable_statistics')
459 enable_statistics = defs.get('repo_enable_statistics')
460 enable_locking = defs.get('repo_enable_locking')
460 enable_locking = defs.get('repo_enable_locking')
461 enable_downloads = defs.get('repo_enable_downloads')
461 enable_downloads = defs.get('repo_enable_downloads')
462 private = defs.get('repo_private')
462 private = defs.get('repo_private')
463
463
464 for name, repo in initial_repo_list.items():
464 for name, repo in initial_repo_list.items():
465 group = map_groups(name)
465 group = map_groups(name)
466 db_repo = rm.get_by_repo_name(name)
466 db_repo = rm.get_by_repo_name(name)
467 # found repo that is on filesystem not in RhodeCode database
467 # found repo that is on filesystem not in RhodeCode database
468 if not db_repo:
468 if not db_repo:
469 log.info('repository %s not found, creating now' % name)
469 log.info('repository %s not found, creating now' % name)
470 added.append(name)
470 added.append(name)
471 desc = (repo.description
471 desc = (repo.description
472 if repo.description != 'unknown'
472 if repo.description != 'unknown'
473 else '%s repository' % name)
473 else '%s repository' % name)
474
474
475 new_repo = rm.create_repo(
475 new_repo = rm.create_repo(
476 repo_name=name,
476 repo_name=name,
477 repo_type=repo.alias,
477 repo_type=repo.alias,
478 description=desc,
478 description=desc,
479 repos_group=getattr(group, 'group_id', None),
479 repos_group=getattr(group, 'group_id', None),
480 owner=user,
480 owner=user,
481 just_db=True,
481 just_db=True,
482 enable_locking=enable_locking,
482 enable_locking=enable_locking,
483 enable_downloads=enable_downloads,
483 enable_downloads=enable_downloads,
484 enable_statistics=enable_statistics,
484 enable_statistics=enable_statistics,
485 private=private
485 private=private
486 )
486 )
487 # we added that repo just now, and make sure it has githook
487 # we added that repo just now, and make sure it has githook
488 # installed
488 # installed
489 if new_repo.repo_type == 'git':
489 if new_repo.repo_type == 'git':
490 ScmModel().install_git_hook(new_repo.scm_instance)
490 ScmModel().install_git_hook(new_repo.scm_instance)
491 new_repo.update_changeset_cache()
491 new_repo.update_changeset_cache()
492 elif install_git_hook:
492 elif install_git_hook:
493 if db_repo.repo_type == 'git':
493 if db_repo.repo_type == 'git':
494 ScmModel().install_git_hook(db_repo.scm_instance)
494 ScmModel().install_git_hook(db_repo.scm_instance)
495
495
496 sa.commit()
496 sa.commit()
497 removed = []
497 removed = []
498 if remove_obsolete:
498 if remove_obsolete:
499 # remove from database those repositories that are not in the filesystem
499 # remove from database those repositories that are not in the filesystem
500 for repo in sa.query(Repository).all():
500 for repo in sa.query(Repository).all():
501 if repo.repo_name not in initial_repo_list.keys():
501 if repo.repo_name not in initial_repo_list.keys():
502 log.debug("Removing non-existing repository found in db `%s`" %
502 log.debug("Removing non-existing repository found in db `%s`" %
503 repo.repo_name)
503 repo.repo_name)
504 try:
504 try:
505 removed.append(repo.repo_name)
505 removed.append(repo.repo_name)
506 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
506 RepoModel(sa).delete(repo, forks='detach', fs_remove=False)
507 sa.commit()
507 sa.commit()
508 except Exception:
508 except Exception:
509 #don't hold further removals on error
509 #don't hold further removals on error
510 log.error(traceback.format_exc())
510 log.error(traceback.format_exc())
511 sa.rollback()
511 sa.rollback()
512 return added, removed
512 return added, removed
513
513
514
514
515 # set cache regions for beaker so celery can utilise it
515 # set cache regions for beaker so celery can utilise it
516 def add_cache(settings):
516 def add_cache(settings):
517 cache_settings = {'regions': None}
517 cache_settings = {'regions': None}
518 for key in settings.keys():
518 for key in settings.keys():
519 for prefix in ['beaker.cache.', 'cache.']:
519 for prefix in ['beaker.cache.', 'cache.']:
520 if key.startswith(prefix):
520 if key.startswith(prefix):
521 name = key.split(prefix)[1].strip()
521 name = key.split(prefix)[1].strip()
522 cache_settings[name] = settings[key].strip()
522 cache_settings[name] = settings[key].strip()
523 if cache_settings['regions']:
523 if cache_settings['regions']:
524 for region in cache_settings['regions'].split(','):
524 for region in cache_settings['regions'].split(','):
525 region = region.strip()
525 region = region.strip()
526 region_settings = {}
526 region_settings = {}
527 for key, value in cache_settings.items():
527 for key, value in cache_settings.items():
528 if key.startswith(region):
528 if key.startswith(region):
529 region_settings[key.split('.')[1]] = value
529 region_settings[key.split('.')[1]] = value
530 region_settings['expire'] = int(region_settings.get('expire',
530 region_settings['expire'] = int(region_settings.get('expire',
531 60))
531 60))
532 region_settings.setdefault('lock_dir',
532 region_settings.setdefault('lock_dir',
533 cache_settings.get('lock_dir'))
533 cache_settings.get('lock_dir'))
534 region_settings.setdefault('data_dir',
534 region_settings.setdefault('data_dir',
535 cache_settings.get('data_dir'))
535 cache_settings.get('data_dir'))
536
536
537 if 'type' not in region_settings:
537 if 'type' not in region_settings:
538 region_settings['type'] = cache_settings.get('type',
538 region_settings['type'] = cache_settings.get('type',
539 'memory')
539 'memory')
540 beaker.cache.cache_regions[region] = region_settings
540 beaker.cache.cache_regions[region] = region_settings
541
541
542
542
543 def load_rcextensions(root_path):
543 def load_rcextensions(root_path):
544 import rhodecode
544 import rhodecode
545 from rhodecode.config import conf
545 from rhodecode.config import conf
546
546
547 path = os.path.join(root_path, 'rcextensions', '__init__.py')
547 path = os.path.join(root_path, 'rcextensions', '__init__.py')
548 if os.path.isfile(path):
548 if os.path.isfile(path):
549 rcext = create_module('rc', path)
549 rcext = create_module('rc', path)
550 EXT = rhodecode.EXTENSIONS = rcext
550 EXT = rhodecode.EXTENSIONS = rcext
551 log.debug('Found rcextensions now loading %s...' % rcext)
551 log.debug('Found rcextensions now loading %s...' % rcext)
552
552
553 # Additional mappings that are not present in the pygments lexers
553 # Additional mappings that are not present in the pygments lexers
554 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
554 conf.LANGUAGES_EXTENSIONS_MAP.update(getattr(EXT, 'EXTRA_MAPPINGS', {}))
555
555
556 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
556 #OVERRIDE OUR EXTENSIONS FROM RC-EXTENSIONS (if present)
557
557
558 if getattr(EXT, 'INDEX_EXTENSIONS', []) != []:
558 if getattr(EXT, 'INDEX_EXTENSIONS', []):
559 log.debug('settings custom INDEX_EXTENSIONS')
559 log.debug('settings custom INDEX_EXTENSIONS')
560 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
560 conf.INDEX_EXTENSIONS = getattr(EXT, 'INDEX_EXTENSIONS', [])
561
561
562 #ADDITIONAL MAPPINGS
562 #ADDITIONAL MAPPINGS
563 log.debug('adding extra into INDEX_EXTENSIONS')
563 log.debug('adding extra into INDEX_EXTENSIONS')
564 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
564 conf.INDEX_EXTENSIONS.extend(getattr(EXT, 'EXTRA_INDEX_EXTENSIONS', []))
565
565
566 # auto check if the module is not missing any data, set to default if is
566 # auto check if the module is not missing any data, set to default if is
567 # this will help autoupdate new feature of rcext module
567 # this will help autoupdate new feature of rcext module
568 from rhodecode.config import rcextensions
568 from rhodecode.config import rcextensions
569 for k in dir(rcextensions):
569 for k in dir(rcextensions):
570 if not k.startswith('_') and not hasattr(EXT, k):
570 if not k.startswith('_') and not hasattr(EXT, k):
571 setattr(EXT, k, getattr(rcextensions, k))
571 setattr(EXT, k, getattr(rcextensions, k))
572
572
573
573
574 def get_custom_lexer(extension):
574 def get_custom_lexer(extension):
575 """
575 """
576 returns a custom lexer if it's defined in rcextensions module, or None
576 returns a custom lexer if it's defined in rcextensions module, or None
577 if there's no custom lexer defined
577 if there's no custom lexer defined
578 """
578 """
579 import rhodecode
579 import rhodecode
580 from pygments import lexers
580 from pygments import lexers
581 #check if we didn't define this extension as other lexer
581 #check if we didn't define this extension as other lexer
582 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
582 if rhodecode.EXTENSIONS and extension in rhodecode.EXTENSIONS.EXTRA_LEXERS:
583 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
583 _lexer_name = rhodecode.EXTENSIONS.EXTRA_LEXERS[extension]
584 return lexers.get_lexer_by_name(_lexer_name)
584 return lexers.get_lexer_by_name(_lexer_name)
585
585
586
586
587 #==============================================================================
587 #==============================================================================
588 # TEST FUNCTIONS AND CREATORS
588 # TEST FUNCTIONS AND CREATORS
589 #==============================================================================
589 #==============================================================================
590 def create_test_index(repo_location, config, full_index):
590 def create_test_index(repo_location, config, full_index):
591 """
591 """
592 Makes default test index
592 Makes default test index
593
593
594 :param config: test config
594 :param config: test config
595 :param full_index:
595 :param full_index:
596 """
596 """
597
597
598 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
598 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
599 from rhodecode.lib.pidlock import DaemonLock, LockHeld
599 from rhodecode.lib.pidlock import DaemonLock, LockHeld
600
600
601 repo_location = repo_location
601 repo_location = repo_location
602
602
603 index_location = os.path.join(config['app_conf']['index_dir'])
603 index_location = os.path.join(config['app_conf']['index_dir'])
604 if not os.path.exists(index_location):
604 if not os.path.exists(index_location):
605 os.makedirs(index_location)
605 os.makedirs(index_location)
606
606
607 try:
607 try:
608 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
608 l = DaemonLock(file_=jn(dn(index_location), 'make_index.lock'))
609 WhooshIndexingDaemon(index_location=index_location,
609 WhooshIndexingDaemon(index_location=index_location,
610 repo_location=repo_location)\
610 repo_location=repo_location)\
611 .run(full_index=full_index)
611 .run(full_index=full_index)
612 l.release()
612 l.release()
613 except LockHeld:
613 except LockHeld:
614 pass
614 pass
615
615
616
616
617 def create_test_env(repos_test_path, config):
617 def create_test_env(repos_test_path, config):
618 """
618 """
619 Makes a fresh database and
619 Makes a fresh database and
620 install test repository into tmp dir
620 install test repository into tmp dir
621 """
621 """
622 from rhodecode.lib.db_manage import DbManage
622 from rhodecode.lib.db_manage import DbManage
623 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
623 from rhodecode.tests import HG_REPO, GIT_REPO, TESTS_TMP_PATH
624
624
625 # PART ONE create db
625 # PART ONE create db
626 dbconf = config['sqlalchemy.db1.url']
626 dbconf = config['sqlalchemy.db1.url']
627 log.debug('making test db %s' % dbconf)
627 log.debug('making test db %s' % dbconf)
628
628
629 # create test dir if it doesn't exist
629 # create test dir if it doesn't exist
630 if not os.path.isdir(repos_test_path):
630 if not os.path.isdir(repos_test_path):
631 log.debug('Creating testdir %s' % repos_test_path)
631 log.debug('Creating testdir %s' % repos_test_path)
632 os.makedirs(repos_test_path)
632 os.makedirs(repos_test_path)
633
633
634 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
634 dbmanage = DbManage(log_sql=True, dbconf=dbconf, root=config['here'],
635 tests=True)
635 tests=True)
636 dbmanage.create_tables(override=True)
636 dbmanage.create_tables(override=True)
637 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
637 dbmanage.create_settings(dbmanage.config_prompt(repos_test_path))
638 dbmanage.create_default_user()
638 dbmanage.create_default_user()
639 dbmanage.admin_prompt()
639 dbmanage.admin_prompt()
640 dbmanage.create_permissions()
640 dbmanage.create_permissions()
641 dbmanage.populate_default_permissions()
641 dbmanage.populate_default_permissions()
642 Session().commit()
642 Session().commit()
643 # PART TWO make test repo
643 # PART TWO make test repo
644 log.debug('making test vcs repositories')
644 log.debug('making test vcs repositories')
645
645
646 idx_path = config['app_conf']['index_dir']
646 idx_path = config['app_conf']['index_dir']
647 data_path = config['app_conf']['cache_dir']
647 data_path = config['app_conf']['cache_dir']
648
648
649 #clean index and data
649 #clean index and data
650 if idx_path and os.path.exists(idx_path):
650 if idx_path and os.path.exists(idx_path):
651 log.debug('remove %s' % idx_path)
651 log.debug('remove %s' % idx_path)
652 shutil.rmtree(idx_path)
652 shutil.rmtree(idx_path)
653
653
654 if data_path and os.path.exists(data_path):
654 if data_path and os.path.exists(data_path):
655 log.debug('remove %s' % data_path)
655 log.debug('remove %s' % data_path)
656 shutil.rmtree(data_path)
656 shutil.rmtree(data_path)
657
657
658 #CREATE DEFAULT TEST REPOS
658 #CREATE DEFAULT TEST REPOS
659 cur_dir = dn(dn(abspath(__file__)))
659 cur_dir = dn(dn(abspath(__file__)))
660 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_hg.tar.gz"))
660 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_hg.tar.gz"))
661 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
661 tar.extractall(jn(TESTS_TMP_PATH, HG_REPO))
662 tar.close()
662 tar.close()
663
663
664 cur_dir = dn(dn(abspath(__file__)))
664 cur_dir = dn(dn(abspath(__file__)))
665 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_git.tar.gz"))
665 tar = tarfile.open(jn(cur_dir, 'tests', 'fixtures', "vcs_test_git.tar.gz"))
666 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
666 tar.extractall(jn(TESTS_TMP_PATH, GIT_REPO))
667 tar.close()
667 tar.close()
668
668
669 #LOAD VCS test stuff
669 #LOAD VCS test stuff
670 from rhodecode.tests.vcs import setup_package
670 from rhodecode.tests.vcs import setup_package
671 setup_package()
671 setup_package()
672
672
673
673
674 #==============================================================================
674 #==============================================================================
675 # PASTER COMMANDS
675 # PASTER COMMANDS
676 #==============================================================================
676 #==============================================================================
677 class BasePasterCommand(Command):
677 class BasePasterCommand(Command):
678 """
678 """
679 Abstract Base Class for paster commands.
679 Abstract Base Class for paster commands.
680
680
681 The celery commands are somewhat aggressive about loading
681 The celery commands are somewhat aggressive about loading
682 celery.conf, and since our module sets the `CELERY_LOADER`
682 celery.conf, and since our module sets the `CELERY_LOADER`
683 environment variable to our loader, we have to bootstrap a bit and
683 environment variable to our loader, we have to bootstrap a bit and
684 make sure we've had a chance to load the pylons config off of the
684 make sure we've had a chance to load the pylons config off of the
685 command line, otherwise everything fails.
685 command line, otherwise everything fails.
686 """
686 """
687 min_args = 1
687 min_args = 1
688 min_args_error = "Please provide a paster config file as an argument."
688 min_args_error = "Please provide a paster config file as an argument."
689 takes_config_file = 1
689 takes_config_file = 1
690 requires_config_file = True
690 requires_config_file = True
691
691
692 def notify_msg(self, msg, log=False):
692 def notify_msg(self, msg, log=False):
693 """Make a notification to user, additionally if logger is passed
693 """Make a notification to user, additionally if logger is passed
694 it logs this action using given logger
694 it logs this action using given logger
695
695
696 :param msg: message that will be printed to user
696 :param msg: message that will be printed to user
697 :param log: logging instance, to use to additionally log this message
697 :param log: logging instance, to use to additionally log this message
698
698
699 """
699 """
700 if log and isinstance(log, logging):
700 if log and isinstance(log, logging):
701 log(msg)
701 log(msg)
702
702
703 def run(self, args):
703 def run(self, args):
704 """
704 """
705 Overrides Command.run
705 Overrides Command.run
706
706
707 Checks for a config file argument and loads it.
707 Checks for a config file argument and loads it.
708 """
708 """
709 if len(args) < self.min_args:
709 if len(args) < self.min_args:
710 raise BadCommand(
710 raise BadCommand(
711 self.min_args_error % {'min_args': self.min_args,
711 self.min_args_error % {'min_args': self.min_args,
712 'actual_args': len(args)})
712 'actual_args': len(args)})
713
713
714 # Decrement because we're going to lob off the first argument.
714 # Decrement because we're going to lob off the first argument.
715 # @@ This is hacky
715 # @@ This is hacky
716 self.min_args -= 1
716 self.min_args -= 1
717 self.bootstrap_config(args[0])
717 self.bootstrap_config(args[0])
718 self.update_parser()
718 self.update_parser()
719 return super(BasePasterCommand, self).run(args[1:])
719 return super(BasePasterCommand, self).run(args[1:])
720
720
721 def update_parser(self):
721 def update_parser(self):
722 """
722 """
723 Abstract method. Allows for the class's parser to be updated
723 Abstract method. Allows for the class's parser to be updated
724 before the superclass's `run` method is called. Necessary to
724 before the superclass's `run` method is called. Necessary to
725 allow options/arguments to be passed through to the underlying
725 allow options/arguments to be passed through to the underlying
726 celery command.
726 celery command.
727 """
727 """
728 raise NotImplementedError("Abstract Method.")
728 raise NotImplementedError("Abstract Method.")
729
729
730 def bootstrap_config(self, conf):
730 def bootstrap_config(self, conf):
731 """
731 """
732 Loads the pylons configuration.
732 Loads the pylons configuration.
733 """
733 """
734 from pylons import config as pylonsconfig
734 from pylons import config as pylonsconfig
735
735
736 self.path_to_ini_file = os.path.realpath(conf)
736 self.path_to_ini_file = os.path.realpath(conf)
737 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
737 conf = paste.deploy.appconfig('config:' + self.path_to_ini_file)
738 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
738 pylonsconfig.init_app(conf.global_conf, conf.local_conf)
739
739
740 def _init_session(self):
740 def _init_session(self):
741 """
741 """
742 Inits SqlAlchemy Session
742 Inits SqlAlchemy Session
743 """
743 """
744 logging.config.fileConfig(self.path_to_ini_file)
744 logging.config.fileConfig(self.path_to_ini_file)
745 from pylons import config
745 from pylons import config
746 from rhodecode.model import init_model
746 from rhodecode.model import init_model
747 from rhodecode.lib.utils2 import engine_from_config
747 from rhodecode.lib.utils2 import engine_from_config
748
748
749 #get to remove repos !!
749 #get to remove repos !!
750 add_cache(config)
750 add_cache(config)
751 engine = engine_from_config(config, 'sqlalchemy.db1.')
751 engine = engine_from_config(config, 'sqlalchemy.db1.')
752 init_model(engine)
752 init_model(engine)
753
753
754
754
755 def check_git_version():
755 def check_git_version():
756 """
756 """
757 Checks what version of git is installed in system, and issues a warning
757 Checks what version of git is installed in system, and issues a warning
758 if it's too old for RhodeCode to properly work.
758 if it's too old for RhodeCode to properly work.
759 """
759 """
760 from rhodecode import BACKENDS
760 from rhodecode import BACKENDS
761 from rhodecode.lib.vcs.backends.git.repository import GitRepository
761 from rhodecode.lib.vcs.backends.git.repository import GitRepository
762 from rhodecode.lib.vcs.conf import settings
762 from rhodecode.lib.vcs.conf import settings
763 from distutils.version import StrictVersion
763 from distutils.version import StrictVersion
764
764
765 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
765 stdout, stderr = GitRepository._run_git_command('--version', _bare=True,
766 _safe=True)
766 _safe=True)
767
767
768 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
768 ver = (stdout.split(' ')[-1] or '').strip() or '0.0.0'
769 if len(ver.split('.')) > 3:
769 if len(ver.split('.')) > 3:
770 #StrictVersion needs to be only 3 element type
770 #StrictVersion needs to be only 3 element type
771 ver = '.'.join(ver.split('.')[:3])
771 ver = '.'.join(ver.split('.')[:3])
772 try:
772 try:
773 _ver = StrictVersion(ver)
773 _ver = StrictVersion(ver)
774 except Exception:
774 except Exception:
775 _ver = StrictVersion('0.0.0')
775 _ver = StrictVersion('0.0.0')
776 stderr = traceback.format_exc()
776 stderr = traceback.format_exc()
777
777
778 req_ver = '1.7.4'
778 req_ver = '1.7.4'
779 to_old_git = False
779 to_old_git = False
780 if _ver < StrictVersion(req_ver):
780 if _ver < StrictVersion(req_ver):
781 to_old_git = True
781 to_old_git = True
782
782
783 if 'git' in BACKENDS:
783 if 'git' in BACKENDS:
784 log.debug('GIT executable: "%s" version detected: %s'
784 log.debug('GIT executable: "%s" version detected: %s'
785 % (settings.GIT_EXECUTABLE_PATH, stdout))
785 % (settings.GIT_EXECUTABLE_PATH, stdout))
786 if stderr:
786 if stderr:
787 log.warning('Unable to detect git version, org error was: %r' % stderr)
787 log.warning('Unable to detect git version, org error was: %r' % stderr)
788 elif to_old_git:
788 elif to_old_git:
789 log.warning('RhodeCode detected git version %s, which is too old '
789 log.warning('RhodeCode detected git version %s, which is too old '
790 'for the system to function properly. Make sure '
790 'for the system to function properly. Make sure '
791 'its version is at least %s' % (ver, req_ver))
791 'its version is at least %s' % (ver, req_ver))
792 return _ver
792 return _ver
793
793
794
794
795 @decorator.decorator
795 @decorator.decorator
796 def jsonify(func, *args, **kwargs):
796 def jsonify(func, *args, **kwargs):
797 """Action decorator that formats output for JSON
797 """Action decorator that formats output for JSON
798
798
799 Given a function that will return content, this decorator will turn
799 Given a function that will return content, this decorator will turn
800 the result into JSON, with a content-type of 'application/json' and
800 the result into JSON, with a content-type of 'application/json' and
801 output it.
801 output it.
802
802
803 """
803 """
804 from pylons.decorators.util import get_pylons
804 from pylons.decorators.util import get_pylons
805 from rhodecode.lib.compat import json
805 from rhodecode.lib.compat import json
806 pylons = get_pylons(args)
806 pylons = get_pylons(args)
807 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
807 pylons.response.headers['Content-Type'] = 'application/json; charset=utf-8'
808 data = func(*args, **kwargs)
808 data = func(*args, **kwargs)
809 if isinstance(data, (list, tuple)):
809 if isinstance(data, (list, tuple)):
810 msg = "JSON responses with Array envelopes are susceptible to " \
810 msg = "JSON responses with Array envelopes are susceptible to " \
811 "cross-site data leak attacks, see " \
811 "cross-site data leak attacks, see " \
812 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
812 "http://wiki.pylonshq.com/display/pylonsfaq/Warnings"
813 warnings.warn(msg, Warning, 2)
813 warnings.warn(msg, Warning, 2)
814 log.warning(msg)
814 log.warning(msg)
815 log.debug("Returning JSON wrapped action output")
815 log.debug("Returning JSON wrapped action output")
816 return json.dumps(data, encoding='utf-8')
816 return json.dumps(data, encoding='utf-8')
@@ -1,163 +1,163 b''
1 # -*- coding: utf-8 -*-
1 # -*- coding: utf-8 -*-
2 """
2 """
3 rhodecode.model.permission
3 rhodecode.model.permission
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
4 ~~~~~~~~~~~~~~~~~~~~~~~~~~
5
5
6 permissions model for RhodeCode
6 permissions model for RhodeCode
7
7
8 :created_on: Aug 20, 2010
8 :created_on: Aug 20, 2010
9 :author: marcink
9 :author: marcink
10 :copyright: (C) 2010-2012 Marcin Kuzminski <marcin@python-works.com>
10 :copyright: (C) 2010-2012 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
26 import logging
26 import logging
27 import traceback
27 import traceback
28
28
29 from sqlalchemy.exc import DatabaseError
29 from sqlalchemy.exc import DatabaseError
30
30
31 from rhodecode.model import BaseModel
31 from rhodecode.model import BaseModel
32 from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
32 from rhodecode.model.db import User, Permission, UserToPerm, UserRepoToPerm,\
33 UserRepoGroupToPerm, UserUserGroupToPerm
33 UserRepoGroupToPerm, UserUserGroupToPerm
34 from rhodecode.lib.utils2 import str2bool
34 from rhodecode.lib.utils2 import str2bool
35
35
36 log = logging.getLogger(__name__)
36 log = logging.getLogger(__name__)
37
37
38
38
39 class PermissionModel(BaseModel):
39 class PermissionModel(BaseModel):
40 """
40 """
41 Permissions model for RhodeCode
41 Permissions model for RhodeCode
42 """
42 """
43
43
44 cls = Permission
44 cls = Permission
45
45
46 def create_permissions(self):
46 def create_permissions(self):
47 """
47 """
48 Create permissions for whole system
48 Create permissions for whole system
49 """
49 """
50 for p in Permission.PERMS:
50 for p in Permission.PERMS:
51 if not Permission.get_by_key(p[0]):
51 if not Permission.get_by_key(p[0]):
52 new_perm = Permission()
52 new_perm = Permission()
53 new_perm.permission_name = p[0]
53 new_perm.permission_name = p[0]
54 new_perm.permission_longname = p[0] #translation err with p[1]
54 new_perm.permission_longname = p[0] #translation err with p[1]
55 self.sa.add(new_perm)
55 self.sa.add(new_perm)
56
56
57 def create_default_permissions(self, user):
57 def create_default_permissions(self, user):
58 """
58 """
59 Creates only missing default permissions for user
59 Creates only missing default permissions for user
60
60
61 :param user:
61 :param user:
62 """
62 """
63 user = self._get_user(user)
63 user = self._get_user(user)
64
64
65 def _make_perm(perm):
65 def _make_perm(perm):
66 new_perm = UserToPerm()
66 new_perm = UserToPerm()
67 new_perm.user = user
67 new_perm.user = user
68 new_perm.permission = Permission.get_by_key(perm)
68 new_perm.permission = Permission.get_by_key(perm)
69 return new_perm
69 return new_perm
70
70
71 def _get_group(perm_name):
71 def _get_group(perm_name):
72 return '.'.join(perm_name.split('.')[:1])
72 return '.'.join(perm_name.split('.')[:1])
73
73
74 perms = UserToPerm.query().filter(UserToPerm.user == user).all()
74 perms = UserToPerm.query().filter(UserToPerm.user == user).all()
75 defined_perms_groups = map(_get_group,
75 defined_perms_groups = map(_get_group,
76 (x.permission.permission_name for x in perms))
76 (x.permission.permission_name for x in perms))
77 log.debug('GOT ALREADY DEFINED:%s' % perms)
77 log.debug('GOT ALREADY DEFINED:%s' % perms)
78 DEFAULT_PERMS = Permission.DEFAULT_USER_PERMISSIONS
78 DEFAULT_PERMS = Permission.DEFAULT_USER_PERMISSIONS
79
79
80 # for every default permission that needs to be created, we check if
80 # for every default permission that needs to be created, we check if
81 # it's group is already defined, if it's not we create default perm
81 # it's group is already defined, if it's not we create default perm
82 for perm_name in DEFAULT_PERMS:
82 for perm_name in DEFAULT_PERMS:
83 gr = _get_group(perm_name)
83 gr = _get_group(perm_name)
84 if gr not in defined_perms_groups:
84 if gr not in defined_perms_groups:
85 log.debug('GR:%s not found, creating permission %s'
85 log.debug('GR:%s not found, creating permission %s'
86 % (gr, perm_name))
86 % (gr, perm_name))
87 new_perm = _make_perm(perm_name)
87 new_perm = _make_perm(perm_name)
88 self.sa.add(new_perm)
88 self.sa.add(new_perm)
89
89
90 def update(self, form_result):
90 def update(self, form_result):
91 perm_user = User.get_by_username(username=form_result['perm_user_name'])
91 perm_user = User.get_by_username(username=form_result['perm_user_name'])
92
92
93 try:
93 try:
94 # stage 1 set anonymous access
94 # stage 1 set anonymous access
95 if perm_user.username == 'default':
95 if perm_user.username == 'default':
96 perm_user.active = str2bool(form_result['anonymous'])
96 perm_user.active = str2bool(form_result['anonymous'])
97 self.sa.add(perm_user)
97 self.sa.add(perm_user)
98
98
99 # stage 2 reset defaults and set them from form data
99 # stage 2 reset defaults and set them from form data
100 def _make_new(usr, perm_name):
100 def _make_new(usr, perm_name):
101 log.debug('Creating new permission:%s' % (perm_name))
101 log.debug('Creating new permission:%s' % (perm_name))
102 new = UserToPerm()
102 new = UserToPerm()
103 new.user = usr
103 new.user = usr
104 new.permission = Permission.get_by_key(perm_name)
104 new.permission = Permission.get_by_key(perm_name)
105 return new
105 return new
106 # clear current entries, to make this function idempotent
106 # clear current entries, to make this function idempotent
107 # it will fix even if we define more permissions or permissions
107 # it will fix even if we define more permissions or permissions
108 # are somehow missing
108 # are somehow missing
109 u2p = self.sa.query(UserToPerm)\
109 u2p = self.sa.query(UserToPerm)\
110 .filter(UserToPerm.user == perm_user)\
110 .filter(UserToPerm.user == perm_user)\
111 .all()
111 .all()
112 for p in u2p:
112 for p in u2p:
113 self.sa.delete(p)
113 self.sa.delete(p)
114 #create fresh set of permissions
114 #create fresh set of permissions
115 for def_perm_key in ['default_repo_perm', 'default_group_perm',
115 for def_perm_key in ['default_repo_perm', 'default_group_perm',
116 'default_user_group_perm',
116 'default_user_group_perm',
117 'default_repo_create',
117 'default_repo_create',
118 #'default_repo_group_create', #not implemented yet
118 #'default_repo_group_create', #not implemented yet
119 'default_user_group_create',
119 'default_user_group_create',
120 'default_fork', 'default_register',
120 'default_fork', 'default_register',
121 'default_extern_activate']:
121 'default_extern_activate']:
122 p = _make_new(perm_user, form_result[def_perm_key])
122 p = _make_new(perm_user, form_result[def_perm_key])
123 self.sa.add(p)
123 self.sa.add(p)
124
124
125 #stage 3 update all default permissions for repos if checked
125 #stage 3 update all default permissions for repos if checked
126 if form_result['overwrite_default_repo'] == True:
126 if form_result['overwrite_default_repo']:
127 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
127 _def_name = form_result['default_repo_perm'].split('repository.')[-1]
128 _def = Permission.get_by_key('repository.' + _def_name)
128 _def = Permission.get_by_key('repository.' + _def_name)
129 # repos
129 # repos
130 for r2p in self.sa.query(UserRepoToPerm)\
130 for r2p in self.sa.query(UserRepoToPerm)\
131 .filter(UserRepoToPerm.user == perm_user)\
131 .filter(UserRepoToPerm.user == perm_user)\
132 .all():
132 .all():
133
133
134 #don't reset PRIVATE repositories
134 #don't reset PRIVATE repositories
135 if not r2p.repository.private:
135 if not r2p.repository.private:
136 r2p.permission = _def
136 r2p.permission = _def
137 self.sa.add(r2p)
137 self.sa.add(r2p)
138
138
139 if form_result['overwrite_default_group'] == True:
139 if form_result['overwrite_default_group']:
140 _def_name = form_result['default_group_perm'].split('group.')[-1]
140 _def_name = form_result['default_group_perm'].split('group.')[-1]
141 # groups
141 # groups
142 _def = Permission.get_by_key('group.' + _def_name)
142 _def = Permission.get_by_key('group.' + _def_name)
143 for g2p in self.sa.query(UserRepoGroupToPerm)\
143 for g2p in self.sa.query(UserRepoGroupToPerm)\
144 .filter(UserRepoGroupToPerm.user == perm_user)\
144 .filter(UserRepoGroupToPerm.user == perm_user)\
145 .all():
145 .all():
146 g2p.permission = _def
146 g2p.permission = _def
147 self.sa.add(g2p)
147 self.sa.add(g2p)
148
148
149 if form_result['overwrite_default_user_group'] == True:
149 if form_result['overwrite_default_user_group']:
150 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
150 _def_name = form_result['default_user_group_perm'].split('usergroup.')[-1]
151 # groups
151 # groups
152 _def = Permission.get_by_key('usergroup.' + _def_name)
152 _def = Permission.get_by_key('usergroup.' + _def_name)
153 for g2p in self.sa.query(UserUserGroupToPerm)\
153 for g2p in self.sa.query(UserUserGroupToPerm)\
154 .filter(UserUserGroupToPerm.user == perm_user)\
154 .filter(UserUserGroupToPerm.user == perm_user)\
155 .all():
155 .all():
156 g2p.permission = _def
156 g2p.permission = _def
157 self.sa.add(g2p)
157 self.sa.add(g2p)
158
158
159 self.sa.commit()
159 self.sa.commit()
160 except (DatabaseError,):
160 except (DatabaseError,):
161 log.error(traceback.format_exc())
161 log.error(traceback.format_exc())
162 self.sa.rollback()
162 self.sa.rollback()
163 raise
163 raise
General Comments 0
You need to be logged in to leave comments. Login now